agent-proxy run starts a proxy alongside your agent and stops it when the agent exits. It all happens on the one machine, with the agent sandboxed away from your credentials:
run takes.
What you set up
There are only two moving parts:run authenticates as you, and it starts and stops its own proxy around the agent.
For agents running on your infrastructure, see standalone proxy.
What the sandbox is for
The proxy holds real credentials, and it runs on the same machine as the agent. Something has to keep the agent away from them, and that something is an OS-level sandbox: the agent cannot read the proxy’s files, your keyring, or your credential files, and it cannot reach the network except through the proxy.run builds it for you each time you start an agent, and takes it down when the agent exits:
Requirements
- The Infisical CLI installed, and
infisical logincompleted. - At least one proxied service in the folder you point
runat. Brokering only happens for hosts a service matches; if you have none, everything simply passes through uncredentialed. - macOS, or Linux with bubblewrap installed. The sandbox comes from the operating system, so what you install depends on which one you are on:
- macOS
- Linux
Nothing to install. The sandbox is part of macOS.
Running an agent
Every option resolves the same way: the flag → an environment variable →.infisical.json → the default. Run it from a directory that has an .infisical.json (created by infisical init) and the project, environment, and path come from there, so most of the flags fall away:
Everything after
-- is your agent’s own command, run as-is. From a project directory:
What a run does
- Resolves your identity, from your keyring login or
--token. - Fetches your proxied services and the real secret values into its own memory. They are never written to disk and never reach the agent.
- Checks the sandbox will hold on this host, then starts the proxy and launches your agent inside it.
- On exit, revokes any dynamic-secret leases, drops the cached credentials, and removes the temporary directory.
0700 temporary directory holds the only things that touch disk:
The sandbox
The sandbox is on by default, and it is what makes brokering safe when the proxy and the agent share a machine. Its restrictions are deliberate, and a few are surprising the first time, so this is the part worth reading before you userun for real work.
Platform support
On Linux,
run checks the sandbox before starting your agent. If the private network is unavailable but the rest of the sandbox works, it falls back to shared networking and warns you. If the sandbox cannot start at all (unprivileged user namespaces restricted, as on stock Ubuntu 24.04), it stops and tells you how to fix the host rather than running your agent uncontained.
Network: the proxy is the only way out
Under both enforced modes the agent has exactly one route to the outside, the proxy. Direct connections fail, including connections straight to an IP with no hostname involved. Only HTTP and HTTPS are brokered, so SSH cannot be: use HTTPS with a brokered token, which is howgit and gh work.
DNS is deliberately unavailable inside the sandbox. The agent does not need a resolver: it hands the hostname to the proxy in a CONNECT or an absolute-URI request, and the proxy resolves it on the host, outside the sandbox. Blocking it buys two things. A tool that ignores the proxy variables fails loudly instead of quietly going direct, and DNS lookups cannot be used to smuggle data out. So Could not resolve host inside a sandboxed agent is expected, and it means the failing tool is not using the proxy.
Both letter cases of every proxy variable are set (HTTP_PROXY and http_proxy, and so on), because some tools read only one, and NO_PROXY always covers localhost and 127.0.0.1.
Two consequences for local servers are worth knowing, since the fence applies to loopback as well as the internet:
- The agent cannot reach a service running on your machine outside the sandbox, such as a database on
127.0.0.1:5432. Loopback bypasses the proxy by design, and the fence denies the direct connection, so it fails. - A server the agent starts is reachable from your machine on macOS, but not on Linux: there the agent gets its own private network, so a dev server it launches is invisible from outside. Start long-lived local servers yourself, outside the agent.
Filesystem: broad read, credentials denied
Reads are allowed nearly everywhere, which is what keeps agents useful. Writes are limited to the working directory, the per-run temporary directory,/tmp, and the state directories of the agents run knows about (~/.claude, ~/.claude.json, ~/.codex), so interactive sessions keep their history and settings. Any other directory an agent writes to needs --allow-write. Carved out of the broad read is everywhere credentials live:
/tmp, so files it writes there are not visible from the rest of your machine. Have it write to your working directory instead of /tmp if you need to open the result yourself.
Credential paths deny writes as well as reads. That matters when you launch an agent from $HOME, where the writable-working-directory rule would otherwise let it append to ~/.ssh/authorized_keys.
If your agent genuinely needs a denied path, re-open exactly that path instead of disabling the sandbox:
~/.aws/config becomes readable, read-only, while everything else under ~/.aws (credentials, sso/) stays denied. run prints what it re-opened. --allow-write <path> adds a writable path, and both flags can be repeated.
Environment: scrubbed
The agent inherits your environment with the credential-shaped parts removed:- Anything whose name looks like a secret is dropped: names containing
TOKEN,SECRET,PASSWORD,PASSWD,CREDENTIAL,API_KEY,APIKEY,PRIVATE_KEY, orACCESS_KEY. The sweep is intentionally coarse and will catch variables you wanted. - Infisical’s own variables, including
INFISICAL_TOKEN,INFISICAL_DOMAIN, and any machine identity credentials. The agent is given no Infisical token at all, so it cannot act as you against the API. - Agent-socket and IPC addresses:
SSH_AUTH_SOCK,SSH_AGENT_PID,GPG_AGENT_INFO,DBUS_SESSION_BUS_ADDRESS,DBUS_SYSTEM_BUS_ADDRESS,XDG_RUNTIME_DIR. An agent socket lets a program sign and authenticate as you without ever reading a key file, which would sidestep the~/.sshdeny entirely.
run sets the proxy variables, the CA trust variables, and a placeholder for each secret-substitution credential in the folder. Services that use a header rewrite need nothing in the environment; the proxy sets the header itself.
run never injects real secret values into the agent’s environment, even for secrets you can read. If the agent needs a literal value, pass it yourself with --set-env.--set-env wins over everything, including a placeholder.
Certificates and the macOS keychain prompt
For the proxy to apply credentials to HTTPS requests it terminates TLS, so the agent has to trust the certificates it presents.run uses a self-signed local root, generated on your machine; it never involves your organization’s root CA, and the private key stays on the parent side of the sandbox. Leaf certificates are minted per hostname from it.
Tools split into two groups by how they decide what to trust:
- Environment-variable trust (Claude Code, Codex,
curl, Python, Node, Deno).runpointsSSL_CERT_FILE,NODE_EXTRA_CA_CERTS,REQUESTS_CA_BUNDLE,CURL_CA_BUNDLE,GIT_SSL_CAINFO, andDENO_CERTat the local root. Nothing to do. - System trust (
ghand most Go-based tools). These ignore those variables and consult the OS trust store.
run keeps the local root under ~/.infisical/agent-proxy (a sandbox-denied path, so the agent cannot read the key) and adds it to your login keychain once. That is the one password prompt you see on the first run; later runs are silent because the root persists. It grants certificate trust only: keychain secret access stays blocked inside the sandbox, so your Infisical login token remains unreadable. Decline it and everything still works except natively-trusting tools, and run says so instead of failing.
On Linux the root is generated fresh in memory for each run and the environment variables are sufficient, so there is no trust-store step.
Permissions: it all runs as you
Every API call is made with your own token, and it needs three permissions:Read on proxied services to find them, Read Value on the secrets they reference to broker them, and Lease to mint a dynamic one. A default project member already has all three.
That is deliberate. You are running an agent as yourself, on your own machine, against secrets you could already read; a permission boundary between you and yourself would be theater. The sandbox is the security boundary here. The only question run asks is whether you can read the value.
Activity records attribute requests to your email (or token when you pass --token), since the run is authenticated as you, and a brokered service’s last used time is reported under your own account.
Dynamic secrets
Dynamic secrets are brokered like any other credential, with one thing to know about who mints them. The proxy leases lazily on the first request that needs the credential, caches the output fields in memory, renews before expiry, and revokes on a clean exit. Withrun it mints using your token, so your own Lease permission on that dynamic secret is the gate. A dynamic credential you cannot lease is skipped up front, with a single warning in the log file naming the secret, rather than failing every request that needs it.
You are the minter here, so
Lease on the dynamic secret is a permission you need yourself. The agent still cannot mint for itself: it has no token and no route to Infisical.Watching what it does
Nothing is logged unless you ask for it. Pass--log-file and the proxy writes a record per request to that path, which you can follow in another terminal:
brokered (a service matched and a credential was applied), passthrough (no service matched, forwarded untouched), blocked (rejected by --unmatched-host=block), or error. Records carry the same fields as in Activity Logs, written in the human-readable console format.
Without --log-file you still see problems: warnings and errors print to your terminal, including a credential the proxy had to skip and a dropped authorization. What you lose is the per-request trail, so reach for --log-file when you need to see what happened on a specific request.
passthrough is the one decision left out by default, and it is usually the bulk of an agent’s traffic, so a log stays small. --log-level debug adds it, which is useful when you are working out why a host is not being brokered and noisy the rest of the time.
A path you pass to
--log-file is appended to on every run and never rotated for you, so rotate it with logrotate (copytruncate) if you keep one around.Troubleshooting
Could not resolve host
Could not resolve host
Expected: DNS is blocked inside the sandbox on purpose. It means the tool that failed is not routing through the proxy. Check whether it reads
HTTP_PROXY / HTTPS_PROXY.Certificate errors
Certificate errors
The tool is not reading the injected CA. Most honor one of the six trust variables; Go-based tools on macOS use the system trust store, which is what the one-time keychain prompt covers. If you declined that prompt, those tools fail here.
A tool refuses to start, complaining it cannot read its own config
A tool refuses to start, complaining it cannot read its own config
For example The same pattern applies to any tool with a config-directory override.
failed to read configuration: open ~/.config/gh/hosts.yml: operation not permitted. The file exists but is unreadable, and many tools treat that as fatal rather than falling back to “no config”. Re-opening it with --allow-read is usually the wrong fix, because for gh that file is the GitHub token.Point the tool at a throwaway config location so it never touches the denied path and picks up the placeholder from the environment instead:Everything is passthrough, nothing is brokered
Everything is passthrough, nothing is brokered
No proxied service matched the host. Check the host pattern against the exact hostname the agent calls, that the service is enabled, and that you are pointed at the folder the service lives in.
A 401 from the upstream API
A 401 from the upstream API
The credential was not applied and the request was forwarded as the agent sent it; the proxy does not block the call. Check the activity log for the decision, and that you have
Read Value on the secret the service references.The sandbox will not start on Linux
The sandbox will not start on Linux
Either bubblewrap is missing (install it as shown in Requirements) or unprivileged user namespaces are restricted on the host. The error says which.
run refuses to start rather than running your agent uncontained.A tool cannot prompt for a password
A tool cannot prompt for a password
On Linux the agent runs in its own session, which is what stops a sandboxed process from pushing keystrokes into your terminal. Its stdin and stdout are still terminals, so TUIs behave normally, but a tool that opens
/dev/tty directly to prompt, sudo for instance, cannot. Run that step yourself, outside the agent.The agent cannot read a file it needs
The agent cannot read a file it needs
It is probably in a denied credential path. Re-open just that file with
--allow-read <path>. Reach for --no-sandbox last, not first.Turning the sandbox off
run prints a warning saying so. This is a debugging tool, and the only option on Windows.
INFISICAL_AGENT_PROXY_SANDBOX=0 does the same thing. Neither can be set from .infisical.json, deliberately, so a committed file cannot quietly disable the boundary for everyone who runs the agent.
Next steps
agent-proxy CLI reference
Every flag for
run, start, and connect, with examples.Proxied Services
Host patterns, header rewrites, and secret substitution in depth.