security: shell snapshots persist secret env vars (PWD/OLDPWD-only denylist)
Summary
Shell snapshots written under $CODEX_HOME/shell_snapshots currently only exclude PWD and OLDPWD from export -p output. Common credential environment variables (API keys, tokens, cloud secrets) can therefore be persisted on disk whenever a snapshot is created.
I attempted to open a PR, but GitHub reports:
An owner of this repository has limited the ability to open a pull request to users that are collaborators on this repository.
Sharing a minimal, tested patch via this issue for a collaborator to land.
Confirmed on current main
// codex-rs/core/src/shell_snapshot.rs
const EXCLUDED_EXPORT_VARS: &[&str] = &["PWD", "OLDPWD"];
Snapshot scripts dump environment exports into files used to warm subsequent shells. Any process that can read CODEX_HOME may recover secrets from those files.
Minimal fix (already implemented)
Branch on my fork (ready to merge by a collaborator):
- Fork branch: https://github.com/1837620622/codex/tree/fix/shell-snapshot-redact-secrets
- Compare: https://github.com/openai/codex/compare/main...1837620622:codex:fix/shell-snapshot-redact-secrets
- Commit:
cc466b9—fix(core): redact secret env vars from shell snapshots - Author: 传康Kk (@1837620622)
<35034498+1837620622@users.noreply.github.com>
Changes
| Change | Why |
|--------|-----|
| Exact denylist for high-signal names (OPENAI_API_KEY, AWS_SECRET_ACCESS_KEY, GH_TOKEN, …) | Known credential env names |
| Pattern denylist (*_TOKEN, *_SECRET, *_PASSWORD, *_API_KEY, …) | Catches custom secret names |
| Same rules for zsh / bash / sh / PowerShell generators | Consistent behavior |
| Regression tests in shell_snapshot_tests.rs | Prevent reintroduction |
Non-secret vars (PATH, HOME, AWS_REGION, etc.) remain available for shell replay.
Local verification
Bash simulation with planted secrets (OPENAI_API_KEY, *_TOKEN, *_PASSWORD, AWS_SECRET_ACCESS_KEY) confirmed values and names are omitted while normal exports are retained.
Request
Could a collaborator cherry-pick or open the PR from the fork branch above? Happy to iterate on the denylist if you prefer a stricter/looser policy.
Thanks!
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