Skip to main content

Code Execution Policy

The code-execution policy category governs what generated code agents can execute. It controls allowed languages, blocked commands, restricted filesystem paths, package installation, sandbox requirements, and optional human review before execution.

Use it when your agents generate and run code -- whether in a cloud sandbox (E2B) or locally via subprocess.

Rules

RuleTypeDefaultDescription
allowed_languagesstring[]["python", "javascript", "sql"]Languages agents are allowed to execute
blocked_languagesstring[][]Languages explicitly denied (takes precedence over allowed)
blocked_commandsstring[]["rm -rf", "chmod", "chown"]Command strings that are forbidden in code. Uses substring matching against the full command
blocked_pathsstring[]["/etc", "/var", "~/.ssh", "~/.aws"]Filesystem paths that code cannot access. Matches using path prefix
allowed_pathsstring[]["/workspace", "/tmp"]If set, code can only access these paths (allowlist). Leave empty to allow all paths not in blocked_paths
allow_package_installbooleanfalseWhether the agent can install packages at runtime
allowed_packagesstring[][]If allow_package_install is true, restrict to these packages
max_execution_time_secondsinteger30Maximum allowed execution duration per command
max_output_size_kbinteger1024Maximum output size per execution
require_reviewbooleanfalseRequire human approval before every code execution
sandbox_requiredbooleantrueWhether code must run in a sandbox (E2B). Set to false for local subprocess execution
action_on_violationstring"block""block" to prevent execution, "warn" to log and continue

How Matching Works

Understanding the difference between blocked commands and blocked paths is critical for configuring policies correctly.

Blocked Commands -- Substring Match

Blocked commands use case-insensitive substring matching against the full command string. This means the blocked command text must appear somewhere in the generated command.

Blocked CommandGenerated CodeMatch?Why
rm -rfrm -rf /etc/*Yes"rm -rf" is in "rm -rf /etc/*"
wgetwget https://example.com/file.shYes"wget" is in the command
curlcurl -X POST https://api.example.comYes"curl" is in the command
lsls -laYes"ls" is in "ls -la"
rm -rfrm file.txtNo"rm -rf" is not in "rm file.txt"
Common Mistake

Putting a command like ls in blocked_paths instead of blocked_commands won't work. blocked_paths checks filesystem paths (like /etc or ~/.ssh), not command names. If you want to block a command, add it to blocked_commands.

Blocked Paths -- Prefix Match

Blocked paths use prefix matching against the filesystem paths extracted from the command. The SDK extracts paths starting with / or ~/ from the command string before evaluation.

Blocked PathPath in CommandMatch?Why
/etc/etc/shadowYes/etc/shadow starts with /etc
/etc/etc/passwdYes/etc/passwd starts with /etc
~/.ssh~/.ssh/id_rsaYes~/.ssh/id_rsa starts with ~/.ssh
/var/var/log/syslogYes/var/log/syslog starts with /var
/etc/tmp/etc-backupNo/tmp/etc-backup does not start with /etc

Allowed Paths -- Allowlist Mode

If allowed_paths is set (non-empty), only those path prefixes are permitted. Any path not matching an allowed prefix is blocked. If allowed_paths is empty, all paths not in blocked_paths are allowed.

ConfigurationBehavior
blocked_paths: ["/etc"], allowed_paths: []Block /etc/*, allow everything else
blocked_paths: [], allowed_paths: ["/workspace", "/tmp"]Only allow /workspace/* and /tmp/*, block all others
blocked_paths: ["/etc"], allowed_paths: ["/workspace"]Both apply -- /etc blocked, only /workspace allowed

Sandbox vs Local Execution

Code execution policies support two modes depending on how your agent runs code:

Sandboxed Execution (E2B)

For agents that execute code in a cloud sandbox (E2B). The sandbox provides an isolated environment, so the policy adds defense-in-depth.

{
"name": "Sandbox Code Governance",
"category": "code-execution",
"rules": {
"allowed_languages": ["python", "javascript"],
"blocked_commands": ["rm -rf", "chmod", "chown"],
"blocked_paths": ["/etc", "~/.ssh", "~/.aws"],
"allowed_paths": ["/workspace", "/tmp"],
"allow_package_install": false,
"max_execution_time_seconds": 30,
"max_output_size_kb": 1024,
"sandbox_required": true,
"action_on_violation": "block"
}
}

Key settings:

  • sandbox_required: true -- warns if no sandbox is available
  • allowed_paths set -- restricts execution to specific directories inside the sandbox

Local Execution (Subprocess)

For agents that generate shell commands and run them on the host machine via subprocess. More dangerous than sandboxed execution, so policies are your primary safety net.

{
"name": "Local Code Execution Governance",
"category": "code-execution",
"rules": {
"allowed_languages": ["python", "shell"],
"blocked_commands": ["rm -rf", "chmod", "chown", "wget", "curl"],
"blocked_paths": ["/etc", "~/.ssh", "~/.aws", "/var"],
"allowed_paths": [],
"allow_package_install": false,
"max_execution_time_seconds": 30,
"max_output_size_kb": 1024,
"sandbox_required": false,
"require_review": false,
"action_on_violation": "block"
}
}

Key differences from sandbox mode:

  • sandbox_required: false -- no cloud sandbox, executing locally
  • allowed_languages includes "shell" -- the agent generates shell commands, not just Python
  • blocked_commands includes "wget", "curl" -- prevent data exfiltration from the host
  • allowed_paths is empty -- we block specific dangerous paths instead of allowlisting
tip

For local execution, block wget and curl to prevent data exfiltration. In a sandbox, these are less dangerous since the sandbox is isolated.

Enforcement

Code execution policies are evaluated at mid-execution time. When the SDK records a code execution event, the policy is checked before the code runs.

Enforcement Flow

Agent generates code


SDK calls record_code_execution(language, code, paths)


Controlplane evaluates code-execution policies

├── Check language restrictions
├── Check blocked commands (substring match)
├── Check blocked paths (prefix match)
├── Check allowed paths (if set)
├── Check package restrictions
└── Check execution time / output size limits

├── ALLOW → Code executes
├── WARN → Code executes, warning logged in trace
└── BLOCK → PolicyViolationError raised, code never runs

In Agent Code

import waxell_observe as waxell
from waxell_observe import WaxellContext
from waxell_observe.errors import PolicyViolationError

waxell.init()

try:
async with WaxellContext(
agent_name="code-agent",
workflow_name="code-exec",
enforce_policy=True,
mid_execution_governance=True,
) as ctx:
# Record the code execution -- governance checks happen here
ctx.record_code_execution(
language="shell",
code="ls -la /tmp",
paths=["/tmp"],
)

# If we reach here, the policy allowed it
result = subprocess.run("ls -la /tmp", shell=True, capture_output=True)

except PolicyViolationError as e:
print(f"Blocked: {e}")
# The code never executed

With the Subprocess Instrumentor

For local execution agents, the subprocess instrumentor automatically intercepts subprocess.run() calls and enforces governance without manual record_code_execution() calls:

import waxell_observe as waxell
from waxell_observe.instrumentors import instrument_all

waxell.init()
instrument_all(libraries=["subprocess"]) # Opt-in: auto-intercept subprocess

async with WaxellContext(
agent_name="code-agent",
enforce_policy=True,
mid_execution_governance=True,
) as ctx:
# The instrumentor automatically:
# 1. Extracts the command from subprocess.run()
# 2. Calls record_code_execution() with language="shell"
# 3. Checks governance -- raises PolicyViolationError if blocked
# 4. Only executes the subprocess if governance allows it
result = subprocess.run("ls -la /tmp", shell=True, capture_output=True)
info

The subprocess instrumentor is opt-in only. It patches subprocess.run(), subprocess.Popen(), and os.system(). It only activates inside a WaxellContext -- outside of one, subprocess calls work normally with zero overhead.

Human Review

Set require_review: true to gate every code execution on human approval, regardless of whether the command itself would be allowed by other rules.

When review is enabled:

  1. Agent generates code
  2. SDK presents the code to the approval handler (e.g., terminal prompt, Slack message)
  3. If approved -- governance rules are still evaluated. A dangerous command is blocked even if approved.
  4. If denied -- PolicyViolationError raised immediately
from waxell_observe.approval import prompt_approval

waxell.init(on_policy_block=prompt_approval)

async with WaxellContext(
agent_name="code-agent",
enforce_policy=True,
mid_execution_governance=True,
) as ctx:
ctx.record_code_execution(language="shell", code="uname -a")
# Terminal prompt: "Approve this operation? (y/n):"
# If approved AND policy allows → executes
# If approved BUT policy blocks → still blocked
# If denied → PolicyViolationError
warning

Human review is an additional gate, not a bypass. Even if a reviewer approves a command, policy rules (blocked commands, blocked paths) are still enforced. This prevents accidental approval of dangerous commands.

See Approval Workflows for custom handlers (Slack, webhooks, etc).

Creating a Policy

Via Dashboard

  1. Navigate to Governance > Policies
  2. Click Create Policy
  3. Select category: Code Execution
  4. Configure rules:
FieldSandbox ModeLocal Mode
Allowed Languagespython, javascriptpython, shell
Blocked Commandsrm -rf, chmod, chownrm -rf, chmod, chown, wget, curl
Blocked Paths/etc, ~/.ssh, ~/.aws/etc, ~/.ssh, ~/.aws, /var
Allowed Paths/workspace, /tmp(leave empty)
Allow Package InstallOFFOFF
Max Execution Time3030
Max Output Size10241024
Require ReviewOFFOFF
Sandbox RequiredONOFF
Action on ViolationBlockBlock
  1. Set Scope to target specific agents, or leave empty for all agents
  2. Save

Via API

curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
https://acme.waxell.dev/waxell/v1/policies/ \
-d '{
"name": "Local Code Execution Governance",
"category": "code-execution",
"rules": {
"allowed_languages": ["python", "shell"],
"blocked_commands": ["rm -rf", "chmod", "chown", "wget", "curl"],
"blocked_paths": ["/etc", "~/.ssh", "~/.aws", "/var"],
"allowed_paths": [],
"allow_package_install": false,
"max_execution_time_seconds": 30,
"max_output_size_kb": 1024,
"require_review": false,
"sandbox_required": false,
"action_on_violation": "block"
},
"scope": {
"agents": ["local-code-agent"]
}
}'

Observability

Code execution governance events appear in the execution detail:

Trace Tab

  • code_exec:shell span -- the governance check. Present for every record_code_execution() call. This span does not mean the code executed -- it means the code was evaluated for governance.
  • subprocess.run span -- the actual execution. Only present if governance allowed the command to run. If you see code_exec:shell but no subprocess.run, the command was blocked before execution.

Governance Tab

  • Pre-execution: Shows code_execution_rules metadata with the full policy configuration
  • Mid-execution: Per-command evaluations showing ALLOW, WARN, or BLOCK with the specific reason (e.g., "Blocked command 'rm -rf' found in code" or "Code accessed blocked path '/etc/shadow'")

Incidents

Policy violations create incidents visible in Governance > Incidents. Each incident includes:

  • The policy that triggered it
  • The blocked command or path
  • The agent name and execution ID
  • Whether it was a mid-execution block (prevented execution) or post-execution audit finding

Warn vs Block

Switch between enforcement modes using action_on_violation:

ModeBehaviorUse Case
"block"PolicyViolationError raised, code never executesProduction -- prevent dangerous actions
"warn"Warning logged, code still executesMonitoring -- discover what agents are doing before enforcing

Start with "warn" to audit your agents' behavior, then switch to "block" once you've tuned the rules.

Combining with Other Policies

Code execution policies work alongside other categories:

  • Safety policies limit total steps and tool calls; code execution governs the content of those calls
  • Content policies scan for PII or credentials in inputs/outputs; code execution scans for dangerous commands
  • Approval policies gate high-stakes actions; require_review specifically gates code execution
  • Network policies control outbound access; blocked_commands with wget/curl prevents downloads at the command level

Common Gotchas

  1. Blocked commands vs blocked paths: blocked_commands does substring matching on the command string ("rm -rf" matches "rm -rf /tmp"). blocked_paths does prefix matching on extracted filesystem paths ("/etc" matches the path /etc/shadow). Don't mix them up.

  2. Allowed paths empty = allow all: When allowed_paths is empty, all paths not in blocked_paths are permitted. Set allowed_paths to restrict to a specific allowlist.

  3. Multiple code execution policies: If you have both a sandbox policy and a local policy, scope them to different agents. Otherwise both evaluate for every agent, and the sandbox policy's sandbox_required: true will warn for agents running locally.

  4. Language must match: The allowed_languages check requires the language string to match exactly. For local subprocess agents, use "shell" -- not "bash" or "sh".

  5. Substring matching is broad: Blocking "rm" would also block "format" because "rm" appears in "format". Be specific: use "rm -rf" instead of "rm".