Skip to content

fix(sandbox): scrub the daemon token file pointer (#677) - #818

Merged
kevincodex1 merged 1 commit into
mainfrom
fix/677-scrub-daemon-token-file
Jul 28, 2026
Merged

fix(sandbox): scrub the daemon token file pointer (#677)#818
kevincodex1 merged 1 commit into
mainfrom
fix/677-scrub-daemon-token-file

Conversation

@Vasanthdev2004

@Vasanthdev2004 Vasanthdev2004 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Fixes #677.

scrubSensitiveEnv removed ZERO_DAEMON_REMOTE_TOKEN but not ZERO_DAEMON_REMOTE_TOKEN_FILE. TokenFromEnv (internal/daemon/remote/auth.go:72-86) accepts either form, so a sandboxed command still inherited the path to the bridge token, and since the default posture is read-all it could then read the token out of that file.

Why the one line is the whole fix

I considered also adding the target to the credential deny-read list, and decided against it. The path comes from this variable alone and TokenFromEnv has no default location to fall back on, so a command that never sees the variable has nothing to guess at. Adding a deny rule for an arbitrary env-supplied path would also collide with #816, which is currently in flight in the same function, for no extra protection.

This mirrors the existing treatment of GOOGLE_APPLICATION_CREDENTIALS, which is scrubbed for exactly this reason. The comment there already spells out the rule; this variable simply matched the description and was missed.

Verification

Extended the existing scrub table rather than adding a new test, because TestScrubSensitiveEnv compares the surviving environment exactly, so a missed key fails the assertion by construction. Both forms of the token now go in and neither is expected out.

Dropping the production line reproduces the leak:

scrubSensitiveEnv() = map[... ZERO_DAEMON_REMOTE_TOKEN_FILE:/home/user/.zero/remote-token ...]
                want map[AWS_PROFILE:staging PATH:/usr/bin SAFE_VAR:hello ZERO_OAUTH_CLIENT_SECRET:not-a-provider-secret]

go test ./internal/sandbox/ passes in full, gofmt and go vet clean.

Scope

Two files, twelve added lines, no behaviour change beyond the scrub itself. Keeping it deliberately small: #685 covered adjacent ground and grew to fifteen files, which is a large part of why it stalled.

Summary by CodeRabbit

  • Bug Fixes
    • Improved security when running sandboxed commands by removing both inline daemon tokens and token file paths from inherited environments.
    • Prevents sandboxed processes from accessing sensitive daemon credentials through environment variables.

scrubSensitiveEnv removed ZERO_DAEMON_REMOTE_TOKEN but not its file
counterpart. TokenFromEnv accepts either form, so a sandboxed command
still inherited the path to the bridge token, and the default posture is
read-all, so it could then read the token itself.

Scrubbing the pointer is the whole fix rather than half of one: the path
comes from this variable alone and TokenFromEnv has no default location
to fall back on, so a command that never sees the variable has nothing to
guess at. This mirrors GOOGLE_APPLICATION_CREDENTIALS, which is already
scrubbed for the same reason.

Extends the existing scrub table, which compares the surviving
environment exactly, so the case fails if the entry is dropped. Verified:
without the fix the assertion reports ZERO_DAEMON_REMOTE_TOKEN_FILE
surviving into the scrubbed environment.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d4d4ce7-9337-40a9-a9d4-6b81af39517f

📥 Commits

Reviewing files that changed from the base of the PR and between 81a5e6c and 49b5a19.

📒 Files selected for processing (2)
  • internal/sandbox/runner.go
  • internal/sandbox/runner_test.go

Walkthrough

The sandbox environment scrubber now removes ZERO_DAEMON_REMOTE_TOKEN_FILE alongside the inline token variable. Tests now cover both daemon remote token environment forms.

Changes

Daemon token environment scrubbing

Layer / File(s) Summary
Scrub daemon token file paths
internal/sandbox/runner.go, internal/sandbox/runner_test.go
scrubSensitiveEnv marks ZERO_DAEMON_REMOTE_TOKEN_FILE as sensitive, and TestScrubSensitiveEnv covers both inline and file-path token variables.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested reviewers: jatmn, anandh8x, kevincodex1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR removes the env var leak, but it does not implement the linked issue's requested filesystem deny rule for the token file. Add a DenyRead rule for the resolved token file path, and verify the sandbox cannot read the referenced file.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the change to scrub the daemon token file pointer from sandbox environments.
Out of Scope Changes check ✅ Passed The changes stay focused on sandbox environment scrubbing and test coverage for the reported token-file leak.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/677-scrub-daemon-token-file

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 49b5a1955118
Changed files (2): internal/sandbox/runner.go, internal/sandbox/runner_test.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator Author

@anandh8x @gnanam1990 putting the whole picture in one place rather than commenting on five PRs, since between you the queue clears.

@anandh8x, three of these need only you. Each is at two of three with @gnanam1990 and CodeRabbit already in, so a single approval on each takes them to CLEAN:

Also #750 c6ad2a43 is waiting on your changes-requested from 21 July about Plan 9. I verified it rather than just asserting: GOOS=plan9 go build ./internal/providers/providerio/ exits 0. The remaining plan9 failures in the tree are in internal/fsutil and internal/execution and reproduce identically on origin/main with none of my code present, which is what #817 is about.

Both of you on #818 49b5a195, which is new and has nobody on it yet. It is the #677 fix: scrubSensitiveEnv dropped ZERO_DAEMON_REMOTE_TOKEN but not the _FILE form, so a sandboxed command inherited the path to the bridge token. Two files, twelve lines.

@gnanam1990 on #808 dbdbda11 when you get a moment. Your approval and anandan's were both dismissed by my own push, sorry, that was the ACE type fix CodeRabbit asked for. The delta from 99fefdc4 is thirteen lines in one test helper and no production code. CodeRabbit has not re-reviewed since the fix landed, so that needs to clear first.

No rush on any of it. Flagging it because six of my eight open PRs are short on approvals rather than short on work, and I would rather ask once than nudge repeatedly.

@kevincodex1
kevincodex1 merged commit 3e7692d into main Jul 28, 2026
9 checks passed
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.

ZERO_DAEMON_REMOTE_TOKEN_FILE leaks the daemon bearer token into sandboxed commands

2 participants