Knowledge tree
Offensive Security
Shells
File Transfer
Web Applications
Sandboxing & Egress
An authorized action can still execute code that does much more than its name suggests.
Allowing an agent to run npm test, execute a script, or open a file answers a permission question: whether that action may start. Sandboxing answers a different one: once execution starts, which resources can it actually reach.
Egress completes that boundary by controlling outbound communication. A process can be isolated from the rest of the host and still have a path to impact if it can read sensitive information and send it to an external destination.
It is therefore useful to analyze both dimensions together:
execution → reachable resources → outbound channel → impact
Execution boundary
Agent permissions determine whether an action may start. Once the process starts, that decision has already been made. What matters next are the restrictions the environment enforces regardless of what the model, the script, or one of its subprocesses tries to do.
An execution boundary can constrain, among other things:
- Which parts of the filesystem are visible.
- Which paths are read-only or writable.
- Which host processes or interfaces are available.
- Which credentials enter the environment.
- Which outbound network connections are possible.
The property that matters is which resources remain unreachable even if the executed process is hostile.
Filesystem isolation
A coding agent usually needs read and write access to its workspace. That does not imply equivalent access to the entire host.
A configuration can expose the repository as read/write while keeping personal directories, system configuration, and credential stores out of reach. It can also make some areas read-only when the agent needs to inspect them but not modify them.
Separating read from write access matters. Preventing changes to ~/.ssh does not protect a private key if the process can still read it and has a channel through which to send it.
A stronger boundary is to keep the secret out of the environment altogether. If a credential remains in the host keychain and is never mounted or exposed to the process, code running inside the sandbox cannot read it directly. Keeping credentials outside the isolated environment reduces blast radius even when code inside it is untrusted.
Resolved paths
Filesystem restrictions must be enforced against the resource that will actually be accessed, not only against the path received by the application.
A classic example is a symbolic link. A file inside an authorized directory can be a symlink to a path outside it. If a system validates the apparent path first and resolves the link afterwards, the operation can cross the boundary it was intended to enforce.
A robust implementation therefore resolves the effective path before deciding whether it falls inside the allowed area.
The boundary has to validate the resource that will ultimately be reached.
Runtime isolation
The filesystem is only one part of the execution environment.
A sandbox can also separate processes, operating-system interfaces, and other host resources. The concrete implementation may use OS-level sandboxing, a container, or a virtual machine.
The level of isolation depends on the implementation. A restricted process can still share much of the host. A container usually adds namespaces and other controls while continuing to share the host kernel. A VM can provide its own kernel, filesystem, and process table.
The useful comparison is which boundary still applies even if the authorized command executes arbitrary code.
If npm test starts Node.js, Node.js launches a subprocess, and that subprocess invokes another utility, the restriction should continue to apply through that chain. A control that only examines the first tool call is not a sufficient execution boundary.
Interfaces deliberately exposed across the isolation boundary also matter. Mounting a host directory, exposing a privileged socket, or introducing a credential expands what the environment can reach. Every exception becomes part of the sandbox’s effective surface.
Network egress
Local isolation does not by itself control what can leave the environment.
Egress is traffic initiated from the execution environment toward other systems. For an agent, this can be an HTTP request, a dependency connection, an API call, or any other network channel available to the process.
From a security perspective, there is a simple relationship:
readable data + outbound channel = possible exfiltration path
A tool called exfiltrate is not required. If an agent or one of its subprocesses can read a secret and has arbitrary network access, Python, an HTTP client, or a dependency executed during the build can provide the channel.
Network policy can be enforced outside the process itself: deny network access by default, allow specific destinations, or route connections through a proxy that decides which ones are accepted.
Allowlisted domains
Allowing a domain grants the environment the operations that can be performed through that destination; it does not make those operations trusted.
An approved host can expose many different operations, store content for multiple users, or support uploads into third-party accounts.
Anthropic documented a case where api.anthropic.com was correctly allowlisted because the product needed to communicate with its own API. Malicious content was nevertheless able to use that route to upload files into an attacker-controlled account. The sandbox and destination check worked; the policy was too broad for the effect it was intended to prevent.
The later control added awareness of the request and credential being used rather than relying only on the hostname.
The same principle appears in agent permissions: denied tool ≠ denied capability. For network access, allowed domain ≠ safe operation.
Alternate paths
An execution boundary has to control the final effect even when code finds another way to express it.
Blocking curl does not remove egress if Python can open network connections and the network remains available. Denying a filesystem tool does not protect a path if the same process can access it through normal system calls. Protecting a directory by name does not work if a symlink resolves outside it.
Sandboxing should not depend on the agent voluntarily choosing the right tools.
Permission rules decide before execution which commands may start. The sandbox enforces another property: the operating system or isolation layer limits what the process can do after it starts.
The two layers complement each other:
permission policy → which action may start
execution boundary → what that action can reach even if it behaves unexpectedly
Example: coding agent
Suppose an agent receives this task:
Run the repository tests and fix the failures.
Its environment provides:
- A read/write workspace.
- Bash and the required dependencies.
- Network access to the registry used by the project.
- No access to the user’s home directory.
- No GitHub credentials inside the sandbox.
The agent correctly decides to run npm test.
During the tests, a compromised dependency is loaded. Its code tries to read the user’s SSH key, inspect environment variables for tokens, and send any secrets it finds to an external server.
The model has made a correct decision and no prompt injection is involved. The original action — running the tests — was legitimate.
Security now depends on the execution boundary.
If $HOME is not visible and credentials never entered the sandbox, the key and tokens are unavailable to that process. If some sensitive data is readable but the external destination is blocked by the egress policy, the channel required to send it is missing. If both the data and arbitrary outbound access are available, the authorized execution has a path to impact.
The chain can be expressed as:
authorized action → untrusted code → reachable resource → available egress → impact
The sandbox also constrains code, tools, and dependencies that the agent correctly executes as part of a legitimate task.
Security boundaries
Prompt injection, permissions, and isolation control different properties of the system.
A prompt injection allows untrusted content to alter the model’s decision.
Agent permissions determine whether the requested action has authority to execute.
Sandboxing and egress limit what that execution can reach and what can leave the environment.
These layers can appear in the same chain:
untrusted input → manipulated decision → authorized action → overexposed execution → external impact
They are also independent. A prompt injection can alter only a response without executing anything. An agent can have excessive permissions even if it never processes malicious content. A compromised dependency can exploit a weak execution boundary even when both the model and permission policy behave exactly as intended.
Separating the layers makes it easier to identify which security property failed and where the control belongs.