---
title: Handle outbound traffic
description: Intercept and handle outbound HTTP from sandboxes using Workers.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/sandbox/llms.txt  
> Use this file to discover all available pages before exploring further.

[Skip to content](#%5Ftop) 

# Handle outbound traffic

Outbound handlers let you intercept and modify HTTP traffic from a sandbox with trusted code.

Use them to:

* Allow or deny specific origin destinations
* Safely inject authorization headers or tokens
* Transparently reroute traffic
* Add custom policy on outbound traffic (such as denying specific HTTP requests)
* [Connect to Workers bindings](https://developers.cloudflare.com/sandbox/guides/workers-connections/) like KV, R2, and Durable Objects

## Block outbound traffic

Use `enableInternet = false` to block public internet access by default:

* [  JavaScript ](#tab-panel-8119)
* [  TypeScript ](#tab-panel-8120)

JavaScript

```

import { Sandbox } from "@cloudflare/sandbox";


export class MySandbox extends Sandbox {

  enableInternet = false;

}


```

TypeScript

```

import { Sandbox } from "@cloudflare/sandbox";


export class MySandbox extends Sandbox {

  enableInternet = false;

}


```

When `enableInternet` is `false`, only traffic you explicitly allow later on this page through `allowedHosts` or outbound handlers can leave the sandbox. Only ports `80`, `443`, and DNS are available, and DNS queries use Cloudflare's DNS servers.

Note

`enableInternet` takes effect when the sandbox starts. Changes to `outbound` handlers and related outbound policies can affect a live-running sandbox without restarting it.

## Block or allow traffic by host

You can filter outbound traffic with the `allowedHosts` and `deniedHosts` properties on the Sandbox class.

Note

Export `ContainerProxy` from your Worker entrypoint for outbound interception to work.

When `allowedHosts` is set, it becomes a deny-by-default allowlist. Any host or IP not in the list is denied, and only matching destinations can reach `outbound` or `outboundByHost` handlers.

`allowedHosts` and `deniedHosts` also support simple glob patterns where `*` matches any sequence of characters.

By default, a Sandbox allows internet access, and you can set `deniedHosts` to disallow specific hosts or IPs:

* [  JavaScript ](#tab-panel-8121)
* [  TypeScript ](#tab-panel-8122)

JavaScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {

  deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];

}


```

TypeScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {

  deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];

}


```

You can also disable internet access by default, but allow specific hosts and IPs:

* [  JavaScript ](#tab-panel-8123)
* [  TypeScript ](#tab-panel-8124)

JavaScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {

  // default internet access to off unless overridden by 'allowedHosts' or outbound proxy

  enableInternet = false;


  // overrides enableInternet = false

  allowedHosts = ["allowed.com"];

}


```

TypeScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {

  // default internet access to off unless overridden by 'allowedHosts' or outbound proxy

  enableInternet = false;


  // overrides enableInternet = false

  allowedHosts = ["allowed.com"];

}


```

## Define outbound handlers

Outbound handlers are programmable egress proxies that run on the same machine as the sandbox. They have access to all Workers bindings.

Use `outbound` to intercept all outbound HTTP and HTTPS traffic:

* [  JavaScript ](#tab-panel-8127)
* [  TypeScript ](#tab-panel-8128)

JavaScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outbound = async (request, env, ctx) => {

  if (request.method !== "GET") {

    console.log(`Blocked ${request.method} to ${request.url}`);

    return new Response("Method Not Allowed", { status: 405 });

  }

  return fetch(request);

};


```

TypeScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outbound = async (

  request: Request,

  env: Env,

  ctx: OutboundHandlerContext,

) => {

  if (request.method !== "GET") {

    console.log(`Blocked ${request.method} to ${request.url}`);

    return new Response("Method Not Allowed", { status: 405 });

  }

  return fetch(request);

};


```

Note

HTTP requests to the outbound handler remain secure because they run on the same machine as the sandbox. You can upgrade requests to HTTPS from the Worker itself to prevent plain-text traffic from reaching the internet.

Use `outboundByHost` to map specific domain names or IP addresses to handler functions:

* [  JavaScript ](#tab-panel-8129)
* [  TypeScript ](#tab-panel-8130)

JavaScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "my.worker": async (request, env, ctx) => {

    // Run arbitrary Workers logic from this hostname

    return await someWorkersFunction(request.body);

  },

};


```

TypeScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "my.worker": async (

    request: Request,

    env: Env,

    ctx: OutboundHandlerContext,

  ) => {

    // Run arbitrary Workers logic from this hostname

    return await someWorkersFunction(request.body);

  },

};


```

Calls to `http://my.worker` from the sandbox invoke the handler, which runs inside the Workers runtime, outside the sandbox.

`deniedHosts` and `allowedHosts` are evaluated before any outbound handler. If you use `allowedHosts`, include the hostname there for either `outbound` or `outboundByHost` to run. `outboundByHost` handlers take precedence over catch-all `outbound` handlers.

## Securely inject credentials

Because outbound handlers run in the Workers runtime — outside the sandbox — they can hold secrets that the sandbox itself never sees. The sandbox makes a plain HTTP request, and the handler attaches the credential before forwarding it to the upstream service.

* [  JavaScript ](#tab-panel-8125)
* [  TypeScript ](#tab-panel-8126)

JavaScript

```

export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "github.com": (request, env, ctx) => {

    const requestWithAuth = new Request(request);

    requestWithAuth.headers.set("x-auth-token", env.SECRET);

    return fetch(requestWithAuth);

  },

};


```

TypeScript

```

export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "github.com": (request: Request, env: Env, ctx: OutboundHandlerContext) => {

    const requestWithAuth = new Request(request);

    requestWithAuth.headers.set("x-auth-token", env.SECRET);

    return fetch(requestWithAuth);

  },

};


```

This is especially useful for agentic workloads where you cannot fully trust the code running inside the sandbox. With this pattern:

* **No token is exposed to the sandbox.** The secret lives in the Worker's environment and is never passed into the sandbox.
* **No token rotation inside the sandbox.** Rotate the secret in your Worker's environment and every request picks it up immediately.
* **Per-host and per-instance rules.** Combine `outboundByHost` with `ctx.containerId` to scope credentials or permissions to a specific sandbox instance.

Here, `ctx.containerId` looks up a per-instance key from KV:

* [  JavaScript ](#tab-panel-8131)
* [  TypeScript ](#tab-panel-8132)

JavaScript

```

export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "my-internal-vcs.dev": async (request, env, ctx) => {

    const authKey = await env.KEYS.get(ctx.containerId);


    const requestWithAuth = new Request(request);

    requestWithAuth.headers.set("x-auth-token", authKey);

    return fetch(requestWithAuth);

  },

};


```

TypeScript

```

export class MySandbox extends Sandbox {}


MySandbox.outboundByHost = {

  "my-internal-vcs.dev": async (

    request: Request,

    env: Env,

    ctx: OutboundHandlerContext,

  ) => {

    const authKey = await env.KEYS.get(ctx.containerId);


    const requestWithAuth = new Request(request);

    requestWithAuth.headers.set("x-auth-token", authKey);

    return fetch(requestWithAuth);

  },

};


```

## HTTPS traffic

Sandboxes intercept HTTPS traffic by default — `interceptHttps` is set to `true` on the Sandbox class.

When HTTPS interception is active, an ephemeral CA file is created at `/etc/cloudflare/certs/cloudflare-containers-ca.crt` once the sandbox starts.

The Sandbox runtime makes a best effort to trust this CA automatically regardless of distro. On startup, it checks common system CA bundle locations across major Linux families and configures common CA environment variables so runtimes like Node.js, `curl`, Python `requests`, and Git trust the certificate automatically.

Note

HTTP communication to the outbound handler is encrypted by the networking stack. For traffic that stays within the Cloudflare Developer Platform, plain HTTP is secure.

## Non-HTTP traffic

Outbound handlers only intercept HTTP and HTTPS traffic. Traffic on ports other than `80` and `443` is never routed through `outbound` or `outboundByHost`.

If you set `enableInternet = false`, that traffic is denied. DNS queries are the one exception, but they only go to Cloudflare's DNS servers. That prevents using arbitrary DNS destinations for data exfiltration.

## Change policies at runtime

Use `outboundHandlers` to define named handlers, then assign them to specific hosts at runtime using `setOutboundByHost()`. You can also apply a handler globally with `setOutboundHandler()`.

You can also manage runtime policy with `setOutboundByHosts()`, `setAllowedHosts()`, `setDeniedHosts()`, `allowHost()`, `denyHost()`, `removeAllowedHost()`, and `removeDeniedHost()`.

This lets a trusted Worker hold credentials without exposing them to an untrusted sandbox:

* [  JavaScript ](#tab-panel-8133)
* [  TypeScript ](#tab-panel-8134)

JavaScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outboundHandlers = {

  authenticatedGithub: async (request, env, ctx) => {

    const githubToken = env.GITHUB_TOKEN;

    return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);

  },

};


```

TypeScript

```

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";

export { ContainerProxy };


export class MySandbox extends Sandbox {}


MySandbox.outboundHandlers = {

  authenticatedGithub: async (

    request: Request,

    env: Env,

    ctx: OutboundHandlerContext,

  ) => {

    const githubToken = env.GITHUB_TOKEN;

    return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);

  },

};


```

Apply handlers to hosts programmatically from your Worker:

* [  JavaScript ](#tab-panel-8135)
* [  TypeScript ](#tab-panel-8136)

JavaScript

```

import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";

export { ContainerProxy };


export default {

  async fetch(request, env) {

    const sandbox = getSandbox(env.Sandbox, "agent-session");


    // Give the sandbox access to github.com during setup

    await sandbox.setOutboundByHost("github.com", "authenticatedGithub");

    await sandbox.exec("node setup.js");


    // Remove access once setup is complete

    await sandbox.removeOutboundByHost("github.com");

  },

};


```

TypeScript

```

import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";

export { ContainerProxy };


export default {

  async fetch(request: Request, env: Env) {

    const sandbox = getSandbox(env.Sandbox, "agent-session");


    // Give the sandbox access to github.com during setup

    await sandbox.setOutboundByHost("github.com", "authenticatedGithub");

    await sandbox.exec("node setup.js");


    // Remove access once setup is complete

    await sandbox.removeOutboundByHost("github.com");

  },

};


```

## Handler precedence

Requests are evaluated in this order:

1. `deniedHosts` is checked first. Matching hosts or IPs are denied immediately.
2. `allowedHosts` is checked next. When it is set, any host or IP not in the list is denied. Matching hosts continue to outbound handlers, or egress to the public internet if no handler is set.
3. Instance-level rules set with `setOutboundByHost()` are checked before class-level `outboundByHost` rules.
4. Per-host handlers always take precedence over catch-all handlers, so `outboundByHost` runs before `outbound`.
5. Instance-level handlers set with `setOutboundHandler()` are checked before the class-level `outbound` handler.
6. If no handler matches, the request can still egress to the public internet when it matched `allowedHosts` or `enableInternet = true`. Otherwise, it is denied.

## Local development

`wrangler dev` supports outbound interception. A sidecar process is spawned inside the sandbox's network namespace. It applies `TPROXY` rules to route matching traffic to the local Workerd instance, mirroring production behavior.

## Related resources

* [Connect to Workers bindings](https://developers.cloudflare.com/sandbox/guides/workers-connections/) — Access KV, R2, Durable Objects, and other bindings from a sandbox
* [Handle outbound traffic (Containers)](https://developers.cloudflare.com/containers/platform-details/outbound-traffic/) — Container SDK API for outbound handlers
* [Sandbox options](https://developers.cloudflare.com/sandbox/configuration/sandbox-options/) — Configure sandbox behavior
* [Environment variables](https://developers.cloudflare.com/sandbox/configuration/environment-variables/) — Configure secrets and environment variables

```json
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/sandbox/","name":"Sandbox SDK"}},{"@type":"ListItem","position":3,"item":{"@id":"/sandbox/guides/","name":"How-to guides"}},{"@type":"ListItem","position":4,"item":{"@id":"/sandbox/guides/outbound-traffic/","name":"Handle outbound traffic"}}]}
```
