Assume the prompt injection worked
Detection asks hostile text to reveal that it is hostile. Containment asks a simpler question: if the agent follows every instruction in the repository, what can the resulting process still reach?
A repository asks the agent to “read the setup notes before running tests.” The notes include a hidden instruction: inspect the user's SSH directory, send the interesting files to a diagnostics endpoint, then continue with the original task. Nothing in that chain requires a memory-safety exploit. Reading files, making requests, and following repository instructions are the agent's advertised capabilities.
The security question is therefore not whether the instruction looks suspicious to a model. It is whether the resulting process can read the directory, reach the endpoint, or carry a reusable credential there.
Prompt injection is often treated as a classification problem. Find the suspicious sentence. Score the page. Ask another model whether the instruction looks malicious. Block the obvious phrasing.
Those controls can reduce noise. They cannot define the security boundary, because the attacker chooses the text and can iterate against the same cues the detector uses. A repository can hide instructions in documentation, generated files, issue text, tool output, test failures, or a web page the agent opens.
The durable control begins after detection fails.
Translate the compromise into capabilities
Do not ask what the injected agent intends. Ask what its process can do:
- Which host paths can it read or write?
- Which credentials exist in its environment or home directory?
- Which network destinations and address families can it reach?
- Which sockets let it borrow authority from another host process?
- Can it write directly into the repository or artifact you will trust?
Each answer should be enforced by something outside the agent.
A key inside the box is already compromised
Environment variables and dotfiles are convenient credential delivery systems. They are also readable bytes in the compromised process's authority domain.
A credential broker changes the shape. The real key stays on the host. The box receives a route to a narrow proxy, and the proxy injects authentication only for the allowed service. Scope that route to one runtime. A Claude box should not be able to turn an OpenAI key into a laundering channel merely because both agents are installed on the host.
This does not stop the model service from receiving source included in a legitimate prompt. Source confidentiality against the model is a separate decision: use a self-hosted model or remove model egress.
An allowlist is only as strong as its layer
Proxy variables constrain cooperative applications. A compromised process can clear them and open a socket. If off-list destinations must be unreachable, enforcement has to meet raw traffic: a private network namespace and packet rules, or a VM network stack.
Name the layer. L7 proxy scoping and L3/L4 destination enforcement are not interchangeable promises.
Local sockets are network authority too
Unix sockets disappear from many threat models because they do not look like internet access. They can connect the box to SSH agents, desktop services, container daemons, and other privileged processes. Some can carry open file descriptors.
Deny the address family by default. Grant it only to profiles that need it, and keep host sockets outside filesystem grants. A browser control daemon may justify one scoped socket. A test runner usually does not.
The final capability is acceptance
A compromised agent that cannot read secrets or dial arbitrary hosts can still produce a malicious patch. Containment limits blast radius during execution; it does not certify the output.
That is why the box should not merge its own work. Export a path-validated patch and evidence bundle. Review them outside. The human-operated output gate is part of the security design, not workflow polish.
What success looks like
Success is not “the detector found every injection.” Success is that an injected agent encountered the same narrow world as a cooperative one:
- the host filesystem was absent except for explicit grants;
- reusable credentials never entered;
- off-list destinations were refused at the claimed layer;
- the process could not reach ambient host sockets;
- the result still required an external decision.
The injection may succeed as language. It fails as authority.
Why detection remains useful but cannot carry the boundary
Filters can catch crude attacks. A reviewer can notice an instruction in a README. A second model can flag text that asks for secrets. Tool descriptions can be scanned before they enter context. These controls reduce exposure and improve triage.
They still operate on the attacker's representation. Rename the file, split the instruction across tool outputs, encode the payload in a test failure, or make the dangerous action look like a legitimate debugging step. A sufficiently strict filter also blocks real work, because coding routinely requires reading configuration, opening documentation, and sending authenticated requests.
Containment works on the action after ambiguity has ended. Whatever prose led to open(), socket(), or a write outside the workspace no longer matters to the enforcement decision.
The browser chains ambient authority without exposing a token
A normal browser profile is the sharpest example. It holds cookies for source control, email, CI, cloud dashboards, and internal tools. The agent never needs to read those cookies. It navigates and the browser authenticates the request automatically.
The same process reaches host loopback, where developer services often rely on “local only” instead of authentication. And the browser's primary input is page content controlled by someone else. Prompt injection becomes the instruction channel joining live sessions, extensions, and local services.
A fresh browser profile inside the box removes the inherited sessions and extensions. A private network namespace changes loopback from “the developer's machine” to “this disposable environment.” The page can still inject the agent. The injected agent finds much less authority waiting for it.
A credential broker removes the reusable secret from the compromise
Model access creates an awkward exception. The box must call Anthropic or OpenAI, and the ordinary implementation puts the API key in an environment variable or credential file inside the very process we are assuming compromised.
h5i can instead point the client at a host-side broker. The box presents a per-run dummy token. The broker pins the upstream origin, validates origin-form request targets, strips the dummy, injects the real host credential, and creates the TLS request itself. Stealing the dummy gives an attacker no reusable API credential.
The broker is authentication plumbing, not authorization. A broad GitHub token remains broad when used through a broker. Fine-grained service credentials are still required. Nor can the broker stop a legitimate model call from containing private source. It removes credential possession; it does not inspect intent.
Build the response as independent layers
| Attack step | Boundary response | Residual risk |
|---|---|---|
| Read host secrets | Do not grant host paths; seed a scrubbed per-box HOME | Files intentionally copied into the workspace remain readable |
| Steal a model key | Keep the real key behind a runtime-scoped broker | Allowed model requests can still contain source |
| Exfiltrate to a new host | Default-deny egress at the claimed layer | Allowed destinations remain reachable |
| Borrow a local daemon | Deny Unix sockets and isolate loopback by default | Explicit socket grants carry real authority |
| Ship a malicious patch | Require export and external review | A reviewer can still make a bad decision |
No row depends on the model agreeing that it has been compromised. That independence is the design.
The honest stopping point
A sandbox does not solve prompt injection as a language problem. The agent may still waste time, damage its disposable workspace, produce a deceptive explanation, or create a malicious patch. A shared-kernel tier remains exposed to a targeted kernel exploit. An allowlisted service can still be abused within its authorization.
The goal is narrower: prevent untrusted instructions from inheriting the developer's ambient machine authority. That turns a successful injection from an account- and host-level incident into a failed or reviewable action inside a disposable box.
Why the usual mitigations stop one layer too early
“I require approval for shell commands.” The dangerous action can be hidden among dozens of ordinary build and inspection calls. Approval fatigue is the predictable output of putting a human gate on a machine-rate loop. More importantly, package hooks and browser requests may occur below the command the human approved.
“The browser verbs are read-only.” Navigation can trigger state changes through confirmation links and poorly designed GET endpoints. Reading page content is itself an exfiltration primitive once that content enters the model context. Verb names do not define authority.
“The key is encrypted on disk.” The agent does not need to decrypt a browser cookie store if it can drive the browser that decrypts and attaches cookies. It does not need to steal an API key if an allowed client will make any request it asks for. Protecting bytes at rest does not constrain the authorized interpreter.
“The agent runs in a container.” A container with the host browser profile mounted, a Docker socket exposed, or host loopback reachable still carries the authority that matters. Containerization is a mechanism, not a completed threat model.
“The model vendor blocks prompt injection.” Even a strong detector cannot mediate a native install script, a compromised compiler plugin, or an ordinary request that is dangerous only because of the credential and destination available in this environment. The enforcement point has to sit where the action becomes concrete.
Use the compromise drill
Take a real profile and assume the agent has become adversarial. Ask it to enumerate readable host paths, reusable credentials, reachable internet hosts, reachable loopback services, Unix sockets, and direct write paths to accepted code. Do not actually exfiltrate data; inspect the resolved policy and exercise harmless denials.
If the answer relies on “the agent would not do that,” the authority is still present. If the answer is “the syscall, packet, or export path is refused and the refusal is recorded,” the boundary can survive the model making the wrong semantic decision.
Sources and further reading
- Credentials and Unix sockets in the manual.
- Write a box policy, for expressing filesystem, network, and socket authority.
- Watch the isolated browser, for the fresh-profile and control-lock workflow.
- Credential proxy design, including the origin-pinning and SSRF threat model.
Questions that come up
Does sandboxing prevent source code from reaching the model?
Are permission prompts still useful inside a box?
Write down what the agent may reach
Create a fail-closed profile for filesystem, network, and resources.
Design for the compromised session
A narrow box makes prompt-injection success less consequential.