Overrides
An override rewrites a matching outbound request after it leaves the agent but before it reaches the upstream, the agent never sees the change. It's the recommended way to inject secrets, re-route traffic, or shape request bodies without trusting the agent with any of it.
Overrides are set with the override field on an allow egress rule and apply only to requests that match that rule's host, ports, methods, and paths filters. The agent cannot read injected values back.
Inject credentials
The most common use: give an agent access to an authenticated API without putting the key in its context or environment. The proxy attaches the header to every matching request.
const sandbox = await getOrCreateSandbox("my-sandbox", {
egress: [{
access: "allow",
host: "api.finnhub.io",
override: { headers: { "X-Finnhub-Token": process.env.FINNHUB_API_KEY! } },
}],
});The agent can now curl https://api.finnhub.io/... with no credentials, the token is added transparently.
What you can override
| Field | Description |
|---|---|
headers | Add or overwrite request headers (e.g. Authorization). |
query | Add or overwrite URL query parameters (e.g. ?api_key=…). |
host | Re-route the request to a different upstream ("hostname[:port]"). The agent-visible Host header and TLS SNI keep the original hostname. |
prefix_path | Prepend a path prefix to the outbound request (/mock turns /v1/user into /mock/v1/user). |
body | Rewrite the request body. A string replaces it verbatim; an object merges into (or replaces) the agent's JSON body. |
If the agent already set the same header or query parameter, the override wins.
Query parameters
Some APIs authenticate with a query parameter instead of a header:
override: {
query: { api_key: process.env.SERVICE_API_KEY! },
}Multiple headers at once
override: {
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"X-Tenant-Id": process.env.TENANT_ID!,
},
}Rewrite the request body
An object body is shallow-merged into the agent's JSON body by default (body_strategy: "merge"), your keys win, the agent's other keys are preserved. Use this to pin fields the agent shouldn't control. Set body_strategy: "replace" to discard the agent's body entirely, or pass a string to replace it verbatim.
override: {
// Force these fields no matter what the agent sends
body: { model: "gpt-4o-mini", temperature: 0 },
body_strategy: "merge", // default
}Programmatic rewrites with a Lua script
When a static override can't express the logic, deriving a header from the body, conditional routing, rewriting part of a payload, set override_script to a small Lua script. It's a sibling of override on the egress rule (not a field inside it) and runs against each matching inspected HTTP request after the static override is applied.
override_script sits alongside override on the rule:
egress: [{
access: "allow",
host: "api.example.com",
override: { headers: { "X-Tenant": "acme" } }, // static override runs first
override_script: `
-- then the script runs and can rewrite headers/body
headers["X-Request-Path"] = path
`,
}]The scripting environment
The script runs in a restricted Lua VM (base, string, table, and math libraries only, no file, network, or OS access).
| Name | Kind | Description |
|---|---|---|
body | mutable string | The request body. Reassign it to rewrite what's sent upstream. |
headers | mutable table | Header name → value. Assign to add/overwrite; set to nil to drop. |
method | read-only string | HTTP method. |
host | read-only string | Request host. |
path | read-only string | Request path. |
query | read-only string | Raw query string, without the leading ?. |
urldecode / urlencode | helper | URL-decode / URL-encode a string. |
b64decode / b64encode | helper | Base64 decode / encode a string. |
Header names in the headers table are canonicalized (X-Raw-Key, not x-raw-key), so index them in that form. Reassigning method/host/path/query has no effect, only body and headers are written back.
Examples
Turn a raw key into a Base64 auth header, the agent sends a plain key, the proxy encodes it and removes the original:
headers["Authorization"] = "Basic " .. b64encode(headers["X-Raw-Key"])
headers["X-Raw-Key"] = nilAdd a header only for certain paths, conditional logic a static override can't do:
if string.match(path, "^/admin/") then
headers["X-Require-Approval"] = "true"
endRewrite the body, force a field in a JSON payload with a string substitution:
-- pin "stream": true regardless of what the agent sent
body = string.gsub(body, '"stream"%s*:%s*false', '"stream": true')Move a query parameter into a header, read from query, inject a header:
local key = string.match(query, "api_key=([^&]+)")
if key then
headers["Authorization"] = "Bearer " .. urldecode(key)
endoverride_script only when the static fields can't do the job, headers, query, and body cover most cases. Scripts apply to inspected HTTP requests only (CONNECT and passthrough TLS are unaffected), are bounded to 200 ms and an 8 MiB body, and fail open: if the script errors, it's logged and the request proceeds with the static override applied but the script's changes skipped.Re-route the upstream
host sends matching requests to a different destination, handy for pointing an agent at a mock or a proxy without it knowing. The agent still sees the original hostname in the request it made.
override: { host: "localhost:8080" }Re-routing the host is also how you point an agent at a mock API: match the real host and override it to a stub you run. See Mocking for a complete example.
Update overrides at runtime
Rotate a token or change routing on a running sandbox with applyConfig:
await sandbox.applyConfig({
...(await sandbox.getConfig()),
egress: [{
access: "allow",
host: "api.example.com",
override: { headers: { Authorization: `Bearer ${newToken}` } },
}],
});The new override applies to all subsequent matching requests.
Back to Access