runner: clear env on windows with a safe allowlist - #136
Conversation
Made-with: Cursor
Greptile SummaryThis PR closes the Windows env-isolation gap in the runner: it defines a Confidence Score: 5/5Safe to merge; all remaining findings are P2 style/cleanup items that do not affect correctness or security. The core security fix (env_clear on Windows) is correct and mirrors the proven Unix path. Both open findings are P2: duplicate cfg bodies (maintenance nuisance, not a runtime defect) and the missing SYSTEMDRIVE entry (edge-case tool breakage, not a secret-leakage regression). Neither blocks merge. packages/runner/src/lib.rs — minor: collapsed cfg bodies and SYSTEMDRIVE gap Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[run_with_secrets called] --> B[Parse command + secrets JSON]
B --> C[Validate secret keys]
C --> D[Build Command]
D --> E{Platform?}
E -->|Unix| F[env_clear]
E -->|Windows| G[env_clear]
F --> H[Re-apply Unix INHERITED_ENV_KEYS\nPATH HOME USER SHELL TERM\nLANG LC_ALL LC_CTYPE TMPDIR TZ]
G --> I[Re-apply Windows INHERITED_ENV_KEYS\nPATH PATHEXT COMSPEC SYSTEMROOT\nWINDIR USERPROFILE APPDATA TEMP …]
H --> J[Inject secrets as env vars]
I --> J
J --> K[Spawn child process]
K --> L[Wait for exit]
L --> M[Return exit code]
|
| const INHERITED_ENV_KEYS: &[&str] = &[ | ||
| "PATH", | ||
| "PATHEXT", | ||
| "COMSPEC", | ||
| "SYSTEMROOT", | ||
| "WINDIR", | ||
| "USERPROFILE", | ||
| "USERNAME", | ||
| "HOMEDRIVE", | ||
| "HOMEPATH", | ||
| "APPDATA", | ||
| "LOCALAPPDATA", | ||
| "PROGRAMFILES", | ||
| "PROGRAMFILES(X86)", | ||
| "PROGRAMW6432", | ||
| "TEMP", | ||
| "TMP", | ||
| "LANG", | ||
| "LC_ALL", | ||
| "LC_CTYPE", | ||
| "TZ", | ||
| "HOME", | ||
| ]; |
There was a problem hiding this comment.
SYSTEMDRIVE missing from Windows allowlist
SYSTEMDRIVE (typically C:) is used by many Windows tools and the runtime itself to resolve absolute paths (e.g., %SYSTEMDRIVE%\Users\...). Without it, child processes that construct paths from %SYSTEMDRIVE% will see an empty or absent variable. SYSTEMROOT is already included, but SYSTEMDRIVE is a distinct variable and is commonly expected.
| const INHERITED_ENV_KEYS: &[&str] = &[ | |
| "PATH", | |
| "PATHEXT", | |
| "COMSPEC", | |
| "SYSTEMROOT", | |
| "WINDIR", | |
| "USERPROFILE", | |
| "USERNAME", | |
| "HOMEDRIVE", | |
| "HOMEPATH", | |
| "APPDATA", | |
| "LOCALAPPDATA", | |
| "PROGRAMFILES", | |
| "PROGRAMFILES(X86)", | |
| "PROGRAMW6432", | |
| "TEMP", | |
| "TMP", | |
| "LANG", | |
| "LC_ALL", | |
| "LC_CTYPE", | |
| "TZ", | |
| "HOME", | |
| ]; | |
| "SYSTEMROOT", | |
| "SYSTEMDRIVE", | |
| "WINDIR", |
|
Hey, the security fix is spot-on and the allowlist looks comprehensive. A few suggestions before merging:
This way if the loop logic ever changes, we only need to update it in one place.
|
|
nice to meet you |
problem
On Unix,
elic run already clears the child environment and re-applies only a small allowlist (PATH, HOME, locale, etc.). On Windows the runner skipped that step, so the child inherited the entire parent process environment. That can leak unrelated secrets (API keys, tokens) that happen to be set in the shell into the target process, which defeats the isolation users expect from a secret runner.
change
This matches the intent described in the previous inline comment that called for a Windows-specific allowlist.