How the CubeSandbox Credential Vault Prevents API Keys from Entering the Sandbox
CubeSandbox isolates secrets by storing them in the egress proxy's policy layer and injecting them at the network edge, ensuring API keys never touch the sandbox filesystem, environment variables, or process logs.
The TencentCloud CubeSandbox project implements a credential vault pattern that fundamentally separates sensitive authentication tokens from untrusted code execution environments. Instead of passing API keys into the sandbox through environment variables or mounted files, the system stores secrets centrally within the CubeEgress proxy and injects them only when requests leave the network perimeter.
Policy-Driven Secret Injection
The CubeSandbox credential vault stores raw secret values inside L7 egress policies rather than inside the sandbox instance. According to the source code in CubeEgress/lua/policy.lua, each EgressRule can contain an inject field that carries the secret inline within the policy object itself.
The policy structure stores these injection rules in a shared Lua dictionary (policy_store) that lives in the CubeEgress proxy memory space. Each inject entry follows the format {header, secret, format}, where the secret field contains the actual API key value. Because this policy object resides in the egress proxy—not the sandbox VM—the secret remains physically separate from the execution environment.
-- CubeEgress/lua/policy.lua
-- Policies are validated and stored in policy_store
-- The inject field contains: {header = "x-api-key", secret = "sk-...", format = "${SECRET}"}
Proxy-Side Injection at the Access Phase
When outbound traffic matches a rule containing injection directives, the CubeEgress proxy performs the header manipulation during the access phase defined in CubeEgress/lua/access_phase.lua. The system executes the inject_gates function to validate safety constraints—including scheme verification, host validation, and secret size limits (under 64 KiB)—before any credential touches the wire.
If validation passes, the apply_injects function renders the final header value by substituting the ${SECRET} placeholder with the actual secret, then assigns it via ngx.header[header] = value. This operation occurs only in the proxy, meaning the header materializes on the outgoing request but never exists inside the sandbox's network stack or filesystem.
-- CubeEgress/lua/access_phase.lua (simplified)
local function apply_injects(decision, inject_list)
for _, inj in ipairs(inject_list) do
local ok, reason = inject_gates({inject=inj})
if ok then
ngx.header[inj.header] = render_inject(inj.format or "${SECRET}", inj.secret)
else
decision.inject_dropped = reason -- Audit only, request proceeds
end
end
end
SDK Integration and Vault-Flavor Usage
The CubeSandbox SDK exposes the Inject struct (defined in sdk/go/policy.go) to enable developers to configure credential injection without handling secrets inside sandbox code. The Go type definition confirms the structure contains Header, Secret, and optional Format fields.
When using the Python SDK as shown in docs/guide/integrations/pi-agent.md, developers create rules that inject headers such as x-api-key while the actual key remains in the host process memory only. Inside the sandbox, environment variable inspection reveals only placeholders—confirming the real credential never entered the VM.
from cubesandbox import Sandbox, Rule, Match, Action, Inject
ANTHROPIC_API_KEY = "sk-deadbeef..." # Exists only in host process
rules = [
Rule(
name="allow_anthropic",
match=Match(scheme="https", sni="api.anthropic.com"),
action=Action(
allow=True,
audit="metadata",
inject=[
Inject(header="x-api-key", secret=ANTHROPIC_API_KEY, format="${SECRET}"),
Inject(header="anthropic-version", secret="2023-06-01")
],
),
)
]
sandbox = Sandbox.create(
template="my-template-id",
allow_internet_access=False,
network={"rules": rules},
)
Audit-Safe Secret Handling
The credential vault implements defense-in-depth for observability by preventing secret leakage through logs. As implemented in the policy validation layer, the system redacts secret values in audit trails—replacing them with ***REDACTED***—and records only a short fingerprint (fp-xxxx) derived from the secret's SHA-256 hash.
This design ensures that even if an attacker gains access to CubeSandbox audit logs, they cannot reconstruct the API keys, while administrators retain the ability to correlate policy usage with specific credential versions via the fingerprint.
Summary
- Secrets live in the proxy: API keys are stored inline within
EgressRulepolicy objects in the CubeEgress proxy's Lua dictionary (policy_store), never in the sandbox filesystem or environment. - Injection happens at the edge: The
apply_injectsfunction inaccess_phase.luaadds authentication headers only during the proxy's access phase, just before the request leaves the network. - Validation gates prevent leakage: The
inject_gatesfunction enforces strict validation (scheme, host, size limits) and drops injection attempts that fail safety checks without exposing the secret. - Audit trails remain safe: Secrets are redacted in logs and identified only by SHA-256 fingerprints, preventing accidental credential exposure through observability data.
Frequently Asked Questions
How does CubeSandbox store API keys if not in the sandbox?
API keys are stored inline within the inject field of egress policies that reside in the CubeEgress proxy's shared Lua dictionary (policy_store). This keeps secrets in the proxy's memory space while the sandbox operates in a separate execution environment that never receives the raw values.
What happens if an injection rule fails validation?
The inject_gates function in CubeEgress/lua/access_phase.lua performs safety checks on every injection attempt. If validation fails—for example, if the secret exceeds size limits or the host is invalid—the injection is dropped and recorded in the decision log, but the request may still proceed to the destination without credentials rather than exposing the error to the sandbox.
Can sandbox code access the injected headers?
No. The sandbox code cannot read the injected headers because the injection occurs in the ** CubeEgress proxy after the request leaves the sandbox**. The sandbox sees only its own outbound request without the authentication headers; the proxy adds them encrypted on the wire, making them invisible to the sandbox process, its filesystem, and any core dumps or memory dumps.
How are secrets protected in audit logs?
The system replaces secret values with ***REDACTED*** in all audit logs and stores only a short fingerprint (fp-xxxx) calculated from the SHA-256 hash of the secret. This allows operators to track which credentials were used for specific requests without risking credential leakage through log aggregation systems or SIEM platforms.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →