Skip to content

fix(worker): withhold credentials from worker bash and fail closed without a sandbox (AGT-4783) - #840

Merged
unohee merged 1 commit into
mainfrom
fix/agt-4783-worker-credential-boundary
Oct 21, 2026
Merged

unohee merged 1 commit into
mainfrom
fix/agt-4783-worker-credential-boundary

Conversation

@unohee

@unohee unohee commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

Why

On 2026-10-20 a cgf-portal worker ran bash scripts/dev/release.sh --help. The script called gh workflow run with the daemon's GitHub login and shipped an unapproved production deploy (AGT-4783).

A command-name fence cannot see inside a script. Comparing omp, codex and Claude Code: none of their command matchers would have stopped it either. So this PR removes the identity instead of trying to recognise the command. It is the first PR of S6 W1.

What changes

  • New src/adapters/workerEnv.ts. buildBashToolEnv now delegates to it. It builds the worker shell's environment as follows:
    • An allowlist of inherited variables: toolchain, locale, terminal, test-resource budget.
      • Not inherited: tokens, keys, DSNs, SSH_AUTH_SOCK, NODE_OPTIONS, and OPENSWARM_* secrets.
    • A private HOME, so file-based logins under the real HOME are not found: wrangler OAuth, ~/.npmrc, docker.
      • CARGO_HOME, RUSTUP_HOME, UV_CACHE_DIR, UV_PYTHON_INSTALL_DIR, npm_config_cache, PIP_CACHE_DIR and GOCACHE are pointed back at the real directories, so builds are not cold.
    • gh / git / ssh identity removed:
      • an empty GH_CONFIG_DIR;
      • credential.helper reset to none via GIT_CONFIG_COUNT (clears osxkeychain from the system config);
      • GIT_SSH_COMMAND with no identity.
  • Fail closed without a sandbox. workerSandbox: on on a host with neither sandbox-exec nor bwrap now refuses the command. It used to warn once and run unfenced. The opt-out is autonomous.workerSandbox: off, named in the refusal, the boot log, config.example.yaml and the CHANGELOG. The Docker image ships bubblewrap.
  • Unchanged scope. buildWorkerEnv (delegated CLIs, interactive chat) is not touched. Delegated adapters in unattended runs are handled separately (AGT-4444).

Measured inside the real worker sandbox (macOS, sandbox-exec)

probe before after
gh auth token token returned none
git credential fill (github.com) password none
wrangler whoami logged in (OAuth) not authenticated
npm whoami E401 ENEEDAUTH
ssh to github.com blocked by the sandbox blocked by the sandbox
uv run --frozen in cgf-portal, cargo, node, npm cache works works

Not closed by this PR (honest scope)

  • Absolute-path token reads. A command that deliberately reads a token file by absolute path, for example the real ~/Library/Preferences/.wrangler, still works. The sandbox allows file-read* and the network is open.
  • workerWritableRoots still lists the wrangler config dirs as writable. They are no longer used once HOME is private; removing them is left for the network-off PR.

Behaviour reversal

#493 deliberately kept DevOps and DB credentials (e.g. GITHUB_TOKEN, POSTGRES_DSN) in the worker shell. That test is rewritten to assert the opposite. A project whose tests need a localhost DSN will need a per-project pass-through. That will come with the setup: config in AGT-4798, not here.

Test plan

  • workerEnv.test.ts (9): allowlist, private HOME, re-pointed caches, gh/git/ssh overrides, and a live git credential fill.
  • tools.sandboxUnavailable.test.ts (2): refusal when there is no backend; off still runs.
  • tools.test.ts: a daemon GH_TOKEN is not visible to a worker command.
  • Mutation tests, each reverted after the check:
    • env passthrough → 2 fail;
    • no helper reset → 1 fail;
    • fail-open → 1 fail;
    • real HOME → 2 fail.
  • src/adapters, osSandbox, service, credentialProbes, worker tests: 1160 passed.
  • typecheck, lint.
  • CI.
  • Live fire after merge: a throwaway repo with scripts/release.sh wrapping gh workflow run, run via openswarm exec --issue. Expect 0 workflow runs.

…thout a sandbox (AGT-4783)

A cgf-portal worker's `release.sh --help` ran `gh workflow run` with the
daemon's GitHub login and shipped an unapproved production deploy. The bash
tool now runs with an allowlisted env, a private HOME (caches re-pointed at
the real dirs), an empty GH_CONFIG_DIR, no git credential helper and no ssh
identity. workerSandbox: on without sandbox-exec/bwrap refuses the command
instead of running it unfenced.
@unohee
unohee merged commit 032c03a into main Oct 21, 2026
7 checks passed
@unohee
unohee deleted the fix/agt-4783-worker-credential-boundary branch October 21, 2026 05:34
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