How the Credential Vault Security Proxy Handles API Key Injection in CubeSandbox

CubeSandbox uses an OpenResty-based L7 proxy called CubeEgress to inject API keys into outbound HTTP requests after they leave the sandbox process, ensuring secrets never appear inside the sandbox environment.

TencentCloud/CubeSandbox implements a credential vault security proxy that prevents API key exposure by injecting secrets at the network layer. This architecture ensures that sensitive tokens never reside in sandbox memory or code, addressing the primary security concern of credential leakage in multi-tenant environments.

Architecture of the CubeEgress Proxy

CubeSandbox routes all outbound traffic through CubeEgress, an OpenResty-based L7 security proxy that acts as the credential vault gatekeeper. When a sandbox initiates an HTTP/HTTPS request, CubeVS forwards the traffic to CubeEgress before it reaches external services. The proxy evaluates the request against configured egress rules and performs credential injection only after the request has exited the sandbox's process namespace.

The Five-Stage Injection Process

The credential vault security proxy handles API key injection through a strictly enforced pipeline that keeps secrets isolated from sandbox runtime.

Policy Definition with Inject Actions

Users define credential injection through an Inject action within an egress rule. The Inject struct, defined in sdk/go/policy.go (lines 27-33), specifies:

  • Header: The HTTP header name (e.g., Authorization)
  • Secret: The raw API key or token value
  • Format: An optional template string (defaults to ${SECRET} if omitted)

Server-Side SNI/Host Matching

Before any injection occurs, CubeEgress validates that the request's SNI/Host matches the rule's Match conditions. This server-side enforcement ensures that credentials are only injected into requests destined for legitimate endpoints, preventing leakage to unintended hosts.

Template Rendering Inside the Proxy

The proxy invokes Inject.Render() to substitute the ${SECRET} placeholder with the actual secret value. This rendering occurs entirely within the proxy process memory, not inside the sandbox. The method implementation in sdk/go/policy.go (lines 27-42) handles the template substitution securely.

Header Injection Outside the Sandbox

After successful matching and rendering, CubeEgress adds the rendered header to the outbound request. Because this step occurs after the request has traversed the sandbox's network namespace boundary, the sandbox code never observes the raw secret value.

Security Guarantees and Log Redaction

The proxy maintains several security controls:

  • Secrets reside only in proxy memory or host-controlled configuration files
  • Failed matches abort injection; requests forward without credentials rather than with partial or incorrect secrets
  • CubeMaster logs display redacted values (***REDACTED***) to prevent accidental credential exposure in audit trails

Credential Delivery Modes

CubeSandbox supports two delivery modes for API keys, selectable via the credentialMode state in web/src/components/agents/AgentSettingsDialog.tsx:

  • egress: The proxy injects credentials (default credential vault mode). This is the secure default that keeps secrets out of the sandbox.
  • env: Credentials pass via environment variables accessible to the sandbox process. This mode is less secure because sandbox code can read the values.

Implementation Examples

Defining Egress Rules with the Go SDK

Create a policy that instructs CubeEgress to inject an Authorization header for OpenAI API requests:

import "github.com/TencentCloud/CubeSandbox/sdk/go"

rule := cubesandbox.Rule{
    Name: "OpenAI API",
    Match: cubesandbox.Match{
        Host:   "api.openai.com",
        Scheme: "https",
    },
    Action: cubesandbox.Action{
        Allow: true,
        Inject: []cubesandbox.Inject{
            {
                Header: "Authorization",
                Secret: "sk-XXXXXXXXXXXXXXXXXXXX",
                // Format: "Bearer ${SECRET}", // optional
            },
        },
    },
}

The marshaled JSON policy is sent to the CubeMaster control plane; the sandbox never receives the Secret value.

Python SDK Equivalent

from cubesandbox import Policy, Match, Action, Inject, Rule

rule = Rule(
    name="OpenAI API",
    match=Match(host="api.openai.com", scheme="https"),
    action=Action(
        allow=True,
        inject=[
            Inject(header="Authorization",
                   secret="sk-XXXXXXXXXXXXXXXXXXXX",
                   format="Bearer ${SECRET}")
        ]
    ),
)
policy = Policy(rules=[rule])
client.update_network_policy(policy)

Sandbox Code Without Credentials

Inside the sandbox, requests require no authentication headers:

import requests

# CubeEgress injects the Authorization header automatically

resp = requests.get("https://api.openai.com/v1/models")
print(resp.json())

Resulting HTTP Request

The upstream service receives:

GET /v1/models HTTP/1.1
Host: api.openai.com
Authorization: Bearer sk-XXXXXXXXXXXXXXXXXXXX
...

Key Source Files

The credential vault implementation spans these components:

Summary

  • CubeSandbox uses CubeEgress, an OpenResty-based L7 proxy, as its credential vault security proxy.
  • API key injection occurs after requests leave the sandbox namespace, ensuring secrets never appear in sandbox memory or logs.
  • The Inject action in sdk/go/policy.go defines header injection rules with optional ${SECRET} templating.
  • Server-side SNI/Host matching prevents credential leakage to unintended destinations.
  • The egress delivery mode maintains security by keeping secrets in the proxy layer, while env mode exposes them to the sandbox process.
  • Failed injections abort credential attachment rather than transmitting partial secrets.

Frequently Asked Questions

How does the credential vault security proxy prevent API key theft from sandbox logs?

The proxy performs injection outside the sandbox process namespace, so the secret value never enters the sandbox's memory space or standard output. Additionally, CubeMaster logs redact secret values as ***REDACTED***, ensuring that even proxy-level audit trails do not expose the raw credentials.

What happens if the egress rule match fails during an outbound request?

If the request's SNI/Host does not match the rule's Match conditions, the injection is aborted. The proxy may still forward the request to the destination, but it will not attach the API key. This fail-safe prevents credential leakage to untrusted endpoints.

Can sandbox code access the raw API key when using the egress credential mode?

No. When configured with credentialMode: egress (the default), the secret is stored only in CubeEgress configuration and memory. The Render method in sdk/go/policy.go executes within the proxy process, substituting ${SECRET} and injecting the header after the request has exited the sandbox's network namespace.

Where is the Inject struct defined in the CubeSandbox source code?

The Inject struct and its Render method are defined in sdk/go/policy.go at lines 27-42. This file also contains the Rule, Match, and Action structures that compose the egress policy schema sent to the CubeMaster control plane.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →