Skip to main content

jsdet_core/
config.rs

1/// Configuration for a single sandbox execution.
2///
3/// Sensible defaults are provided. Zero config for consumers who just want
4/// `execute(scripts)`. Full control for experts.
5#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
6pub struct SandboxConfig {
7    /// Maximum wall-clock execution time in milliseconds.
8    /// Default: 200ms. Enough for most phishing kits.
9    /// Set to 5000ms for complex extension analysis.
10    pub timeout_ms: u64,
11
12    /// Maximum WASM linear memory in bytes.
13    /// Default: 16MB. `QuickJS` needs ~4MB for bootstrap.
14    pub max_memory_bytes: usize,
15
16    /// Maximum fuel (WASM instruction count).
17    /// Default: `100_000_000` (~100ms of execution on modern hardware).
18    /// 0 = unlimited (use timeout only).
19    pub max_fuel: u64,
20
21    /// Maximum observations before the sandbox stops recording.
22    /// Prevents memory exhaustion from observation floods.
23    /// Default: `10_000`.
24    pub max_observations: usize,
25
26    /// Maximum number of scripts to execute per sandbox run.
27    /// Default: 100.
28    pub max_scripts: usize,
29
30    /// Maximum size of a single script in bytes.
31    /// Default: 1MB.
32    pub max_script_bytes: usize,
33
34    /// Maximum combined size of all scripts in bytes.
35    /// Default: 5MB.
36    pub max_total_script_bytes: usize,
37
38    /// Whether to immediately drain all pending timers after script execution.
39    /// When true, setTimeout/setInterval callbacks fire synchronously.
40    /// Default: true (for detonation — you want to trigger delayed payloads).
41    pub drain_timers: bool,
42
43    /// Maximum timer callbacks to drain per execution.
44    /// Default: 50.
45    pub max_timer_drains: usize,
46
47    /// Whether to allow nested WASM instantiation.
48    /// When true, JS `new WebAssembly.Module()` creates a real nested WASM instance.
49    /// When false, it returns a stub that records the attempt but doesn't execute.
50    /// Default: true.
51    pub allow_nested_wasm: bool,
52
53    /// Maximum linear memory for nested WASM instances in bytes.
54    /// Default: 4MB.
55    pub nested_wasm_max_memory: usize,
56
57    /// Maximum fuel for nested WASM instances.
58    /// Default: `10_000_000`.
59    pub nested_wasm_max_fuel: u64,
60}
61
62impl Default for SandboxConfig {
63    fn default() -> Self {
64        Self {
65            timeout_ms: 200,
66            max_memory_bytes: 16 * 1024 * 1024,
67            max_fuel: 100_000_000,
68            max_observations: 10_000,
69            max_scripts: 100,
70            max_script_bytes: 1024 * 1024,
71            max_total_script_bytes: 5 * 1024 * 1024,
72            drain_timers: true,
73            max_timer_drains: 50,
74            // Secure by default — nested WASM disabled. Enable explicitly for extension analysis.
75            allow_nested_wasm: false,
76            nested_wasm_max_memory: 4 * 1024 * 1024,
77            nested_wasm_max_fuel: 10_000_000,
78        }
79    }
80}
81
82impl SandboxConfig {
83    /// Config tuned for fast URL detonation (Sear).
84    /// Low timeouts, drain timers, nested WASM disabled.
85    #[must_use]
86    pub fn detonation() -> Self {
87        Self {
88            timeout_ms: 200,
89            max_fuel: 50_000_000,
90            drain_timers: true,
91            allow_nested_wasm: false,
92            ..Self::default()
93        }
94    }
95
96    /// Config tuned for deep extension analysis (Soleno).
97    /// Higher timeouts, nested WASM enabled, more observations.
98    #[must_use]
99    pub fn extension_analysis() -> Self {
100        Self {
101            timeout_ms: 5000,
102            max_fuel: 500_000_000,
103            max_observations: 50_000,
104            max_scripts: 500,
105            drain_timers: true,
106            allow_nested_wasm: true,
107            ..Self::default()
108        }
109    }
110
111    /// Config for interactive research.
112    /// No fuel limit, high timeouts, everything enabled.
113    #[must_use]
114    pub fn research() -> Self {
115        Self {
116            timeout_ms: 30_000,
117            max_fuel: 0, // unlimited
118            max_observations: 1_000_000,
119            max_scripts: 10_000,
120            max_memory_bytes: 256 * 1024 * 1024,
121            drain_timers: false, // researcher controls timer advancement
122            allow_nested_wasm: true,
123            nested_wasm_max_memory: 64 * 1024 * 1024,
124            nested_wasm_max_fuel: 100_000_000,
125            ..Self::default()
126        }
127    }
128}