Remote sandbox protocol: allow token injection and per-connection token verification (single static shared token today)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3
- Forks
- 1
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 20
Description
Component
hyperforge.codemode.sandbox (remote sandbox protocol: SandboxRunner.remote, run_sandbox_server)
Summary
The remote sandbox protocol authenticates every connection with a single static shared bearer token, and the token cannot be supplied programmatically. Two halves of the same limitation (verified on hyperforge==1.0.0.post310):
Client — SandboxRunner.remote(socket, callback, debug=False) accepts no token. _run_remotely reads the module-level snapshot settings = SandboxSettings() (instantiated at import time, line 40) and sends it on every run (lines 140/146):
if settings.sandbox_token is None:
raise RuntimeError("SANDBOX_TOKEN is required for remote codemode")
...
await writer.write_message(SandboxMessage.Run(run=request, token=settings.sandbox_token))
Server — run_sandbox_server compares every incoming connection against one static value (lines 387/400):
sandbox_token = settings.sandbox_token
...
if not hmac.compare_digest(msg.token or "", sandbox_token):
raise PermissionError("Invalid sandbox token")
Impact
- No per-principal authorization: there is exactly one credential for all callers and all invocations. The sandbox cannot distinguish principals, so it cannot enforce (or even observe) per-principal authorization — any process that can reach the socket and knows the token can execute arbitrary Python. Embedding applications that complete their own authz before dispatching to the sandbox cannot bind the sandbox execution to that decision.
- No rotation or revocation: the token is environment-only and snapshotted at import on both sides; changing it requires restarting both processes. Short-lived, scoped, revocable per-connection credentials are impossible to construct.
- Programmatic injection: callers managing secrets via a vault/secret manager (rather than process env) have no supported path to supply the token at all.
Proposal (backward compatible)
- Client:
SandboxRunner.remote(socket, callback, *, token: str | Callable[[], str] | None = None, debug=False)—Nonekeeps today's behavior (read from settings). This also removes the import-time-snapshot fragility for callers that configure the environment late. - Server:
run_sandbox_server(*, token_verifier: Callable[[str], Awaitable[bool]] | None = None)—Nonekeeps the constant-compare default. A verifier hook lets deployments issue and validate short-lived, scoped tokens per connection while the default single-token mode stays intact.
Acceptance criteria
- A token can be supplied programmatically on the client without touching the environment; omitted parameters reproduce current behavior exactly.
- A server can verify connection tokens through a hook (e.g. signed short-lived tokens), with the default static-compare path unchanged.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in hyperforge.codemode.sandbox, reading SandboxRunner.remote, _run_remotely, and run_sandbox_server around the referenced token handling. Trace the existing remote client/server message flow and inspect available tests for sandbox connections. Done means programmatic client tokens and an optional server verifier work while omitted parameters preserve the static-token behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authentication, backend, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100