Docs / Security / Sandbox escape
sandbox_escape
When an agent has a code-execution tool (Python REPL, shell wrapper, Jupyter kernel, sandboxed JavaScript runtime), sandbox_escape scans the tool's arguments + return values for patterns indicating the agent is trying to break out: importing OS modules, evaluating dynamic code, opening raw network sockets, reading cloud instance metadata, walking /proc or /sys, escalating privileges, or reading host secret files.
What this detector catches
Twelve built-in patterns covering Python and JavaScript escape vectors:
python_os_import— agent importsosfrom the sandboxed Python runtime (matchesimport osandfrom os import).python_subprocess_import— importssubprocess(matchesimport subprocessandfrom subprocess import).shell_invocation—os.system,os.popen,subprocess.run/call/Popen/check_output,child_process.exec/spawn.dynamic_code_eval—eval(...) orexec(...) called with arguments.js_vm_module— Node.jsvm.runInNewContext,vm.runInContext,vm.createContext. Thevmmodule is itself a sandbox primitive; reaching for it from inside a code-exec sandbox is a classic nested-context escape vector.js_dynamic_require—require(...)with a non-literal argument (variable, expression, function call). The safe formrequire('fs')with a string literal is NOT flagged.js_function_constructor—(new) Function('...')constructing a runnable function from a string at runtime; identical attack surface toeval.raw_socket_open—import socket/socket.socket/create_connection/gethostbyname.instance_metadata_access— AWS / GCP / Azure link-local IMDS endpoints (169.254.169.254,metadata.google.internal,metadata.azure.com).proc_sys_access—/proc/self,/proc/1,/sys/kernel,/sys/class.privilege_escalation—chmod <numeric>,chown root,setuid(0)patterns. Does NOT matchsudoorsu -directly; add a custom pattern if you need those flagged.host_secret_read—.aws/credentials,.ssh/id_rsa,.ssh/id_ed25519,.ssh/known_hosts,/etc/passwd,/etc/shadow.
The detector matches against tool-call arguments and return values via RE2 (no ReDoS risk). Built-in patterns run first, then custom patterns. The production path emits ALL distinct matches per execution (capped at 20), so multi-vector attacks surface as multiple failure_groups rather than collapsing into the first match. Pattern compilation panics at process startup if any built-in rule fails to compile — a fail-fast posture that prevents shipping a silent-dark detector to production.
What it does NOT catch
- Path-traversal sequences themselves (
../../../-style prefixes). The detector matches the destination (e.g./etc/passwd,.ssh/id_rsa), not the traversal pattern. This is deliberate: false-positive cost on legitimate../usage in code-exec tools would be too high. - Dynamic
import()in JavaScript — the current JS pattern set coversvm.*, dynamicrequire(), and theFunctionconstructor, but does NOT cover dynamicimport()expressions. Add a custom pattern via the custom-patterns primitive if your stack uses ES-module dynamic imports. - Obfuscated escape attempts — base64-encoded payloads, hex-encoded strings, multi-line concatenation. The pattern set is open-source-bound; sophisticated attackers can bypass with relatively cheap obfuscation. Defense-in-depth practices (real OS-level sandboxing, syscall restriction, capability-based confinement) are the load-bearing layer; this detector is the telemetry layer above them.
What to do when it fires
Open the failure-group detail page. The Playbook walks through three diagnostics: identify which pattern_id fired (the signature carries the pattern name + a redacted snippet of the matched substring); trace which tool call produced the hit (intent matters — a Python REPL agent legitimately importing os is qualitatively different from a code-search agent suddenly invoking subprocess); decide between revoking the tool from the agent vs tightening the OS-level sandbox vs adding a custom allowlist for the legitimate use case.
Custom rules
Per-project custom sandbox-escape patterns ship via the same primitive that backs prompt_injection + data_leakage. See Custom security patterns for the editor + REST surface. Use custom patterns to extend coverage to vectors the built-ins miss (e.g. sudo / su - if your stack treats those as dangerous, dynamic ES-module import(), Ruby Kernel.system, obfuscated base64 payloads decoded to dangerous shapes) or to lock down argument shapes specific to your tools.
Related docs
- Custom security patterns — per-project pattern extensibility for all 3 security detectors.
- prompt_injection — the input-side security sibling.
- data_leakage — the secret-egress security sibling.