---
key: "agent-code-sandboxing"
title: "Sandbox model-generated code and computer-use agents"
url: "https://softwaresecurity.com/domains/ai-emerging/agent-security/agent-code-sandboxing/"
api: "https://softwaresecurity.com/api/v1/articles/agent-code-sandboxing.json"
domain: "ai-emerging"
topic: "AI security"
type: "Guide"
identifiers: ["CWE-653","CWE-94","CWE-250","CWE-770","LLM10:2026","LLM03:2026","ASI05:2026","ASI01:2026","ASI09:2026","V15.2.5","V15.2.2","V13.2.4"]
tags: ["Kubernetes and containers","AI agents and tools"]
stages: ["design","build"]
roles: ["developer","platform-sre"]
license: "CC-BY-4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
code_license: "MIT"
---

# Sandbox model-generated code and computer-use agents

Run the code an agent writes, and agents that drive a browser or desktop, inside a boundary built for hostile code: a disposable runtime with no secrets and no default network, hard resource limits, and a person in front of every side effect.

Canonical URL: https://softwaresecurity.com/domains/ai-emerging/agent-security/agent-code-sandboxing/

## In short

Assume the code an agent writes was written by an attacker, because any page, file or tool result the model read may have steered it. Run it in a fresh, disposable sandbox: a container hardened with no network, a read-only root, no capabilities, a non-root user and limits on memory, CPU, processes and time, or gVisor or a microVM when the code is less trusted still. Mount nothing from the host and pass no secrets in. Fail closed when the sandbox is unavailable. Keep side effects outside it, behind an approval that shows the exact action; for computer-use agents, treat the screen as untrusted and keep logins and irreversible clicks with a person.

- OWASP lists this as ASI05:2026 Unexpected Code Execution (RCE) in the Top 10 for Agentic Applications; its mitigations start with never running as root and running code in sandboxed containers with strict limits, including on network access.
- In-process restrictions are not a sandbox: Python's own documentation says audit hooks are not suitable for one, and a regex that blocks `import os` is bypassed by the next spelling.
- A container shares the host kernel. Harden it with `--network=none`, `--read-only`, `--cap-drop=ALL`, `no-new-privileges`, `--pids-limit`, equal `--memory` and `--memory-swap`, and `--cpus`; use gVisor (`--runtime=runsc`) or a Firecracker microVM for a stronger boundary.
- Files go in and out as data, never as a shared folder: Auto-GPT's writable compose-file mount (CVE-2023-37273) let generated code escape to the host on the next restart.
- Never fall back to running the code on the host when the sandbox fails, and never put API keys, tokens or credential files inside it.
- Computer-use vendors agree: run the agent in an isolated VM, container or browser profile, allowlist the sites it may visit, keep sensitive credentials away from it, and confirm purchases, messages, deletions and agreements with a person.

## Recommended defaults

| Setting | Value | Note | Source |
| --- | --- | --- | --- |
| Where code runs | A fresh container (or microVM) per job, removed afterwards | Never the agent's own process, and never the host as a fallback. | — |
| Network | `--network=none` | Only the loopback device exists. If code must reach a service, route it through an allowlisting proxy. | https://docs.docker.com/engine/network/drivers/none/ |
| Filesystem | `--read-only` with a size-limited `--tmpfs=/tmp`; no `--volume` or `--mount` | Inputs on stdin, outputs in the result. | — |
| Identity and privileges | `--user=65534:65534`, `--cap-drop=ALL`, `--security-opt=no-new-privileges` | Keep Docker's default seccomp profile; never `--privileged` or the Docker socket. | — |
| Processes | `--pids-limit=64` | A fork bomb stops at the limit with EAGAIN. | — |
| Memory | `--memory=256m --memory-swap=256m` | Equal values mean no swap; the kernel's OOM killer ends the code at the limit. | https://docs.docker.com/engine/containers/resource_constraints/ |
| CPU and time | `--cpus=1` and a wall-clock deadline that kills the container by name | Killing the docker client leaves the container running. | — |
| Files and output | `--ulimit=fsize=16777216`; return at most 64 KB of stdout and stderr to the model | Output is untrusted model input on its next turn. | — |
| Image | Pinned by digest, packages pre-installed | No `pip install` at run time: the network is off. | — |
| Stronger isolation | gVisor (`--runtime=runsc`) or a microVM such as Firecracker | For code from many tenants or with no review at all. | — |
| Computer use | Dedicated VM or browser profile, domain allowlist, no saved logins, confirmation for irreversible actions | — | https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool |

## Verify it

1. Run the agent-code-sandbox project's live tests against your sandbox image and flags: every escape case must fail and every legitimate case must pass.
2. Inspect the `docker run` command your tool actually issues and confirm it has `--network=none`, `--read-only`, `--cap-drop=ALL`, `no-new-privileges`, `--pids-limit`, equal `--memory` and `--memory-swap`, `--cpus` and no `--volume`, `--mount`, `--env` or Docker socket.
3. Stop the Docker daemon (or point the tool at a missing binary) and confirm the tool raises an error instead of running the code anywhere else.
4. Run an endless loop with a short deadline and confirm `docker ps -a` shows no container afterwards.
5. For a computer-use agent, serve a page with an injected instruction and a fake login form from an allowlisted test domain, and confirm the agent asks before acting and never types a credential.

## What you will learn

- Choose an isolation boundary (hardened container, gVisor, microVM, WebAssembly, separate account) for what the generated code must do.
- Run generated code with no network, no secrets, no host mounts and hard limits on time, memory, CPU, processes and output.
- Keep side effects outside the sandbox and behind an approval that shows the exact action.
- Treat a computer-use agent's screen as untrusted input, and keep credential entry and irreversible clicks with a person.

Audience: Developers and platform engineers who give an LLM agent a code interpreter, a shell, or control of a browser or desktop

Before you start:

- Know what a container shares with its host (the kernel) and what `docker run` flags control.
- Know how an agent's tool calls reach your code.
- Python 3.11 or later and Docker for the local project.

Time: About 45 minutes: 15 to read and 30 for the exercise, plus 45 to 75 for the local project

## Treat generated code as an attacker's code

An agent that writes and runs code turns text into execution. The model cannot reliably tell instructions from data, so a web page, document, email or tool result it read can steer what it writes, and the code then runs with whatever the runtime can reach. The OWASP Top 10 for Agentic Applications 2026 lists this as ASI05 Unexpected Code Execution (RCE): generated scripts, shell commands, deserialized objects or template evaluation that lead to host or container compromise, persistence or sandbox escape. Its examples include prompt injection that runs attacker-defined code and unverified package installs that execute during installation.

Auto-GPT showed how quickly this reaches the host. Its own advisories describe two flaws fixed in version 0.4.3. In CVE-2023-37273, the `docker-compose.yml` in the repository root mounted itself into the container without write protection, so code run through the `execute_python_file` or `execute_python_code` commands could overwrite it and gain control of the host the next time Auto-GPT started. In CVE-2023-37274, which affected the setup that runs Auto-GPT on the host and only the generated code in a container, `execute_python_code` wrote model-supplied code to a file with a model-supplied name it did not sanitize, so a name such as `../../../main.py` overwrote Auto-GPT's own code, which then ran on the host at the next start. Positive Security's write-up reached those commands through an indirect prompt injection on a web page the agent browsed.

Nothing inside the interpreter fixes this. Python's documentation says audit hooks "are not suitable for implementing a sandbox" and that malicious code can disable or bypass them; denylists of imports or shell commands fail the same way. The boundary has to be the operating system or a hypervisor, and it has to assume the code is hostile on every run.

## Choose the isolation boundary by what the code must do

Pick the weakest boundary that still contains the code you expect, then add one level if many tenants share the machine or nobody reviews what runs. Whatever you choose, run one disposable environment per job or per session, and never reuse one across users.

| Option | What isolates the code | Good for | Watch for |
| --- | --- | --- | --- |
| Hardened container (runc) | Linux namespaces, cgroups, capabilities and Docker's default seccomp profile, which disables around 44 of 300+ system calls | Data analysis and scripts for one tenant at a time | It shares the host kernel, so a kernel or runtime bug is an escape; the Docker daemon runs as root and must not be reachable from the sandbox |
| gVisor (`runsc`) | An application kernel that implements a Linux-like interface, so the code's system calls are handled by gVisor rather than passed straight to the host kernel | Untrusted code from many users on shared hosts | It implements a Linux-like interface, not Linux itself, so test your workload under it |
| MicroVM (Firecracker, Kata Containers) | A KVM virtual machine per job with a minimal device model; Firecracker emulates five devices and adds a jailer as a second line of defense | Multi-tenant code interpreters and anything that needs a full kernel | Needs KVM, so it runs on bare metal or nested virtualization, not inside most containers |
| WebAssembly (Wasmtime with WASI, Pyodide) | The Wasm sandbox: the code reaches only the imports and directories it is given | Pure computation in a browser or an edge function | Pyodide's threading, multiprocessing and sockets do not work, so many libraries do not either |
| Separate OS account or VM per user | Ordinary operating system permissions | Long-lived workspaces such as a hosted notebook | Easy to grant too much: shared folders, credentials in the home directory, an open network |
| Hosted code execution tool | The provider's sandbox | Analysis where data may leave your infrastructure | Check what it allows: Anthropic's has no internet access and 5 GiB of memory, OpenAI's Code Interpreter container expires after 20 idle minutes, and Gemini's code execution stops after 30 seconds |

