Outbound request header transformation

Updated at:

With network.rules, when the sandbox sends HTTP/HTTPS requests to specified domains, the platform can add or override request headers, or replace credential placeholders in header values. Real credentials never enter the sandbox as environment variables, files, or code.

How it works

When an egress request from the sandbox passes through the node egress proxy, the platform matches network.rules against the target domain and adds or overrides headers, or replaces placeholders in header values, for matched requests.

For HTTP requests, the platform modifies headers directly at the node egress proxy. For HTTPS requests, the platform must decrypt the traffic first, so it performs TLS inspection at the node egress proxy: it dynamically issues a certificate for the target domain using the platform CA and validates the HTTPS certificate presented by the real upstream service. Sandbox clients must trust the platform CA; otherwise HTTPS requests return certificate errors. For template requirements, see Prerequisites.

Prerequisites

  • Prepare real credentials in the control-plane execution environment. The examples in this topic read credentials from the API_TOKEN environment variable; real credentials never enter the sandbox.

  • If code inside the sandbox accesses target domains over HTTPS, the template must include the platform CA:

    • Official templates and supported Debian/Ubuntu custom templates have the platform CA built in, and curl, Python requests, and Node.js work out of the box.

    • Official images must be at least version v0.0.44:

      • fc-e2b-registry.${regionId}.cr.aliyuncs.com/runtime/base:v0.0.44

      • fc-e2b-registry.${regionId}.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.44

    • Custom images must be built after the platform release of 2026-08-15. Earlier images do not receive the platform CA automatically.

Choose a transformation method

Method

Use case

How the sandbox constructs the header

Full header injection

The control plane knows the complete header, for example Authorization: Bearer ....

The sandbox does not need to construct the header at all.

Header value placeholder replacement

A third-party SDK or sandbox code needs to construct the header dynamically, and only sensitive fragments must be hidden.

Sends the header structure with non-sensitive placeholders.

When the same header matches both methods, the platform performs placeholder replacement first and then full header injection; the injected value takes final precedence.

Full header injection

Node.js

import { Sandbox } from "e2b";

const token = process.env.API_TOKEN;
if (!token) throw new Error("API_TOKEN is required");

const sandbox = await Sandbox.create({
  network: {
    allowOut: ["api.example.com"],
    denyOut: ["0.0.0.0/0"],
    rules: {
      "api.example.com": [
        {
          transform: {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          },
        },
      ],
    },
  },
});
console.log(`[create] Sandbox created: ${sandbox.sandboxId}`);

// When code inside the sandbox calls https://api.example.com,
// the platform injects the Authorization header automatically;
// the business code does not need to set this header.

Python

import os

from e2b import Sandbox

token = os.environ["API_TOKEN"]

sandbox = Sandbox.create(
    network={
        "allow_out": ["api.example.com"],
        "deny_out": ["0.0.0.0/0"],
        "rules": {
            "api.example.com": [
                {
                    "transform": {
                        "headers": {"Authorization": f"Bearer {token}"}
                    }
                }
            ]
        },
    },
)
print(f"[create] Sandbox created: {sandbox.sandbox_id}")

Code inside the sandbox calls https://api.example.com as usual without setting Authorization. The target service receives the header injected by the platform.

Header value placeholder replacement

The current E2B SDK does not expose a standalone replacement field. FC Agent Sandbox carries replacement rules in a reserved header key whose value must be a JSON string containing a replacement array:

fc.sandbox.network.header-value-replacements

This key is used only when creating or updating rules. It is never sent to the target service as a real HTTP header.

Node.js

import { Sandbox } from "e2b";

const token = process.env.API_TOKEN;
if (!token) throw new Error("API_TOKEN is required");

const replacements = JSON.stringify([
  { placeholder: "TOKEN_PLACEHOLDER", value: token },
]);

const sandbox = await Sandbox.create({
  network: {
    allowOut: ["api.example.com"],
    denyOut: ["0.0.0.0/0"],
    rules: {
      "api.example.com": [
        {
          transform: {
            headers: {
              "fc.sandbox.network.header-value-replacements": replacements,
            },
          },
        },
      ],
    },
  },
});

Python

import json
import os

from e2b import Sandbox

token = os.environ["API_TOKEN"]
carrier = json.dumps(
    [{"placeholder": "TOKEN_PLACEHOLDER", "value": token}]
)

sandbox = Sandbox.create(
    network={
        "allow_out": ["api.example.com"],
        "deny_out": ["0.0.0.0/0"],
        "rules": {
            "api.example.com": [
                {
                    "transform": {
                        "headers": {
                            "fc.sandbox.network.header-value-replacements": carrier
                        }
                    }
                }
            ]
        },
    },
)

After the configuration is in place, when sandbox code or a third-party SDK sends:

Authorization: Bearer TOKEN_PLACEHOLDER

The target service receives:

Authorization: Bearer real token

Replacement is case-sensitive, and all occurrences within the same header value are replaced. The scan runs only once—the generated output does not trigger another round of replacement—and unmatched placeholders are sent to the target service as-is.

Update rules at runtime

network.rules can be modified without rebuilding the sandbox: call updateNetwork in Node.js, or update_network in Python. PUT /sandboxes/{id}/network is a full replacement, not an incremental update: every update must submit the complete allowOut, denyOut, and rules. Omitting rules, or passing null or {}, clears the existing rules.

If an update fails, the previous rules remain in effect. Network rules are preserved while the sandbox is paused, and network.rules can also be updated while paused; after the sandbox resumes, the latest rules apply.

