Skip to content

security: keep OpenWorker's own sidecar token out of the shell environment - #295

Open
Mr-Neutr0n wants to merge 1 commit into
andrewyng:mainfrom
Mr-Neutr0n:security/shell-does-not-inherit-sidecar-token
Open

security: keep OpenWorker's own sidecar token out of the shell environment#295
Mr-Neutr0n wants to merge 1 commit into
andrewyng:mainfrom
Mr-Neutr0n:security/shell-does-not-inherit-sidecar-token

Conversation

@Mr-Neutr0n

Copy link
Copy Markdown
Contributor

LocalExecutor builds the shell environment as {**os.environ, ...}, so every command run_shell executes inherits the whole server process environment — including COWORKER_API_TOKEN.

Measured

With the token and a provider key set on the server process:

run_shell(`echo "token=$COWORKER_API_TOKEN key=$OPENAI_API_KEY"`)
-> token=SIDECAR-SECRET-abc123 key=sk-user-key-xyz

After this change:

-> token=[] key=sk-user-key-xyz

Why the token specifically

COWORKER_API_TOKEN authenticates every request to the local API (server/app.py::require_sidecar_token). It's the only thing standing between a process on this machine and the agent's shell and file tools — and it's what stops a fetch of http://127.0.0.1:<port>/ from driving the sidecar (relevant to #292).

The whole point of run_shell is executing project code: build scripts, test suites, npm lifecycle hooks. Any of those can read the token out of its environment and then drive the local API directly. echo $COWORKER_API_TOKEN is the demo; env | curl -d @- is the attack.

The repo already draws this line elsewhere. verify.scrubbed_env() exists so "target-repo code never sees our credentials" (DOMAIN_MODEL §2) and is applied to agent CLI sandboxes and local test runs. run_shell was the gap.

Scope

Deliberately narrow: only OpenWorker's own credential is withheld. The user's provider keys stay in the environment so builds, gh, and everything else keep working.

Whether provider keys should also be scrubbed from run_shell is a real question — the agent has connector tools for GitHub and friends, so the shell arguably doesn't need those either — but that's a UX decision with real breakage risk, not a bug fix. Happy to follow up if you want it.

Tests

tests/test_shell_env_isolation.py — the token is absent from both $VAR expansion and a full env listing (echo isn't the only way to read it), the user's own keys survive, PATH survives, and the explicit env= constructor argument is unchanged.

Note these tests import the new helper, so they can't run against the unpatched tree — the before/after above is the direct evidence instead.

Full suite: 921 passed. The 14 failures reproduce on a clean checkout — test_fake_slack.py (dead-port timeouts, #252) and test_bedrock_provider.py (missing bedrock extra, #284/#285).


Reviewed and tested locally; drafted with AI assistance.

…nment

LocalExecutor built the shell env as {**os.environ, ...}, so every command
run_shell executes inherited the whole server process environment - including
COWORKER_API_TOKEN.

Measured, with the token and a provider key set on the server process:

    run_shell(`echo "token=$COWORKER_API_TOKEN key=$OPENAI_API_KEY"`)
    -> token=SIDECAR-SECRET-abc123 key=sk-user-key-xyz

That token authenticates every request to the local API
(server/app.py::require_sidecar_token). It is the only thing standing between a
process on this machine and the agent's shell and file tools, and the whole
point of run_shell is executing project code - build scripts, test suites, npm
lifecycle hooks. Any of those could read it back out and then drive the API
directly.

The repo already draws this line elsewhere: verify.scrubbed_env() exists so
"target-repo code never sees our credentials" (DOMAIN_MODEL §2) and is applied
to agent CLI sandboxes and local test runs. run_shell was the gap.

Scoped narrowly on purpose. Only OpenWorker's own credential is withheld; the
user's provider keys stay in the environment so builds, gh, and everything else
keep working. Widening this to provider keys is a real question but a UX
decision, not a bug fix, so it is left alone here.

Tests: tests/test_shell_env_isolation.py - the token is absent from both $VAR
expansion and a full `env` listing, the user's own keys survive, PATH survives,
and the explicit env= constructor argument is unchanged.
@Mr-Neutr0n
Mr-Neutr0n force-pushed the security/shell-does-not-inherit-sidecar-token branch from 7eddcf6 to 1d7860f Compare July 28, 2026 20:52
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