Guillaume Lebedel · · 6 min
Why AI agent sandboxes don't limit what an API key can do
Table of Contents
AI agent sandboxes such as Modal Sandboxes and Perplexity’s SPACE run agent code in an isolated virtual machine and keep API keys outside it, adding the credential at a proxy as each request leaves. That stops the key from leaking but leaves its scope untouched, so a hijacked agent can still make any call the key allows, deletes included.
Facts checked against Modal, Perplexity and HubSpot documentation on 16 October 2026.
Sandboxes are now a large business. On 14 October 2026 Modal announced a $750M Series D at a $15.75B valuation and said it had crossed $1B in annualized run rate, with sandboxes alone a $300M run rate product. A day later Perplexity open-sourced SPACE, the sandbox platform behind its Computer product.

For a head of AI or a security lead approving agent access to a CRM or HR system, sandboxes settle where the agent’s code runs. They say much less about what the agent may do once its requests reach the CRM.
What does an AI agent sandbox protect against?
An AI agent sandbox protects the host and other tenants from code the agent writes or downloads, and it keeps secrets out of the agent’s working environment. If a prompt injection makes the agent run printenv or read a config file, there is no key there to print, upload or paste into a reply.
Perplexity says SPACE treats “the sandbox as untrusted” and manages “network access and platform-held credentials outside the sandbox”. Each SPACE sandbox runs in a small virtual machine with its own operating system. Its published security evaluation found no escape from the virtual machine to the host in 108 attempts, though some attempts got around network restrictions, and Perplexity says it fixed those weaknesses and neither identified attack method succeeded in follow-up testing.
A sandbox covers four things:
- Untrusted code runs in its own VM or container, not on the host.
- The agent sees its own disk and nothing else.
- Outbound traffic passes through a policy the operator writes.
- Credentials live outside the environment the agent can read.
How does credential injection at a sandbox proxy work?
Credential injection puts a proxy between the sandbox and the internet. The secret stays in the provider’s secret store, the agent sends requests with no credential, and the proxy adds an authorization header to any outbound request whose destination matches a rule. Modal calls this rule an Outbound Policy.
In Modal’s version, the flow has five steps:
- You store the API key as a named Secret.
- You create the sandbox with an Outbound Policy that pairs a domain, such as
api.hubapi.com, with a header template that references the secret by name. - The agent’s code calls the API with no credential.
- The proxy matches the request’s host against the rule and fills the template with the secret value.
- The authenticated request reaches the API, and the secret never appears in the sandbox environment.
Modal’s sandbox secret injection docs say the proxy reads the destination domain from the TLS handshake, a rule’s domain can be an exact hostname, a *. wildcard or a bare *, and only HTTPS on port 443 is eligible. The page describes no path or method condition and marks the feature experimental. NVIDIA OpenShell binds each credential more tightly, to a host, port and path, as we covered in how NVIDIA OpenShell keeps API keys away from AI agents.
What can an agent still do with a key it never sees?
An agent can still do anything the key’s scope allows on the matched domain. The proxy checks where a request is going, not what it asks for, so an update and a delete sent to the same API both leave with the same credential attached.
HubSpot’s CRM scopes reference says crm.objects.contacts.write lets an app “Create, delete, and make changes to contacts”, and there is no separate delete scope for contacts. Its v3 contacts API guide documents a DELETE on the same path a PATCH uses to update a record, /crm/v3/objects/contacts/{contactId}. An agent given write access to fix a phone number holds a credential that can also delete the contact, and a path binding cannot tell the two requests apart.
Picture a support agent in a clean microVM that has never seen the HubSpot token. It reads an inbound email asking it to clean up duplicate contacts from last week’s import. It sends a run of DELETE requests, and the proxy, working as designed, matches api.hubapi.com and attaches the token to each one, so the contacts move to HubSpot’s recycling bin.

Each control answers a different question:
| Control | Keeps the key out of the agent’s environment | Can block a delete on an allowed host | Can hide a field from the model | Knows the person the run is for |
|---|---|---|---|---|
| Proxy injection keyed on domain (Modal Outbound Policy) | Yes | No | No | No |
| Credential bound to host, port and path (NVIDIA OpenShell) | Yes | Only when the delete uses a different path | Not documented | Not documented |
| Provider OAuth scope (HubSpot contacts) | No | No, write covers delete | No | Only the user who authorized the app |
| Action-level policy at the tool layer (StackOne Tool Policies) | Not its job, pair it with a sandbox | Yes, by tool name or pattern | Yes, by field path | Yes, users and groups from the identity provider |
Where should per-action permissions for agents be enforced?
Per-action permissions belong at the tool-call layer between the agent and the business system, before the call turns into an HTTP request. That layer sees the action by name, its arguments and the person the agent acts for. A network proxy sees a host and some headers, while the tool layer sees delete_contact and who asked.
The rules to write at that layer are specific:
- Which tools this agent may call, by name or pattern, such as no
*delete*tools for a support agent. - Which argument values are allowed, such as payments inside a set range.
- Which response fields reach the model, such as no salary or bank details.
- Which users and groups each rule applies to, synced from the identity provider.
That gap is why we built Tool Policies at StackOne, launched on 15 October 2026. A policy sits between the agent and the app across all of our 560+ connectors (stackone.com, 16 October 2026). Its rules block tools by name pattern, limit argument values, mask fields by path, or ask a plain-language question, such as whether a field is compensation, for a decision model to answer. Rules compile to Cedar, where a deny always wins, and they scope to users and groups from your identity provider. One launch example blocks contractors from every *delete* tool, which is the rule the HubSpot scenario above needed.
New rules can run in Monitor mode first, which records what a rule would have done without blocking anything. We described that rollout in monitor first, then enforce agent policies.
An agent that runs code it wrote still needs a sandbox for isolation and to keep keys out of reach.
How do you trace each agent action back to the person it ran for?
You trace an agent action by recording the person the agent acted for on every call, next to the agent, the action, its arguments and the policy decision. A proxy-injected key makes every request look like it came from the key’s owner, so the person has to be captured at the layer that knows who started the run.
A record a security reviewer can use holds:
- The person or role that delegated the run
- The agent and the session it ran in
- The action name and its arguments
- The policy decision, including what a Monitor rule would have done
- The result returned to the agent
We went through each field in what an AI agent’s audit record should contain. In StackOne, every evaluated policy is recorded with its mode and decision, so a reviewer can see who ran which action and which rule allowed it.
If you are reviewing an agent rollout this quarter, list what each injected key can delete, then decide which of those actions any agent should ever call. The Agent Tool Policies page shows how these rules are written, including Monitor only mode.