[codex] Trust protected PowerShell parsers and reject untrusted wrappers#30628
Draft
bookholt-oai wants to merge 11 commits into
Draft
[codex] Trust protected PowerShell parsers and reject untrusted wrappers#30628bookholt-oai wants to merge 11 commits into
bookholt-oai wants to merge 11 commits into
Conversation
This was referenced Jun 30, 2026
This was referenced Jul 1, 2026
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.
Why
Codex inspects PowerShell commands before deciding whether they may run. On Windows, that inspection previously launched the PowerShell executable named by the command, so a model- or repository-selected
powershell.exeorpwsh.execould execute before the normal command-policy, approval, and sandbox boundary.What
How
Parser resolution derives the Windows PowerShell path from the System Known Folder and the PowerShell 7 path from the machine-wide Program Files Known Folder. It canonicalizes both the protected root and candidate, rejects reparse escapes and non-files, and launches only that verified parser.
The parser child runs from its canonical protected installation directory with a cleared, minimal environment. A module-free, length-bounded framed protocol uses only .NET primitives, so request handling does not invoke autoloadable PowerShell cmdlets or inherit runtime/profiler hooks, user module paths, profiles, or repository-relative discovery.
Before any script is sent to PowerShell, a deliberately conservative raw-source gate rejects parse-time module and DSC constructs, escaped forms, and assembly-qualified type syntax. The assembly gate becomes sticky after a raw
[and rejects any later raw comma, covering nested types and block-comment tricks beforeParseInputcan resolve a rooted local DLL or UNC assembly identity. Benign false positives are treated as opaque rather than sent to the parser.PowerShell classification records runtime trust independently from parse success. A trusted, parsed runtime continues through normal inner-command policy evaluation. A trusted but unsupported command follows the existing generic outer-wrapper path on its unchanged full argv: it remains non-known-safe, so restricted modes sandbox or prompt unless an explicit outer-command policy allows it. A protected-parser process or protocol failure is terminal, and an untrusted runtime is always forbidden whether or not its body parses. This preserves protected-runtime compatibility without letting a hidden inner command inherit a safelist result.
For parsed scripts, lowered inner commands can make the result stricter and can permit sandboxed execution, but they cannot authorize sandbox bypass: the eventual PowerShell runtime can resolve profiles, modules, and external commands differently from the isolated parser. Only an exact full-argv outer Allow can override heuristic concerns and run outside the sandbox. Explicit inner or outer Prompt/Forbidden rules remain strictest, and every proposed persistent amendment binds the unchanged outer argv.
This intentionally keeps parser provenance, untrusted-wrapper fail-closed behavior, conservative pre-parse gating, and exact approval identity in one review boundary. The larger-than-usual diff is primarily the platform and policy regression matrix needed to cover that boundary.
This PR is a stack-only security prerequisite, not a standalone product fix. A non-Known-Folder custom or PATH-selected PowerShell remains terminal here. The downstream composed one-shot policy layer must restore eligible custom-runtime execution without classifier-time launch, cache reuse, or durable PATH-sensitive authority before this stack lands.
Testing
just test -p codex-shell-command(149 tests passed)codex-corePowerShell policy tests (99 tests passed)just fixandjust fmtRelated: PSEC-4922