Node.js

import { Sandbox } from "e2b";

const sandbox = await Sandbox.create({
  network: {
    allowOut: ["api.example.com"],
    denyOut: ["0.0.0.0/0"],
  },
});
console.log(`[create] Sandbox created: ${sandbox.sandboxId}`);

// Add rules later
await sandbox.updateNetwork({
  allowOut: ["api.example.com"],
  denyOut: ["0.0.0.0/0"],
  rules: {
    "api.example.com": [
      {
        transform: {
          headers: {
            Authorization: `Bearer ${process.env.API_TOKEN}`,
          },
        },
      },
    ],
  },
});
console.log("[update] network.rules applied");

// Clear rules
await sandbox.updateNetwork({
  allowOut: ["api.example.com"],
  denyOut: ["0.0.0.0/0"],
});
console.log("[update] network.rules cleared");

Python

import os

from e2b import Sandbox

sandbox = Sandbox.create(
    network={
        "allow_out": ["api.example.com"],
        "deny_out": ["0.0.0.0/0"],
    },
)
print(f"[create] Sandbox created: {sandbox.sandbox_id}")

# Add rules later
sandbox.update_network({
    "allow_out": ["api.example.com"],
    "deny_out": ["0.0.0.0/0"],
    "rules": {
        "api.example.com": [
            {
                "transform": {
                    "headers": {
                        "Authorization": f"Bearer {os.environ['API_TOKEN']}"
                    }
                }
            }
        ]
    },
})
print("[update] network.rules applied")

# Clear rules
sandbox.update_network({
    "allow_out": ["api.example.com"],
    "deny_out": ["0.0.0.0/0"],
})
print("[update] network.rules cleared")

The network.rules returned by getInfo or GET /sandboxes/{id} reflects the currently effective rules. Use it to verify current rule content or as input for subsequent updates. In the response, each replacement rule is re-encoded as a JSON string carried by the reserved header key, and the real value is returned in plaintext. Do not write the response into general logs, tickets, or frontend error reporting.

Security recommendations

  • Read and submit real credentials only from a trusted control plane. Never commit secrets to code repositories.

  • Use a secrets management service, CI secrets, or short-lived, authenticated business credentials.

  • Prefer HTTPS. Once an HTTP request leaves the node egress proxy, it is plaintext, and credentials may leak in transit.

  • Use short-lived, least-privilege credentials that can be revoked per tenant or per session.

  • Configure exact domains only for real targets, and confirm that the target does not echo or log authentication headers.

  • Protect the identity permissions of the create, update, and query APIs, and avoid printing the complete network.rules.

  • Never put a real, usable credential into a placeholder itself.

Limits

In network.rules, each exact domain maps to one rule object, and the rule object carries ordinary headers or replacement rules through transform.headers. The following limits apply:

Item

Limit

Target domains

Up to 10. Exact domains only, matched exactly; subdomains do not match. Wildcards, IPs, CIDR blocks, URLs, ports, and paths are not supported.

Rules per domain

Fixed at 1.

Ordinary headers

Up to 20 per rule. Header name: 1 to 64 bytes. Header value: up to 2,048 bytes.

Total serialized rule size

Up to 64 KiB.

Replacement rules

Up to 16 per domain. Up to 64 per sandbox.

Placeholder

8 to 128 bytes. Only letters, digits, _, ., and - are allowed.

Replacement value

1 to 2,048 bytes.

A placeholder must not be the same as the real value, must not be duplicated, and must not be a substring of another placeholder.

The following header categories cannot be configured or are skipped during replacement: Host, Content-Length, Transfer-Encoding, Connection, Upgrade, proxy authentication headers, x-envoy-*, x-forwarded-*, and other routing or frame control headers. The restricted set may change across platform versions; do not rely on the behavior of these headers on a specific version.

FAQ

Why can't I reach the target even though rules is configured?

rules does not grant network access. Confirm that the target is included in allowOut and that denyOut does not cover the target.

Why is the header transformation not taking effect?

First confirm that the rules are effective through the network.rules returned by getInfo. If the rules are configured correctly but the target service still does not receive the expected header, check the following items one by one:

  • Domain matching: target domains support exact matching only; subdomains do not match, and wildcards, IPs, CIDR blocks, URLs, ports, and paths are not supported.

  • Restricted headers: header categories such as Host and Content-Length cannot be configured or are skipped during replacement.

  • Placeholder constraints: replacement is case-sensitive, and unmatched placeholders are sent to the target service as-is; a placeholder must not be the same as the real value, must not be duplicated, and must not be a substring of another placeholder.

  • Rule clearing: if the most recent update omitted rules, or passed null or {}, the existing rules have been cleared.

Why does HTTP work but HTTPS returns a certificate error?

The platform must decrypt HTTPS to modify headers, so it performs TLS inspection at the node egress proxy and dynamically issues a certificate for the target domain using the platform CA. For details, see How it works. If the sandbox client does not trust the platform CA, check the certificate file, the template version, and the trust store of the corresponding language. The following clients typically require extra trust configuration:

  • Java: import /usr/local/share/ca-certificates/e2b-ca.crt into the JVM cacerts or the application trust store.

  • Firefox or NSS.

  • Applications that read only the OpenSSL CApath.

  • Custom images that are not Debian/Ubuntu-based.

  • Clients that use a private trust store, certificate pinning, or that ignore system environment variables.

    Also confirm the template version; templates that are too old do not have the platform CA injected. For the version requirements of official and custom images, see Prerequisites.