fix(tasks): stop the sandbox retaining a prior actor's GitHub token - #72507
Merged
VojtechBartos merged 1 commit intoJul 21, 2026
Conversation
Two runtime gaps let a follow-up actor keep the previous actor's GitHub identity after a per-message logout: - The agent-server was launched with GITHUB_TOKEN/GH_TOKEN in its process env, frozen for the process lifetime. Clearing the live /tmp/agent-env file could not revoke that copy, so in-process tools resurrected it. Add both vars to SANDBOX_AGENT_LAUNCH_UNSET_ENV_VARS; the token is still delivered per command via the file (re-sourced by BASH_ENV, seeded before the unset). - The periodic user-token refresh loop re-applied the run owner's token to every live sandbox keyed on the owner's integration, overwriting a transition. Skip runs whose sandbox-github-identity marker is bound to a different actor. Pairs with the agent-server fix (PostHog/code) that treats an emptied env file as an explicit logout instead of falling back to the process env.
VojtechBartos
merged commit Jul 21, 2026
c9b507c
into
vojtab/github-identity-transitions
178 checks passed
Member
Author
|
Folded into #71941 so there's a single posthog PR for the GitHub identity work. The two hardening commits (unset the launch env token + actor-aware refresh loop) are now part of that PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Summary
Follow-up to #71941. During multiplayer testing, a follow-up actor without repo access pushed as the previous actor: the exact leak the GitHub identity gate is meant to prevent. The logout stripped the git remote and the
/tmp/agent-envfile, but the prior actor's token survived in two runtime places the file-clear can't reach. This closes both.When does a transition happen?
A "transition" is a follow-up in the same thread from a different Slack user than the one the sandbox is currently bound to. The gate fires only then (same-actor follow-ups and bot runs are skipped).
sequenceDiagram actor A as User A (has access) actor B as User B (no access) participant S as Sandbox (one shared box) participant G as GitHub A->>S: "@bot clone repo X and work on it" Note over S: provisioned with A's token<br/>identity marker = A B->>S: same thread: "commit it and open a PR" rect rgb(255,235,235) Note over S: ACTOR TRANSITION A to B S->>S: gate: B has no access, so LOG OUT<br/>clears git remote + /tmp/agent-env S-->>S: but A's token survives elsewhere S->>G: git push (recovered A's token) G-->>B: PR opened as User A (LEAK) endWhy the logout didn't stick: the token lives in 3 places
One running sandbox holds A's token in three spots. Logout only reached two of them:
Changes
constants.py: addGITHUB_TOKEN/GH_TOKENtoSANDBOX_AGENT_LAUNCH_UNSET_ENV_VARS, so the agent-server process holds no static token. The token is still delivered per command via the live file (re-sourced byBASH_ENV, seeded byenv -0 > ENV_FILEbefore the unset), sogit/ghstill authenticate on turn 1: only the un-revocable copy is removed. Audited every agent-server token consumer first: all resolve via the file-firstresolveGithubToken, so the unset is safe.sandbox_credentials.py: the periodic refresh loop now skips a run whosesandbox-github-identitymarker is bound to a different actor than the run owner (a transition / logout has occurred), so it can't re-inject the owner's token.flowchart LR T([user token refreshed]) --> L{ run's sandbox marker<br/>== run owner? } L -- "yes / unset" --> A[re-apply owner token] L -- "no: transitioned away" --> S[skip, leave the current<br/>actor's state intact]Companion PR (required together)
Needs PostHog/code#3611, which makes the agent-server treat an emptied env file as an explicit logout (return
"") instead of falling back toprocess.env, and runs theghattribution/whoami calls as the current actor. This backend PR removes the process-env token; the code PR stops the resolver andghpaths from resurrecting it. Both are needed for a complete fix.How did you test this code?
resolveGithubTokentests in fix(agent): treat an emptied sandbox env file as GitHub logout code#3611 (11 pass), including the assertion that an emptied file does not resurrect the process-env token.test_actor_transition_gates_owner_token_propagation(marker unset / owner / other -> include / include / exclude). Could not run the DB-backed suite locally (ClickHouse held by the local dev stack); CI validates.