Skip to content

Require a bearer token on the sandbox API (VULN-3072) - #110

Merged
earakely-scale merged 1 commit into
mainfrom
edgararakelyan/vuln-3072-sandbox-auth-token
Oct 28, 2026
Merged

earakely-scale merged 1 commit into
mainfrom
edgararakelyan/vuln-3072-sandbox-auth-token

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes VULN-3072. Follows up #99, which only made the documented port publishing loopback-only.

What

The sandbox API on :1984 runs any MCP tool, including code execution, with the operator's API keys, and had no auth. Loopback publishing still leaves it reachable from other containers, from browser pages via DNS rebinding, and from any non-default deployment.

  • Sandbox (main.py, new auth.py): every endpoint except / and /health requires Authorization: Bearer $SANDBOX_AUTH_TOKEN (constant-time compare, 401 otherwise). The dependency is attached app-wide, so endpoints added later are covered too. The service refuses to start without the token.
  • Callers: the harness (/call-tool, /list-tools, /reset-state), run_eval.py (pre-flight /enabled-servers) and test_servers.py send the token from the environment or the repo .env. run_eval.py now fails with a clear message on 401; before, it printed None/None online and passed.
  • Setup: make run-docker and run_all.sh add a random token to .env if it's missing (openssl rand -hex 32, with a Python fallback). env.template and both READMEs document it.
  • CI: new tests/test_auth.py. The workflow now installs fastapi and httpx and also runs when auth.py or main.py change.

Compatibility

  • Breaking for direct docker run: the sandbox won't start without SANDBOX_AUTH_TOKEN. make run-docker and run_all.sh handle this automatically.
  • Old sandboxes keep working: a harness with the token works against the current 1.2.7 image, which ignores the header.
  • Needs an image release: the server-side check only reaches prebuilt-image users after a new image is pushed (e.g. 1.2.8). The docs still point at 1.2.7, so bump them in the release PR.
  • Still open, unchanged: /docs and /openapi.json (the FastAPI built-ins) expose only the API schema.

Testing

  • pytest tests/: 20 passed, 18 of them new. The wiring test fails against the old main.py. tsc --noEmit passes for the harness.
  • Live sandbox: published 1.2.7 with this branch's main.py/auth.py added and re-synced to main's uv.lock (fastapi 0.136.3, starlette 1.0.1, mcp 1.28.1), default servers:
    • Without the token it exits at startup with the error.
    • /list-tools, /call-tool, /enabled-servers, /cache-stats, /cache-clear return 401 with no token or a wrong one, and 200 with the right one. / and /health stay 200.
    • An unauthenticated mcp-server-code-runner_run-code call that writes a file returns 401, and the file is not created. With the token, the call runs.
  • No regression vs the unmodified 1.2.7 image: both show 112 tools and 13/20 servers online. test_servers.py gives 12/36 on both with an identical failure set (missing API keys, plus 7 servers that don't start in this arm64 Docker setup on either image). Without the token it's 0/36.
  • Harness, end to end (README smoke task, offline fake LLM):
    • With the token, /v2/mcp_eval/run_agent reads /data/Barber Shop.csv through the sandbox.
    • Without the token it fails fast with Failed to fetch tools from sandbox: Unauthorized.
    • With the token against the old image, it still works.
  • run_all.sh from a .env with no token: it generates the token, then the sandbox, harness, test_servers.py and run_eval.py on a 1-task CSV all complete (1/1 succeeded).
  • Token generation: the make sandbox-token edge cases (no trailing newline, the template's empty SANDBOX_AUTH_TOKEN= line, no .env) all yield a 64-char token. Docker --env-file, Node dotenv, python-dotenv and test_servers.py all read the same value.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

Adds a required shared bearer token to the sandbox API and updates its callers.

  • Sandbox tool routes now require a shared bearer token.
  • Harness and evaluation callers send the sandbox token.
  • Local setup creates and documents the sandbox token.

Acknowledged by earakely-scale: direct Docker starts now require the token; prebuilt-image protection needs a later image release; /docs and /openapi.json remain public.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Setup["Setup writes SANDBOX_AUTH_TOKEN"] --> Sandbox["Sandbox loads token"]
  Setup --> Callers["Harness and Python callers load token"]
  Callers --> Request["Sandbox request"]
  Request --> Check{"Public probe?"}
  Check -- Yes --> Probe["Return health response"]
  Check -- No --> Auth{"Bearer token matches?"}
  Auth -- No --> Reject["Return 401"]
  Auth -- Yes --> Route["Run API route"]
Loading

Reviews (1) · Last reviewed commit: "Require a bearer token on the sandbox AP..." · Reviewed by Greptile

The agent-environment API runs any MCP tool (including code execution) with
the operator's API keys and had no authentication. Loopback-only port
publishing (#99) narrowed exposure but left the API open to other containers,
DNS-rebinding pages and non-default deployments.

- main.py / new auth.py: every endpoint except `/` and `/health` requires
  `Authorization: Bearer $SANDBOX_AUTH_TOKEN` (constant-time compare, 401
  otherwise); the service refuses to start without the token.
- Harness, run_eval.py and test_servers.py send the token (env or repo .env).
  run_eval's pre-flight check now fails clearly on 401 instead of passing with
  None counts.
- `make run-docker` and run_all.sh generate a random token in .env if missing;
  env.template and READMEs document it.
- Tests: tests/test_auth.py; CI installs fastapi/httpx and also runs on
  auth.py/main.py changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 661631d into main Oct 28, 2026
4 checks passed
@earakely-scale
earakely-scale deleted the edgararakelyan/vuln-3072-sandbox-auth-token branch October 28, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant