Skip to main content
E2B sandboxes provide multiple layers of security: authenticated access to the sandbox controller, fine-grained network controls, and rate limits to protect your infrastructure.

Secured access

Secure access authenticates communication between SDK and sandbox controller. Sandbox controller runs in sandbox itself and exposes APIs for work with file system, run commands, and generally control the sandbox via our SDK. Without secure access, anyone with a sandbox ID can access the controller APIs and control the sandbox from inside.
SDKs version v2.0.0 and above are using secure access by default when creating sandbox. This may not be compatible with older custom templates and you may need to rebuild them.

Migration path

When using custom templates created before envd v0.2.0, you need to rebuild the templates to enable secure access. Temporarily, you can disable secure access by setting secure to false during sandbox creation, but this is not recommended for production use because it increases security risks. You can check the template envd version using the e2b template list command or by viewing the templates list on the dashboard.

Supported versions

All sandboxes based on templates with envd version at least v0.2.0 already support secure access without any additional changes. The secure access flag was introduced in 1.5.0 for JavaScript and Python SDKs to be used optionally. Starting with SDK version v2.0.0, sandboxes are created with secure access enabled by default.

Access sandbox API directly

In some cases, you might want to access sandbox controller APIs directly through its URL, such as when you are not using SDKs. When secure access is enabled, you must provide an authentication token that was returned during sandbox creation. Each call to the sandbox controller must include an additional header X-Access-Token with the access token value returned during sandbox creation. For sandbox upload and download URLs, you need to generate pre-signed URLs. We are advising to use SDK for generating presigned URLs.

Disable secure access

Disabling secured access is discouraged because it creates security vulnerabilities.
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create({ secure: false }) // Explicitly disable

Internet access

Every sandbox has access to the internet and can be reached by a public URL.

Controlling internet access

You can control whether a sandbox has access to the internet by using the allowInternetAccess parameter when creating a sandbox. By default, internet access is enabled (true), but you can disable it for security-sensitive workloads.
import { Sandbox } from '@e2b/code-interpreter'

// Create sandbox with internet access enabled (default)
const sandbox = await Sandbox.create({ allowInternetAccess: true })

// Create sandbox without internet access
const isolatedSandbox = await Sandbox.create({ allowInternetAccess: false })
When internet access is disabled, the sandbox cannot make outbound network connections, which provides an additional layer of security for sensitive code execution.
Setting allowInternetAccess to false is equivalent to setting network.denyOut to ['0.0.0.0/0'] (denying all traffic).

Fine-grained network control

For more granular control over network access, you can use the network configuration option to specify allow and deny lists for outbound traffic.

Allow and deny lists

You can specify IP addresses, CIDR blocks, or domain names that the sandbox is allowed to use:
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Deny all traffic except specific IPs
const sandbox = await Sandbox.create({
  network: {
    denyOut: [ALL_TRAFFIC],
    allowOut: ['1.1.1.1', '8.8.8.0/24']
  }
})

// Deny specific IPs only
const restrictedSandbox = await Sandbox.create({
  network: {
    denyOut: ['8.8.8.8']
  }
})

Domain-based filtering

You can allow traffic to specific domains by specifying hostnames in allow out. When using domain-based filtering, you must include ALL_TRAFFIC in deny out to block all other traffic. Domains are not supported in the deny out list.
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Allow only traffic to google.com
const sandbox = await Sandbox.create({
  network: {
    allowOut: ['google.com'],
    denyOut: [ALL_TRAFFIC]
  }
})
When any domain is used, the default nameserver 8.8.8.8 is automatically allowed to ensure proper DNS resolution.
You can also use wildcards to allow all subdomains of a domain:
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Allow traffic to any subdomain of mydomain.com
const sandbox = await Sandbox.create({
  network: {
    allowOut: ['*.mydomain.com'],
    denyOut: [ALL_TRAFFIC]
  }
})
You can combine domain names with IP addresses and CIDR blocks:
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Allow traffic to specific domains and IPs
const sandbox = await Sandbox.create({
  network: {
    allowOut: ['api.example.com', '*.github.com', '8.8.8.8'],
    denyOut: [ALL_TRAFFIC]
  }
})
Domain-based filtering only works for HTTP traffic on port 80 (via Host header inspection) and TLS traffic on port 443 (via SNI inspection). Traffic on other ports uses CIDR-based filtering only. UDP-based protocols like QUIC/HTTP3 are not supported for domain filtering.

Priority rules

When both allow out and deny out are specified, allow rules always take precedence over deny rules. This means if an IP address is in both lists, it will be allowed.
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Even though ALL_TRAFFIC is denied, 1.1.1.1 and 8.8.8.8 are explicitly allowed
const sandbox = await Sandbox.create({
  network: {
    denyOut: [ALL_TRAFFIC],
    allowOut: ['1.1.1.1', '8.8.8.8']
  }
})

ALL_TRAFFIC helper

The ALL_TRAFFIC constant represents the CIDR range 0.0.0.0/0, which matches all IP addresses. Use it to easily deny or allow all network traffic:
import { Sandbox, ALL_TRAFFIC } from '@e2b/code-interpreter'

// Deny all outbound traffic
const sandbox = await Sandbox.create({
  network: {
    denyOut: [ALL_TRAFFIC]
  }
})

Sandbox public URL

