Security: replace exec()/execSync with execFile/spawnSync#1976
Security: replace exec()/execSync with execFile/spawnSync#1976vladsoltan wants to merge 11 commits into
Conversation
…s object
Codex auto-discovers a plugin's hooks/hooks.json whenever the Codex
manifest has no `hooks` field: load_plugin_hooks falls back to a
hardcoded DEFAULT_HOOKS_CONFIG_FILE = "hooks/hooks.json" and registers
it. hooks/hooks.json is the Claude Code SessionStart hook, it is tracked
in this repo, and the Codex marketplace installs the whole repo root
(source url "./"), so the fallback re-registered the SessionStart hook
and its install-time trust prompt on Codex.
Removing the Codex hook file and the manifest `hooks` pointer (commit
"Remove Codex hooks") did not disable the hook on Codex — it removed the
explicit declaration that was overriding the fallback, so the fallback
took over and found the Claude hooks/hooks.json.
Declare an empty inline hooks object ({}) in .codex-plugin/plugin.json.
It parses as an empty inline hook set and stops Codex reaching the
auto-discovery fallback. An absent field, an empty array ([]), and an
empty inline list all collapse back to the fallback, so the value must
be exactly {}.
Update the test to assert the manifest declares hooks: {} (and that
hooks/hooks.json exists, which is what makes the declaration necessary),
replacing the prior assertion that the field was absent — which passed
while the hook was still being auto-discovered.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… docs hooks/session-start-codex has had no caller since "Remove Codex hooks" (obra#1845) deleted hooks-codex.json and its manifest registration; the Codex manifest now declares an empty hooks object so Codex registers no session-start hook at all. The script is Codex-specific dead code — nothing executes it on Codex or any other harness. - Delete hooks/session-start-codex. - tests/hooks/test-session-start.sh: drop the two Codex cases that are redundant with the generic session-start tests (nested-format and the legacy-warning omission are already covered by the Claude Code cases). Re-point the "wrapper dispatches" case to the live `session-start` script so run-hook.cmd dispatch coverage — used by Claude Code and Cursor in production — is preserved rather than lost. - docs/porting-to-a-new-harness.md: Codex is no longer a Shape A (shell-hook) harness, so re-anchor that worked example to Cursor (a live shell-hook harness that demonstrates the same per-harness field, schema, and matcher variance) and mark Codex as native skill discovery with no session-start hook. Clears the references to the deleted hooks-codex.json. - docs/windows/polyglot-hooks.md: the "check hooks-codex.json" pointer referenced a file deleted in obra#1845; re-point to hooks-cursor.json. RELEASE-NOTES.md keeps its historical mention of hooks-codex.json (it accurately records what that release did). The tests/codex-plugin-sync fixtures build their own synthetic session-start-codex and test the sync mechanism generically, so they are intentionally left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…x portal packaging
|
Appreciate the sweep — 1. The
|
…command injection
Fixes two command injection vulnerabilities:
1. skills/brainstorming/scripts/server.cjs (BRAINSTORM_OPEN_CMD):
- Changed from cp.exec() (shell-based) to cp.execFile() (no shell)
- URL passed as argv element instead of string concatenation
- Prevents shell metacharacter injection if URL contains special chars
2. skills/writing-skills/render-graphs.js:
- Changed from execSync('which dot') to spawnSync('which', ['dot'])
- Changed from execSync('dot -Tsvg') to spawnSync('dot', ['-Tsvg'], {input})
- Added proper exit/error handling for spawnSync
- Avoids shell interpretation, reduces attack surface
Security audit revealed no hardcoded secrets but identified shell-based exec as
highest-risk pattern in this codebase. Shell-less exec functions mitigate injection.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
4ddb4c4 to
9b0d490
Compare
|
Thanks for the detailed review. I've addressed all three points:
The amended commit now contains only the render-graphs.js changes, coordinating with existing PRs #1964 and #1805 rather than duplicating their work. |
Derives the thread list from GitHub rather than a hand-maintained manifest. A manifest we had to remember to update would drift, and the sweep would then report 'nothing new' while skipping a thread — the same failure as the stale overlay we just filed against gitban. GitHub already knows every issue and PR we have authored or commented on; that IS the manifest. Only state is a last-checked timestamp. Load-bearing detail found by running it: 'gh search issues' does NOT return pull requests. The first version reported 4 threads and silently omitted all four of our own PRs plus every PR we had reviewed. Now queries issues AND prs, for author AND commenter. Its first real run found a signal we had missed entirely: @vladsoltan adopted all three points of our obra#1976 review — dropped the hunk we proved broke a test, aligned with obra's own obra#1805 that we spotted it duplicated, and retargeted main to dev. That makes additive review 2-for-3, against 0-for-4 on our own PRs.
Who is submitting this PR? (required)
What problem are you trying to solve?
skills/writing-skills/render-graphs.jsusesexecSync('which dot', ...)to check graphviz availability. Thewhichcommand is Unix-specific and does not exist on Windows (cmd.exehas nowhichequivalent), making the tool unusable on Windows—even if graphviz is installed. This PR makes the availability check portable across platforms.What does this PR change?
Replaces shell-based command execution in
render-graphs.jswithexecFileSync()to make the tool portable and remove shell-based execution:execSync('which dot')toexecFileSync('dot', ['-V'])— tests that dot is both installed and executable, works across platforms.execSync('dot -Tsvg', {input})toexecFileSync('dot', ['-Tsvg'], {input})— no shell invocation, no string parsing.Is this change appropriate for the core library?
Yes.
render-graphs.jsis existing core tooling that ships with thewriting-skillsskill. This is a portability bugfix to existing infrastructure that enables Windows support.What alternatives did you consider?
whichon Unix,whereon Windows): Would add branching and complexity;execFileSync('dot', ['-V'])works on all platforms.Does this PR contain multiple unrelated changes?
No. One file, one concern: run graphviz without a shell to enable Windows portability.
Existing PRs
BRAINSTORM_OPEN_CMDbrowser launcher), fix(writing-skills): run graphviz without a shell in render-graphs.js (Windows portability) #1805 (Windows portability fix for this same file — takes a similar approach). This PR now focuses solely on the render-graphs.js portability issue; the server.cjs browser-launcher hardening is handled by fix(brainstorm): launch BRAINSTORM_OPEN_CMD without a shell #1964.Environment tested
Code changes reviewed for correctness and portability; aligned with #1805's approach for Windows compatibility.
New harness support (required if this PR adds a new harness)
N/A
Evaluation
execSync()as security risk; found Windows portability issue in render-graphs.js (whichdoes not exist on Windows).Rigor
Human review