## Lock the container down

The function below builds the `docker run` command for one job in the agent-code-sandbox project, whose live tests run each flag against real escape attempts. The image is pinned by digest. `--network=none` leaves only the loopback device. `--read-only` and a size-limited `tmpfs` give the code scratch space but no way to change the image. The code runs as `nobody` with no capabilities, and `no-new-privileges` stops a setuid binary from raising them again. `--pids-limit` ends a fork bomb, equal `--memory` and `--memory-swap` mean the kernel kills the code at the limit instead of swapping, `--cpus` caps its share of the machine and `--ulimit=fsize` caps any file it writes. `--log-driver=none` keeps its output out of Docker's logs, and `--init` reaps any processes it leaves.

What is absent matters as much: no `--volume` or `--mount`, no `--env`, no `--privileged`, no `--network=host` or `--pid=host`, no `seccomp=unconfined` and above all no Docker socket. Docker's own security page says only trusted users should control the daemon, because it runs as root; a container that can reach it can start a privileged container on the host. For a stronger boundary, keep the same flags and add `--runtime=runsc` once gVisor is installed.

```python
def sandbox_argv(image: str, name: str, limits: Limits = Limits(), docker=("docker",)) -> list:
    """`docker run` for one job: a fresh container with no network and nothing from the host."""
    if not DIGEST_PINNED.fullmatch(image):
        raise ValueError("pin the sandbox image by digest")
    return [
        *docker, "run", "--rm", "-i", "--init", "--name", name,
        "--network=none",
        "--read-only",
        f"--tmpfs=/tmp:rw,nosuid,nodev,noexec,size={limits.tmpfs_bytes}",
        f"--user={USER}",
        "--cap-drop=ALL",
        "--security-opt=no-new-privileges",
        f"--pids-limit={limits.pids}",
        f"--memory={limits.memory}",
        f"--memory-swap={limits.memory}",  # equal to --memory: no swap
        f"--cpus={limits.cpus}",
        f"--ulimit=fsize={limits.file_bytes}",
        "--ulimit=nofile=256:256",
        "--ulimit=core=0",
        "--log-driver=none",  # the code's output must not land in Docker's logs
        image, "python", "-I", "-c", RUNNER,
    ]
```

## Pass files in and out as data, not as a shared folder

A shared folder is the most common way out of a code sandbox. If the host mounts a job folder read-write and then reads the code's output files from it, the code can leave a symbolic link named `report.txt` that points at `/home/agent/.env`, and the host follows it and hands the agent's API key back to the model. In the project's live tests the starter does exactly this on Docker Desktop. Auto-GPT's compose file shows the other direction: a writable mount lets the code change something the host will later execute.

Send inputs on stdin as part of the job, write them to the container's `tmpfs`, and have a small runner inside the container return the exit status, stdout, stderr and any regular files from an output folder as one JSON envelope on stdout. The runner opens files with `O_NOFOLLOW` and skips links, but the generated code runs as the same user and can forge the envelope, so the host checks it again: valid JSON of the expected shape, file names from a strict pattern, sizes under a limit, base64 that decodes. Nothing the code returns becomes a path on the host until those checks pass.

## Keep the network off, or name the destinations

With network access, generated code can send whatever it finds to an attacker, reach your internal services and cloud metadata endpoint, or download a second stage. Start with no network at all. That also stops `pip install`, which is a feature: build an image with the packages the tool supports, pin it by digest and update it on a schedule, so a hallucinated or typosquatted package name cannot be installed at run time.

If the code genuinely needs a service, do not give the container a general route out. Attach it to an internal network whose only exit is an egress proxy with an allowlist of host names (ASVS 5.0 V13.2.4), block the link-local metadata address, and prefer having the host call the API on the code's behalf through a narrow tool so the credential never enters the sandbox. Remember that DNS is a channel too: a resolver that answers any name lets code leak data in the names it looks up.