Every sandbox has a public URL that can be used to access running services inside the sandbox.
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

// You need to always pass a port number to get the host
const host = sandbox.getHost(3000)
console.log(`https://${host}`)
The code above will print something like this:
https://3000-i62mff4ahtrdfdkyn2esc.e2b.app
The first leftmost part of the host is the port number we passed to the method.

Restricting public access to sandbox URLs

By default, sandbox URLs are publicly accessible. You can restrict access to require authentication using the allowPublicTraffic option:
import { Sandbox } from '@e2b/code-interpreter'

// Create sandbox with restricted public access
const sandbox = await Sandbox.create({
  network: {
    allowPublicTraffic: false
  }
})

// The sandbox has a traffic access token
console.log(sandbox.trafficAccessToken)

// Start a server inside the sandbox
await sandbox.commands.run('python -m http.server 8080', { background: true })

const host = sandbox.getHost(8080)
const url = `https://${host}`

// Request without token will fail with 403
const response1 = await fetch(url)
console.log(response1.status) // 403

// Request with token will succeed
const response2 = await fetch(url, {
  headers: {
    'e2b-traffic-access-token': sandbox.trafficAccessToken
  }
})
console.log(response2.status) // 200
When allowPublicTraffic is set to false, all requests to the sandbox’s public URLs must include the e2b-traffic-access-token header with the value from sandbox.trafficAccessToken.

Connecting to a server running inside the sandbox

You can start a server inside the sandbox and connect to it using the public URL approach described above. In this example we will start a simple HTTP server that listens on port 3000 and responds with the content of the directory where the server is started.
import { Sandbox } from '@e2b/code-interpreter'

const sandbox = await Sandbox.create()

// Start a simple HTTP server inside the sandbox.
const process = await sandbox.commands.run('python -m http.server 3000', { background: true })
const host = sandbox.getHost(3000)
const url = `https://${host}`
console.log('Server started at:', url)

// Fetch data from the server inside the sandbox.
const response = await fetch(url);
const data = await response.text();
console.log('Response from server inside sandbox:', data);

// Kill the server process inside the sandbox.
await process.kill()

Masking request host headers

You can customize the Host header that gets sent to services running inside the sandbox using the maskRequestHost option. This is useful when your application expects a specific host format.
import { Sandbox } from '@e2b/code-interpreter'

// Create sandbox with custom host masking
const sandbox = await Sandbox.create({
  network: {
    maskRequestHost: 'localhost:${PORT}'
  }
})

// The ${PORT} variable will be replaced with the actual port number
// Requests to the sandbox will have Host header set to for example: localhost:8080
The ${PORT} variable in the mask will be automatically replaced with the actual port number of the requested service.

Rate limits

This section describes API and sandbox rate limits of the E2B platform. Here’s a limits breakdown table based on the plan:
PlanHobbyProEnterprise
Sandbox lifecycle & management API20,000 / 30s20,000 / 30sCustom
Sandbox operations40,000 / 60s per IP40,000 / 60s per IPCustom
Concurrent sandboxes20100 - 1,100*Custom
Sandbox creation rate1 / sec5 / secCustom
Egress connections per sandbox2,5002,500Custom
*Pro plan default is 100 concurrent sandboxes. Higher concurrency of up to 1,100 is available as a separate purchasable add-on.

Sandbox lifecycle and management API

20,000 requests per 30 seconds This rate limit applies to lifecycle and management operations such as sandbox create, kill, update, list, and other.

Sandbox operations and requests to sandboxes

40,000 requests per 60 seconds This rate limits applies to operations to/within running sandboxes such as running code, listing files, running commands, etc. This also includes requests made to custom ports in the sandbox.
This limit is enforced globally across all sandbox operations from a single IP address.

Concurrent sandboxes

Number of concurrent sandboxes differs based on the pricing tier.

Hobby tier

Up to 20 concurrent sandboxes

Pro tier

Starts at 100 concurrent sandboxes
Can go up to 1,100 with additional add-ons available for purchase.

Enterprise tier

Custom limit - 1,100+ concurrent sandboxes

Sandbox creation rate

This limit controls how quickly you can create new sandboxes.

Hobby tier

1 sandbox per second

Pro tier

5 sandboxes per second

Enterprise tier

Custom limit - 5+ sandboxes per second

Egress connections

2,500 connections per sandbox This limit controls the maximum number of outbound (egress) network connections that can be established from a single sandbox.

Reaching limits

When you reach the limits of your plan, subsequent requests/function calls will be effectively dropped and return the following:
  • the 429 Too Many Requests HTTP status code (when calling API/sandbox ports directly)
  • RateLimitError in the JS/TS SDK
  • RateLimitException in the Python SDK
For example, if you’re on the Pro tier (without any concurrency add-ons), you can create up to 100 sandboxes running concurrently. If the 100 sandboxes are still running, requests for creating new sandboxes from the SDKs (Sandbox.create() in JS/TS or Sandbox.create() in Python) will fail and return RateLimitError or RateLimitException respectively. Once the number of running sandboxes drops below 100, or you purchase a concurrency add-on, you’ll be able to create new sandboxes again.

Increasing and avoiding rate limits

You can avoid rate limits by upgrading your plan or contacting our sales team to discuss your specific requirements and we can provide tailored limits to meet your needs at enterprise@e2b.dev.