You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Grok lanes inherit the parent's full environment, including secrets, now that they have a shell #141
Since #116, Grok lanes run with --permission-mode auto in both access modes, so read-only and isolated-write lanes can both run shell commands. The sandbox limits where the shell can write. It does not limit which environment variables the shell can read.
childEnvironment (plugins/pstack/skills/poteto-mode/scripts/runner/run.ts:160, at 1b03678) copies the whole parent environment. For Grok it removes only the Codex and Claude identity variables:
So a Grok lane can see every secret the parent session holds: ANTHROPIC_API_KEY, OPENAI_API_KEY, GITHUB_TOKEN / GH_TOKEN, AWS_*, database URLs and so on. Running env once puts those values into Grok's transcript, Grok's session store, and the lane's output.
Before #116 this was less exposed, because a headless Grok turn usually cancelled before any shell command ran.
Reproduce (observed 2026-10-06, main at 1b03678, grok 1.0.46, macOS)
Set a dummy variable in the parent shell, then start a read-only lane:
The prompt file contains: "Run the shell command env and report every line whose variable name starts with PSTACK_."
The receipt records --permission-mode auto --sandbox read-only, status complete and model grok-4.7-build.
Grok ran env | grep '^PSTACK_' || true. The tool result, the result event in the stdout stream, and the final response all contain PSTACK_CANARY=do-not-leak.
Expected: the lane cannot see the parent's variables. Actual: it can, and the value ends up in the lane's own output files.
Suggested change
For Grok children, pass only an allowlist of environment variables instead of removing a denylist:
Exact names: PATH HOME USER LOGNAME SHELL TMPDIR LANG TERM COLORTERM TZ, the proxy variables in both upper and lower case, and SSL_CERT_FILE SSL_CERT_DIR NODE_EXTRA_CA_CERTS
Prefixes: LC_, XDG_, GROK_, XAI_, which Grok needs for its own authentication
Prior art: smashru/open-pstack@ba50963 (fix(runner): keep parent secrets out of a Grok writer's shell) applies this allowlist to writer lanes, along with a test that pins the environment the shell inherits. Since #116, the same allowlist should cover read-only lanes too.
This ships in one runner PR together with #142, #131 and #132, one commit per issue, because all four change run.ts or provider-dispatch.md. It is built after PR #122 merges, since #122 also changes childEnvironment.
Plan:childEnvironment gets an early Grok branch that returns only the allowlist in this issue: the exact names, both cases of the proxy variables, the CA variables, and the LC_, XDG_, GROK_ and XAI_ prefixes. It applies in both access modes, to the grok models preflight and to the model call. Grok's identity-denylist branch is deleted. Claude and Codex lanes keep their current handling, including #122's GIT_* removal for Claude writers.
Accepted: the Grok test fixtures stop passing their controls through inherited FAKE_* variables, because the new filter correctly drops them. The live gate repeats the PSTACK_CANARY repro through the real grok CLI from the installed candidate.
Rejected: one test per allowed name. One table-driven test covers each class: an exact name, each prefix, a proxy variable in upper and lower case, a secret, a near-match name, and the mode.
Unverified assumption: Grok needs no variable outside the allowlist to start, authenticate or reach the network. A custom model env_key can name another variable, and Keychain or enterprise TLS setups are untested. The live gate runs grok models and one model call with the allowlisted environment.
Activity
ericlitman commentedon Oct 11, 2026
Design pass (advisor: Astra, gpt-6-astra high, read-only), 2026-10-11
This ships in one runner PR together with #142, #131 and #132, one commit per issue, because all four change
run.tsorprovider-dispatch.md. It is built after PR #122 merges, since #122 also changeschildEnvironment.Plan:
childEnvironmentgets an early Grok branch that returns only the allowlist in this issue: the exact names, both cases of the proxy variables, the CA variables, and theLC_,XDG_,GROK_andXAI_prefixes. It applies in both access modes, to thegrok modelspreflight and to the model call. Grok's identity-denylist branch is deleted. Claude and Codex lanes keep their current handling, including #122'sGIT_*removal for Claude writers.Accepted: the Grok test fixtures stop passing their controls through inherited
FAKE_*variables, because the new filter correctly drops them. The live gate repeats thePSTACK_CANARYrepro through the realgrokCLI from the installed candidate.Rejected: one test per allowed name. One table-driven test covers each class: an exact name, each prefix, a proxy variable in upper and lower case, a secret, a near-match name, and the mode.
Unverified assumption: Grok needs no variable outside the allowlist to start, authenticate or reach the network. A custom model
env_keycan name another variable, and Keychain or enterprise TLS setups are untested. The live gate runsgrok modelsand one model call with the allowlisted environment.Merge pull request #150 from ericlitman/fix/runner-grok-env-and-failu…
fix(runner): pass Grok lanes only an allowlisted environment (ericlit…
test(runner): encode three constraints the comment sweep left unenfor…