## Keep secrets out of the sandbox, and fail closed

The sandbox should hold nothing worth stealing: no model API key, no cloud credentials, no repository tokens, no SSH keys, no `.env` file and no environment variables copied from the agent. Docker passes no host environment variables unless you ask for them, so the risk is the flag someone adds later; test for it by planting a canary variable on the host and checking the code cannot print it. If the code must act on a system, give the host a narrow, authorized tool for that action instead of handing the code a token.

Decide in advance what happens when the sandbox cannot start. A tool that falls back to `subprocess.run([sys.executable, "-c", code])` "so the agent keeps working on laptops" runs hostile code with the agent's environment, files and network. Raise an error and let the agent tell the user the tool is unavailable.

## Bound time, memory, CPU, processes and output

Generated code loops, allocates and forks by mistake as well as by design, and every run costs you capacity. Set each limit in the runtime, not in the prompt: processes with `--pids-limit`, memory with equal `--memory` and `--memory-swap`, CPU share with `--cpus`, file size with `--ulimit=fsize`, and wall-clock time with a deadline on the host. The deadline must kill the container itself: `docker run` is only a client, so a timeout that kills it leaves the container running. The excerpt below kills the container by name and then removes it in case the client died before the container started.

Cap what goes back to the model as well. Output becomes part of the next prompt, so a script that prints 30 MB turns into an unbounded-consumption problem (LLM06:2026) and a channel for injected instructions. Return the first few kilobytes and say the rest was cut.

```python
try:
    status = proc.wait(timeout=limits.timeout_seconds)
except subprocess.TimeoutExpired:
    # Killing the docker client does not stop the container: kill the container by name.
    subprocess.run([*docker, "kill", name], capture_output=True, timeout=30)
    proc.kill()
    proc.wait()
    # If the client died before the container started, remove the late container too.
    subprocess.run([*docker, "rm", "--force", name], capture_output=True, timeout=30)
    raise Rejected(f"timed out after {limits.timeout_seconds:g} s; container killed")
```

## Keep side effects outside the sandbox, behind an approval

A sandbox makes computation safe to run; it does not make the result safe to act on. Sending an email, changing a record, deploying code or paying an invoice should happen outside the sandbox, through the same tool gateway and authorization as any other agent action (/domains/ai-emerging/agent-security/tool-authorization/). OWASP's ASI05 guidance says to separate code generation from execution with validation gates and to require human approval for elevated runs, with any allowlist for automatic execution kept under version control.

Show the approver the exact action, arguments and data involved, not the model's summary of them. People approve what an agent recommends more readily than they should, which OWASP lists separately as ASI09 Human-Agent Trust Exploitation; an approval screen that renders the model's explanation instead of the actual diff or payment details invites exactly that.

## Computer-use and browser agents: the screen is untrusted input

A computer-use agent reads screenshots and sends clicks and keystrokes, so everything on the screen is input to the model. Anthropic's computer use documentation warns that instructions on web pages or in images might override your instructions, and OpenAI's says to treat screen content as untrusted because text in a page, document or tool result "cannot grant permission or override the user's instructions". Vendors add their own detection: Anthropic runs classifiers over what the tools return, such as screenshots, and when they flag a likely injection they steer the model to check that the instruction really came from the user, and Google offers prompt injection detection for Gemini computer use as an opt-in setting that is off by default. Treat these as a second layer; all three vendors still tell you to isolate the agent.

Their documents converge on the same controls. Run the agent in a dedicated virtual machine, container or browser profile with minimal privileges, start each task from a known clean state, and allowlist the domains it may visit. Keep it away from sensitive data such as account logins: do not leave password managers unlocked or sessions signed in, and hand control to the user when a login is needed, because, as OpenAI's guide puts it, typing sensitive information into a form counts as transmission. Ask a person to confirm anything with real-world consequences: purchases and other financial transactions, sending messages, deleting data, accepting cookies or agreeing to terms. Gemini's API marks such steps with a `safety_decision` of `require_confirmation`, and the client must ask the end user and send a `safety_acknowledgement` before continuing. Finally, set step, time and cost limits, support cancellation, and log screenshots, proposed actions and the actions actually executed.

- On-screen injection: a page, email or image tells the agent to open another site, download a file or paste data. Allowlist domains and confirm any navigation the task did not call for.
- Credential entry: the agent types a password or card number into a form it was steered to. Keep credentials out of its reach and let the user sign in.
- Irreversible clicks: Send, Buy, Delete, Accept. Require confirmation in the client, not a polite instruction in the prompt, and show the person what will happen.

## Test escapes, not just features

A sandbox that runs ordinary code proves nothing about hostile code. The agent-code-sandbox project's live tests run both against real Docker: legitimate analysis, a busy loop and a buggy script must still work, while a connection to a canary server on the host, a planted host environment variable, a search for the Docker socket and credential files, a link to a host file left in the output folder, a bounded fork bomb, a 1 GiB allocation, four spinning processes, an endless loop and a 32 MB output flood must all fail or be cut. Each network test has a control run with networking on that does reach the canary, so the test can fail.

Run the same cases against your own runtime after every change to the image, the flags, the container runtime or the host, and record the versions with the results. For a computer-use agent, add pages that carry injected instructions and a fake login form, and check that the agent asks before following them.

## Why prompts, denylists and the agent's own process are not sandboxes

"Do not access the network" in the system prompt is a request to the model, not a control; prompt injection exists because the model cannot be relied on to follow one instruction over another. Denylists of imports, functions or shell commands are bypassed by aliases, dynamic imports, encodings and chained commands; Positive Security noted that Auto-GPT's shell command allowlist could be bypassed by chaining a disallowed command after an allowed one.

Running generated code in the agent's own process, with `exec` or an embedded interpreter, gives it the agent's memory, environment, credentials and network. Running it in a container that mounts the project folder, passes the agent's environment or can reach the Docker socket only moves the problem. The boundary must deny those paths by construction, and the tests must prove it.

## Check the result against concrete cases

Each row is generated code or an agent action and the result the boundary must produce. The project on this page runs the first eight against real Docker.

| Case | Expected result | What it establishes |
| --- | --- | --- |
| Analysis of an attached CSV that writes `out/summary.csv` | Exit 0; JSON on stdout; the CSV returned as data | Legitimate work still succeeds |
| TCP connection to a canary server on the host | Connection fails; canary receives nothing; a control run with networking on does reach it | No network, proven by a test that can fail |
| Print an environment variable planted on the host | Prints `absent` | No secrets pass into the sandbox |
| A link in the output folder to a host `.env` file | The key never comes back | Outputs return as data; the host follows no links |
| Fork bomb bounded at 300 processes | Fork fails at the process limit | Process limit |
| Allocate 1 GiB | Killed by the OOM killer at 256 MB | Memory limit with no swap |
| Endless loop | Killed at the deadline; no container left | The deadline kills the container, not just the client |
| Docker unavailable | Error; nothing runs | Fails closed, never on the host |
| Computer-use agent sees "open this link and sign in" on a page | Agent asks the user; no navigation off the allowlist | Screen content cannot redirect the task |
| Agent reaches a Buy or Send button | Confirmation shows the exact purchase or message | Irreversible actions stay with a person |

## Guided practice

Your team is adding a "run Python" tool and a browser agent to a support assistant. Review the proposed design, identify how generated code or on-screen content could escape or cause harm, and write the corrected configuration.

### Supplied material

```text
Code tool (proposal)
  docker run --rm -i -v $PWD/jobs:/work -w /work --env-file .env python:3.14-slim python -c "$CODE"
  Timeout: subprocess.run(..., timeout=60) around the docker command
  If docker is not installed: run the code with the local python3 so the demo works
  Output files: read every file under jobs/<id>/out/ and attach it to the chat

.env (agent's environment)
  ANTHROPIC_API_KEY=...
  SUPPORT_DB_URL=postgres://support:...@db.internal/support

Browser agent (proposal)
  Runs in the support engineer's own Chrome profile, already signed in to the admin console
  May visit any site a ticket links to
  Can click "Issue refund" when the ticket says the customer was double-charged
```

### 1. Find the escapes in the code tool

List each way generated code could reach secrets, the host or the network.

Worked answer: `--env-file .env` puts the model API key and the database URL inside the container; the default network lets the code send them out or reach `db.internal`; the shared `jobs` folder lets one job read another's files and lets code leave links the host follows when it reads `out/`; the image tag is not pinned; there are no memory, CPU or process limits; the timeout kills only the docker client; and the local fallback runs the code on the host with everything.

### 2. Write the corrected command

Rewrite the docker run command and the surrounding behavior.

Worked answer: An image pinned by digest; `--network=none`, `--read-only`, a size-limited `tmpfs`, a non-root `--user`, `--cap-drop=ALL`, `no-new-privileges`, `--pids-limit`, equal `--memory` and `--memory-swap`, `--cpus` and `--ulimit=fsize`; no `-v` or `--env-file`; inputs on stdin and outputs returned as a checked envelope; a deadline that runs `docker kill` on the container's name; and an error, not a fallback, when Docker is missing.

### 3. Fix the browser agent

Describe where it runs, what it can reach and what needs a person.

Worked answer: A dedicated, disposable VM or browser profile with no saved sessions; an allowlist of domains the support workflow needs; the engineer signs in when needed; ticket text and pages are untrusted; issuing a refund goes through the refund tool with an approval that shows the amount, account and ticket, not through a click the agent makes.

### 4. Prove it

Name four tests you would run before shipping.

Worked answer: A canary connection that fails (with a control that succeeds), a planted host variable that the code cannot print, a link in `out/` that does not return the linked file, and an endless loop that leaves no container; for the browser agent, a page with an injected instruction that makes the agent ask the user.

Deliverable: A list of the escapes you found, the corrected sandbox command and tool behavior, the browser agent's operating rules, and the tests that prove them.

Scope: The design is fictional. Run escape tests only against sandboxes you own, with bounded payloads such as the project's, on a host that holds no real credentials.

## Executable practice

- [Run model-generated Python in a locked-down container: project ZIP](https://softwaresecurity.com/downloads/projects/agent-code-sandbox-ca88c140c78d6501.zip) — Python 3.11+ offline · Docker for the live tests

Articles and teaching material: CC BY 4.0. Original executable code: MIT. Attribution: Software Security.

## Sources

- [OWASP Top 10 for Agentic Applications for 2026 (ASI05 Unexpected Code Execution)](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/). Version 2026, December 2025.
- [OWASP AI Agent Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html)
- [Auto-GPT advisory GHSA-x5gj-2chr-4ch6: Docker escape when running from docker-compose.yml in the git repo (CVE-2023-37273)](https://github.com/Significant-Gravitas/AutoGPT/security/advisories/GHSA-x5gj-2chr-4ch6)
- [Auto-GPT advisory GHSA-5h38-mgp9-rj5f: Python code execution sandbox escape in the non-Docker version (CVE-2023-37274)](https://github.com/Significant-Gravitas/AutoGPT/security/advisories/GHSA-5h38-mgp9-rj5f)
- [Positive Security: Hacking Auto-GPT and escaping its docker container (third-party research)](https://positive.security/blog/auto-gpt-rce). 29 June 2023.
- [Python documentation: sys.addaudithook (audit hooks are not a sandbox)](https://docs.python.org/3/library/sys.html#sys.addaudithook). Python 3.14.
- [Docker docs: docker container run (option reference)](https://docs.docker.com/reference/cli/docker/container/run/)
- [Docker docs: Resource constraints (memory, swap and CPU)](https://docs.docker.com/engine/containers/resource_constraints/)
- [Docker docs: None network driver](https://docs.docker.com/engine/network/drivers/none/)
- [Docker docs: Seccomp security profiles for Docker](https://docs.docker.com/engine/security/seccomp/)
- [Docker docs: Docker Engine security (daemon attack surface)](https://docs.docker.com/engine/security/)
- [gVisor: What is gVisor?](https://gvisor.dev/docs/)
- [gVisor: Docker quick start (--runtime=runsc)](https://gvisor.dev/docs/user_guide/quick_start/docker/)
- [Firecracker microVMs](https://firecracker-microvm.github.io/)
- [Wasmtime: Security](https://docs.wasmtime.dev/security.html)
- [Pyodide: Python compatibility (WebAssembly constraints)](https://pyodide.org/en/stable/usage/wasm-constraints.html). Pyodide 314.0.7.
- [Anthropic: Computer use tool (security considerations)](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool)
- [Anthropic: Code execution tool (containers, networking and limits)](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)
- [OpenAI: Computer use guide (Run safely)](https://developers.openai.com/api/docs/guides/tools-computer-use)
- [OpenAI: Code Interpreter guide (containers)](https://developers.openai.com/api/docs/guides/tools-code-interpreter)
- [Google: Gemini API computer use (safety decisions and best practices)](https://ai.google.dev/gemini-api/docs/computer-use)
- [Google: Gemini API code execution (limitations)](https://ai.google.dev/gemini-api/docs/code-execution)