Secrets in E2B sandboxes
E2B takes environment variables at creation and per command, so both shapes on the sandboxes overview work without any E2B-side configuration.
Inject at creation
import os
import seekrit
from e2b import Sandbox
secrets = seekrit.Client(token=os.environ["SEEKRIT_TOKEN"]).resolve()
sandbox = Sandbox.create(
envs={
"OPENAI_API_KEY": secrets["OPENAI_API_KEY"],
"TAVILY_API_KEY": secrets["TAVILY_API_KEY"],
},
)
import { Sandbox } from 'e2b';
import { Seekrit } from '@seekrit/sdk';
const secrets = await new Seekrit({ token: process.env.SEEKRIT_TOKEN }).resolve();
const sandbox = await Sandbox.create({
envs: {
OPENAI_API_KEY: secrets.OPENAI_API_KEY,
TAVILY_API_KEY: secrets.TAVILY_API_KEY,
},
});
Named keys, not envs=secrets. The token can see the whole environment and the
sandbox has no business holding all of it — see
Pick names, not the whole environment.
Inject per command
Creation-time variables apply to everything the sandbox runs. If only one step needs a credential, scope it to that step:
sandbox = Sandbox.create()
sandbox.commands.run(
"python fetch_and_summarize.py",
envs={"OPENAI_API_KEY": secrets["OPENAI_API_KEY"]},
)
# This one gets no key at all.
sandbox.commands.run("python render_report.py")
Per-command variables are narrower in time, not in secrecy. E2B says so
plainly: they are "scoped to the command but are not private in the OS." Any
other process in the sandbox can read /proc/<pid>/environ while the command
runs. Use this to keep a key out of unrelated steps, not to hide it from code
running alongside.
Keep the credential outside the sandbox
When the code inside is model output or a coding agent, do not inject at all.
Run seekrit-proxy on the host and give the sandbox
a placeholder plus a base URL:
# seekrit-proxy.toml — on the host, not in the sandbox
listen = "0.0.0.0:8080"
[[route]]
prefix = "/openai"
upstream = "https://api.openai.com"
allow = ["OPENAI_API_KEY"]
methods = ["POST"]
paths = ["/v1/chat/completions", "/v1/embeddings"]
sandbox = Sandbox.create(
envs={
# A placeholder, not a key. Worthless if it leaks.
"OPENAI_API_KEY": "{{seekrit:OPENAI_API_KEY}}",
"OPENAI_BASE_URL": "http://<host>:8080/openai",
},
)
The agent's SDK sends Authorization: Bearer {{seekrit:OPENAI_API_KEY}}; the
proxy swaps in the real value and forwards it. What the sandbox holds is a
string that means nothing anywhere else, and the paths list means the key
cannot be spent on anything but chat completions and embeddings even from inside.
Bind the proxy where the sandbox can reach it, and nowhere else. 0.0.0.0
above is for the sandbox-to-host hop; put it behind a firewall or on a private
network, because anything that can reach the proxy can spend the credential on
the allowed operations. The default 127.0.0.1 is right when the proxy is a
sidecar in the same network namespace.
See also
- Agent sandboxes — the two shapes and when each is right
- Agent proxy — the full proxy configuration
- SDKs —
resolve()in every language