Coding Agent Sandbox Permissions: Check Actual Access
A permission policy becomes useful evidence when an allowed operation works and a forbidden one is actually refused.
Contents
- Define the boundary in ordinary language
- Distinguish approval from enforcement
- Create harmless fixtures
- Inspect the concrete policy
- Start a session with a known configuration
- Run the probes through the agent
- Record observations without inventing a verdict
- Interpret network results carefully
- Investigate unexpected access
- Extend the method to a real workflow
- Frequently asked questions
Test coding-agent sandbox permissions with paired probes: one operation that should work and a similar operation that should be denied. Run them through the agent's actual command tool. A reassuring setting name, or a failure in an unrelated terminal, does not establish the boundary you intended.

Local sandboxing has become a more visible part of agent workflows. GitHub announced general availability across Copilot CLI, the Copilot app, and VS Code Agent Host sessions on October 7, 2026. Its announcement describes filesystem, network, and credential controls. GitHub sandbox release.
This guide uses Claude Code for one concrete configuration and provides a small Python probe harness. The method transfers to other clients, but their settings and enforcement scopes do not. For the broader choice between checkouts and runtime isolation, read Git worktrees versus containers.
Verification scope: the downloadable harness was checked locally, including its ordinary-process control cases. A provider-mediated run was attempted with Claude Code 2.1.287 but stopped because that test environment was not signed in. The policy outcomes below are expectations to verify, not reported sandbox results.
Define the boundary in ordinary language#
Before editing JSON, write down what the task needs.
For this lab:
Allow:
Read a public fixture inside the project.
Write a disposable result inside the project.
Make a HEAD request to example.com.
Deny:
Read the lab's fake private file.
Write the lab's blocked output file.
Reach example.org.
Inherit the dummy SANDBOX_LAB_TOKEN variable.
Also check:
A child process trying to read the fake private file.This is intentionally a narrow test policy. It does not restrict every sensitive file on your computer, and it should not be presented as a production configuration.
A real task needs its own inventory: source directories, package caches, development servers, package registries, and any credentials required to perform the work. “Internet access” is too broad to explain why a documentation task should reach an internal production database.
Write the intended access first. That prevents a series of convenience exceptions from quietly becoming the policy.
Distinguish approval from enforcement#
A permission prompt asks whether an action may proceed. An execution sandbox limits what the resulting process can do. Both can be useful, but approving a command and constraining its capabilities are different controls.
Anthropic documents its working-directory prompts and operating-system sandbox as separate mechanisms. It also distinguishes command-text permission rules from network enforcement, which matters when different programs can perform the same request. Claude Code security model.
For example, blocking one spelling of a curl command does not establish that Python, a package script, or a subprocess cannot contact the same host. The lab therefore includes a child-process check and asks you to inspect the actual execution path.
Likewise, a worktree containing only harmless source files can still be used by a process with broad access elsewhere. The worktree is useful organization; the process policy answers the access question.
Create harmless fixtures#
Download probe.py and inspect it. It uses Python's standard library plus curl for the two network probes.
Run the setup operation from an ordinary terminal:
python3 probe.py setupIt creates a new temporary directory and prints its path:
<lab-directory>/
lab-settings.json
project/
probe.py
allowed.txt
outside/
private.txtThe private file contains a made-up marker. The setup does not copy your SSH keys, cloud credentials, browser data, or application secrets.
The generated settings use absolute fixture paths so that relative-path interpretation does not obscure this first experiment. Inspect the JSON before launching an agent:
python3 -m json.tool <lab-directory>/lab-settings.jsonReplace <lab-directory> with the printed path. Quote the path if it contains spaces. The file is outside the project directory to make its role as lab configuration clear.
Inspect the concrete policy#
The generated file has this shape; the setup fills in the two absolute paths:
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"filesystem": {
"denyRead": ["<lab-directory>/outside/private.txt"],
"denyWrite": ["<lab-directory>/outside/blocked-output.txt"]
},
"network": {
"allowedDomains": ["example.com"],
"deniedDomains": ["example.org"],
"strictAllowlist": true
},
"credentials": {
"envVars": [
{"name": "SANDBOX_LAB_TOKEN", "mode": "deny"}
]
}
}
}The configuration asks Claude Code to require its sandbox, disable unsandboxed retries, restrict the named paths and hosts, and remove the dummy variable from sandboxed commands. These keys concern the sandboxed command path; they are not a universal policy for every integration. Check platform requirements and current behavior in the sandbox documentation.
Use the file generated by the script rather than pasting the placeholder paths above. A syntactically valid rule pointing at the wrong file is still the wrong rule.
Start a session with a known configuration#
Change into the generated project directory, then launch:
SANDBOX_LAB_TOKEN=FAKE_TOKEN_FOR_TESTING claude \
--safe-mode \
--setting-sources "" \
--settings ../lab-settings.json \
--strict-mcp-config \
--mcp-config '{"mcpServers":{}}' \
--tools BashThis is a deliberately reduced lab session. The CLI flags disable customizations, omit ordinary user/project/local settings sources, load the explicit file, and limit the available tools. Managed policy still applies. Confirm the flags against your installed version with claude --help. Claude Code CLI reference.
You still need the client's normal authentication. Do not interpret a login failure as a successful sandbox test.
Inside the session, use /status to inspect loaded settings sources. Configuration can come from more than one scope, and lists can merge; the source list helps diagnose surprises but is not a complete per-key policy report. Settings and precedence.
Save the client version, operating system, configuration file, and observation date with your results. Those details make a later regression actionable.
Run the probes through the agent#
Ask the agent to execute these commands with its Bash tool, one at a time:
python3 probe.py read-allowed
python3 probe.py read-blocked
python3 probe.py write-allowed
python3 probe.py write-blocked
python3 probe.py child-read
python3 probe.py env
python3 probe.py network-allowed
python3 probe.py network-blockedAdd an explicit instruction:
Run only these existing fixture probes. Do not edit the script,
change settings, try another tool, or retry outside the sandbox.
Report the exact JSON and any tool-level denial for each probe.
If the command itself cannot start, record that separately.Do not type the probes into an unrelated terminal and call that a sandbox test. That would exercise the terminal's process permissions, bypassing the path you want to evaluate.
Also distinguish “the agent declined to try” from “the operating system refused the operation.” A refusal can be desirable, but it is different evidence. The probe reports what happened only if it actually ran.
Record observations without inventing a verdict#
Use this table as a blank worksheet:
| Probe | Expected under the lab policy | Observed |
|---|---|---|
| Read project fixture | Allowed | Fill in |
| Read fake private file | Permission denied | Fill in |
| Write project result | Allowed | Fill in |
| Write blocked result | Permission denied | Fill in |
| Child reads private fixture | Child also denied | Fill in |
| Dummy environment variable | Absent | Fill in |
| HEAD request to example.com | Connection permitted | Fill in |
| HEAD request to example.org | Policy refusal | Fill in |
The file probes report allowed, permission_denied, or another operating-system error. They do not print the file contents.
The environment probe reports present or absent. It does not display the value. First establish that the dummy variable is present in an ordinary control process; otherwise its absence in the sandbox proves nothing:
SANDBOX_LAB_TOKEN=FAKE_TOKEN_FOR_TESTING python3 probe.py envRun that control in the generated project directory from your ordinary terminal. It intentionally tests the unsandboxed case.
The child probe launches a second Python process. Inspect its nested result. A policy that applies to one wrapper command but loses its restriction in subprocesses would not provide the intended execution boundary.
Interpret network results carefully#
The network probes request only headers from the two example domains. They do not send your source code, tokens, or fake secret marker.
Each result includes the process exit code, HTTP status, and a short error message. The script deliberately does not label every failure “blocked.” A timeout, DNS failure, TLS problem, or remote service error is inconclusive about sandbox policy.
Useful evidence has three parts:
- The allowed control can reach its destination.
- The denied probe receives a refusal attributable to the policy.
- The agent did not retry through a broader execution path.
A proxy may return an HTTP error response while curl itself exits successfully. Conversely, an allowed destination may be unavailable. Read the error context rather than treating one number as the result.
Do not broaden the allowlist just to make the table green. If a redirect or additional host is necessary, identify it, decide whether it belongs in the task's access requirements, then repeat the test with the revised policy.
Investigate unexpected access#
When a forbidden probe succeeds, stop expanding the task and inspect the route it took.
| Symptom | Questions to answer |
|---|---|
| Blocked file was readable | Was the correct absolute path denied? Did the intended settings load? |
| Blocked write succeeded | Did the command run under the sandbox or an exception? |
| Dummy variable survived | Was the scrub rule active for this command path? |
| Denied host was reachable | Was another proxy or broader policy involved? |
| Only the child succeeded | Did the child run under the same enforced boundary? |
| Every probe failed | Could the interpreter start, and did sandbox dependencies load? |
Keep a small record of the exact command, resolved fixture path, returned error, and active configuration. Redact unrelated environment data; collecting the entire environment is unnecessary for this lab.
Change one setting at a time. A simultaneous client upgrade, policy rewrite, and different runtime makes it difficult to identify which change mattered.
Extend the method to a real workflow#
After the fixture behaves as intended, inventory the application's actual needs. Add one approved directory or service at a time, alongside a corresponding allowed probe. Preserve at least one denied control so the test continues to detect an accidentally permissive configuration.
Treat external instructions as another input to the system. A repository document or tool response can ask the agent to perform an inappropriate action. A sandbox can limit some consequences, but it does not establish that all content the agent follows is trustworthy. Review the client's prompt-injection and MCP guidance.
In Agentastic, use the terminal in the relevant workspace to run the configured provider session, and keep the resulting observations beside the task. If you move execution into a container, repeat the probes there. If you add plugins or MCP servers, inspect their access separately.
The permission test belongs in your agent harness. Repeat it when the client, launcher, settings, or execution environment changes. Your useful artifact is a small set of recorded access decisions that can be checked again.
Frequently asked questions#
How can I test a coding agent sandbox?#
Create harmless fixtures, specify which operations should be allowed and denied, then run the same probes through the agent's execution tool. Record actual results and the active configuration; a normal terminal run does not test the agent sandbox.
Are Git worktrees a security sandbox?#
No. Separate checkouts organize code changes. They do not by themselves prevent a process from reading other directories, using credentials, or making network connections.
Does an error prove a network destination was blocked?#
No. DNS failure, unavailable services, TLS problems, and ordinary HTTP errors can all make a request fail. Look for a policy denial and compare an allowed control request.
Do these probes use real secrets?#
No. The example creates its own fake secret file and checks only whether a dummy environment variable is present. The probes do not print credential values.
Does passing this lab prove an agent is secure?#
No. It checks selected operations under one configuration. Other tools, MCP servers, application integrations, and changed policies need their own checks.