AID-H-025.002: Safe Interpreter Enforcement

Version 1.20261015 · Actionable sub-technique

When dynamic evaluation is required, force safe/restricted interpreters inside the execution boundary so code cannot access filesystem, network, or privileged APIs by design. For interactive 'vibe coding' run evaluation only inside ephemeral sandboxes.

Pillars: app

Lifecycle: building, operation

Scope boundary

Owns mandatory selection and configuration of a restricted interpreter when dynamic evaluation is allowed. It limits the language and API surface but is not the process, filesystem, network, or resource containment boundary.

AID-H-025.001: AID-H-025.002 constrains code that is allowed to run; AID-H-025.001 decides whether exact code bytes contain policy-prohibited constructs before execution. Interpreter restriction and static admission address different failure modes.

AID-I-001: AID-H-025.002 restricts language semantics inside an evaluator; AID-I-001 contains the evaluator process and its operating-system effects. A restricted interpreter escape must still meet a separate sandbox boundary.

AID-H-018.009: AID-H-025.002 selects and configures the restricted interpreter and authorizes code evaluation; AID-H-018.009 confines any model-influenced interpreter, script, module, working-directory, or executable filesystem target. Interpreter admission and opened-object confinement remain separate results, and execution permission stays with this control and AID-I-001.

Warning

Restricted Interpreter Is Not a Complete Sandbox

Restricted interpreters are security-sensitive dependencies. Use a supported release, track published escape fixes, and regression-test the exact language and built-in surface enabled by policy before promotion.

Implementation guidance

AID-H-025.002-G001

Allowlist restricted interpreters and enforce interpreter selection via an execution gateway (policy), not via model output.
Action: enforce the restricted-interpreter boundary
Example code (Python) - restricted interpreter inside a sandbox
from importlib.metadata import version
import os
from pathlib import Path

from packaging.version import Version
from RestrictedPython import compile_restricted
from RestrictedPython import safe_globals

if Version(version("RestrictedPython")) < Version("8.3"):
    raise RuntimeError("RestrictedPython 8.3+ is required; older releases are not accepted")

# This function must be invoked only inside a short-lived OS/container/WASM sandbox
# with no outbound network, non-root execution, and a minimal writable filesystem.

def run_restricted(code_str: str) -> None:
    if not isinstance(code_str, str) or not code_str:
        raise ValueError("restricted source must be non-empty text")
    byte_code = compile_restricted(code_str, "<agent-code>", "exec")
    globals_map = dict(safe_globals)
    exec(byte_code, globals_map, {})


if __name__ == "__main__":
    # The immutable workload artifact exposes exactly this gateway-selected path.
    source_path = Path("/workspace/untrusted.py")
    requested = Path(os.path.abspath(os.sys.argv[1])) if len(os.sys.argv) == 2 else None
    if requested != source_path or source_path.is_symlink() or not source_path.is_file():
        raise SystemExit("usage: run_restricted.py /workspace/untrusted.py")
    maximum = int(os.environ["SANDBOX_SOURCE_MAX_BYTES"])
    if maximum < 1 or maximum > 1_048_576:
        raise RuntimeError("sandbox source cap is invalid")
    raw = source_path.read_bytes()
    if not raw or len(raw) > maximum:
        raise RuntimeError("restricted source violates the byte cap")
    run_restricted(raw.decode("utf-8", errors="strict"))

Boundary: RestrictedPython is a language-surface reduction layer, not an operating-system sandbox. The execution gateway must select the approved interpreter and sandbox image; model output must never choose either one.

Enforce the outer boundary
: "${BROKERED_WORKLOAD_IMAGE:?gateway must supply an H-018.009-bound workload image}"
: "${BROKERED_WORKLOAD_RECEIPT_ID:?gateway must supply the opened-artifact receipt ID}"
case "$BROKERED_WORKLOAD_IMAGE" in
  *@sha256:*) ;;
  *) echo "BROKERED_WORKLOAD_IMAGE must be pinned by digest" >&2; exit 2 ;;
esac
: "${SANDBOX_PIDS_LIMIT:?load SANDBOX_PIDS_LIMIT from the verified sandbox policy}"
: "${SANDBOX_MEMORY_LIMIT:?load SANDBOX_MEMORY_LIMIT from the verified sandbox policy}"
: "${SANDBOX_CPU_LIMIT:?load SANDBOX_CPU_LIMIT from the verified sandbox policy}"
: "${SANDBOX_USER:?load SANDBOX_USER from the verified sandbox policy}"
: "${SANDBOX_TMPFS_SIZE:?load SANDBOX_TMPFS_SIZE from the verified sandbox policy}"
: "${SANDBOX_SOURCE_MAX_BYTES:?load SANDBOX_SOURCE_MAX_BYTES from the verified sandbox policy}"

docker run --rm \
  --network=none \
  --read-only \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  --pids-limit="$SANDBOX_PIDS_LIMIT" \
  --memory="$SANDBOX_MEMORY_LIMIT" \
  --cpus="$SANDBOX_CPU_LIMIT" \
  --user="$SANDBOX_USER" \
  --tmpfs "/tmp:rw,noexec,nosuid,nodev,size=$SANDBOX_TMPFS_SIZE" \
  --env "SANDBOX_SOURCE_MAX_BYTES=$SANDBOX_SOURCE_MAX_BYTES" \
  --workdir /workspace \
  "$BROKERED_WORKLOAD_IMAGE" \
  /opt/aidefend/venv/bin/python \
  /opt/aidefend/run_restricted.py \
  /workspace/untrusted.py

The code-execution gateway, not model text or an ambient $PWD/PATH, selects the exact interpreter, runner, and workspace artifact. Before this sandbox step it consumes AID-H-018.009 broker-opened handles or a content-addressed workload artifact and binds that receipt to BROKERED_WORKLOAD_IMAGE; the reference command never reopens a model-supplied host path and does not claim filesystem-confinement PASS. The runtime-platform team applies this guidance to every model- or user-supplied execution request. A separately credentialed verifier reconciles the complete request population against gateway decisions, broker receipt IDs, immutable runtime/workload image identities, resource and syscall traces, and the external network-canary readback; the executor's own verdict is never sufficient.

Negative tests and evidence

Exercise imports, file reads/writes, subprocess creation, sockets, excessive CPU, memory exhaustion, fork attempts, ambient $PWD/PATH substitution, wrong artifact or receipt reuse, and writes outside the temporary directory. Run a separate network canary outside the container and prove that no connection arrives. Require the expected language-level denials plus container/runtime enforcement; a crash, timeout, missing telemetry, mutable image reference, or unsupported runtime must block release. Preserve the interpreter and package versions, immutable workload image digest, broker receipt ID, gateway decision, runtime policy, exit reason, resource telemetry, syscall/network evidence, and test-corpus digest.

Block release when any expected execution request, immutable workload image digest, broker receipt, runtime receipt, resource trace, network canary result, or negative-test case is absent. Exclude this method only when signed inventory proves that the covered workflow never evaluates or executes model- or user-supplied code; disabling one interpreter is insufficient.

Open-source tools

Commercial / hosted tools

Threat mappings

MITRE ATLAS

MAESTRO

OWASP LLM Top 10 2026

OWASP ML Top 10 2023

OWASP Top 10 for Agentic Applications 2026

NIST Adversarial Machine Learning 2025

Cisco Integrated AI Security and Safety Framework

Google Secure AI Framework 2.0 - Risks

Databricks AI Security Framework 3.0

AID-H-025.002: Safe Interpreter Enforcement | AIDEFEND

Loading interactive view…

A Practical Knowledge Base for AI Security Defenses

Version