E2B
Run Claude Code in an E2B sandbox with secrets injected via proxy
Overview
This example creates an E2B sandbox with Claude Code, using Oshu Vault to securely inject your Anthropic API key. The sandbox only sees a sealed token — the real key never leaves the proxy.
Prerequisites
- E2B account and
E2B_API_KEYset - Oshu Vault instance running
SECRETS_PROXY_API_KEY— your proxy management API keyANTHROPIC_API_KEY— your real Anthropic key
Install Dependencies
npm install @e2b/code-interpreter @oshu/vault-sdkBuild the Template
E2B uses custom sandbox templates defined programmatically. Create a template definition:
// e2b-template.ts
import { Template } from "e2b";
const PROXY_BASE_URL = process.env.PROXY_BASE_URL ?? "https://pv.oshu.dev";
export const template = Template()
.fromDockerfile(
`FROM node:22-slim
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL ${PROXY_BASE_URL}/v1/ca.pem \\
-o /usr/local/share/ca-certificates/proxy-ca.crt \\
&& update-ca-certificates
# Wrap the node binary so it trusts the system CA store
RUN mv /usr/local/bin/node /usr/local/bin/node.real \\
&& echo '#!/bin/sh' > /usr/local/bin/node \\
&& echo 'exec /usr/local/bin/node.real --use-openssl-ca "$@"' >> /usr/local/bin/node \\
&& chmod +x /usr/local/bin/node
RUN npm install -g @anthropic-ai/claude-code`,
);Then build and push:
// build-e2b-template.ts
import { Template, defaultBuildLogger } from "e2b";
import { template } from "./e2b-template.js";
const buildInfo = await Template.build(template, {
alias: "oshu-vault-claude",
cpuCount: 2,
memoryMB: 2048,
onBuildLogs: defaultBuildLogger(),
});
console.log(`Template ready: ${buildInfo.alias}`);npx tsx build-e2b-template.tsFull Example
import { Sandbox } from "@e2b/code-interpreter";
import { SecretsProxyClient } from "@oshu/vault-sdk";
// --- Config ---
const PROXY_BASE_URL = "https://pv.oshu.dev";
const PROXY_HOST = "pv.oshu.dev";
const API_KEY = process.env.SECRETS_PROXY_API_KEY!;
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY!;
// 1. Create an Oshu Vault session
const client = new SecretsProxyClient({
baseUrl: PROXY_BASE_URL,
apiKey: API_KEY,
});
const session = await client.createSession({
secrets: { ANTHROPIC_API_KEY },
});
const proxyUrl = `https://${session.session_id}:${session.token}@${PROXY_HOST}`;
// 2. Create sandbox from template — CA cert + Claude Code already baked in
const sandbox = await Sandbox.create("oshu-vault-claude", {
envs: {
ANTHROPIC_API_KEY: session.sealed_secrets["ANTHROPIC_API_KEY"],
HTTP_PROXY: proxyUrl,
HTTPS_PROXY: proxyUrl,
},
});
try {
// 3. Run claude -p — no special flags, just works
const result = await sandbox.commands.run(
`claude -p "Write a hello world program in Python"`,
{ timeoutMs: 120_000 },
);
console.log(result.stdout);
} finally {
await client.deleteSession(session.session_id);
await sandbox.kill();
}Custom Proxy URL
If your Oshu Vault instance is at a different URL, pass it as a build arg:
e2b template build -n oshu-vault-claude --build-arg PROXY_BASE_URL=https://your-proxy.example.comWhat's Happening
Template built with Claude Code + trusted CA
The template installs the proxy CA certificate into the system trust store and wraps the node binary with --use-openssl-ca so Node.js trusts it too. Claude Code is pre-installed. E2B caches this template.
Session created
The SDK sends your real ANTHROPIC_API_KEY to the proxy and gets back a sealed token like SEALED_7f3a9b2c....
Sandbox configured
The sandbox receives ANTHROPIC_API_KEY=SEALED_7f3a9b2c... and proxy env vars. No certificate setup needed at runtime.
Secret injected on-the-fly
When Claude Code calls the Anthropic API with x-api-key: SEALED_7f3a9b2c..., the proxy intercepts the request and replaces the sealed token with your real API key before forwarding.
The sandbox never sees your real API key. Even if the AI-generated code tries to log or exfiltrate ANTHROPIC_API_KEY, it only gets the useless sealed token.