Frontmatter
| title | fix: the spawn function executes commands with argum... in... |
| author | anupamme |
| state | Closed |
| createdAt | Jul 22, 2026, 2:40 PM |
| updatedAt | Jul 22, 2026, 4:28 PM |
| closedAt | Jul 22, 2026, 4:28 PM |
| mergedAt | |
| branches | dev ← fix-repo-neo-fix-v-001-spawn-command-injection-validation |
| url | https://github.com/neomjs/neo/pull/15710 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Request Changes
🪜 Strategic-Fit Decision
- Decision: Request Changes
- Rationale: The delivered shape contains a code-shape defect with an in-place repair (two unjustified security-scanner suppressions) and a false exploitability premise; the bounded repair is specified below.
Peer-Review Opening: Welcome to Neo.mjs, and thank you for running security analysis against the codebase — scanner-driven hardening contributions are welcome when the finding survives a reachability check. This one does not, and the suppression comments are the part that needs rework. Notes below with concrete guidance for a successful next pass.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch:
ai/scripts/lifecycle/resumeHarness.mjs+windowsBatchSpawn.mjsat currentdev(thecreateSpawnRequestindirection and its callers), the PR's vulnerability claim (V-001, "likely exploitable shell injection"), and the diff. - Expected Solution Shape: A security fix should name the reachable attacker-controlled path from input to sink, then close it with the minimal change; if a scanner finding is a false positive, address the scanner configuration with a documented justification rather than editing code.
- Patch Verdict: Contradicts the premise. The claimed injection surface does not exist:
spawn(spawnRequest.cmd, spawnRequest.args, spawnRequest.options)runs withoutshell: true, so Node callsexecvedirectly — no shell, no metacharacter interpretation onargs. Callers ofspawnAsyncpass internal literal tool names and script paths, not user input. (Thewin32branch routes throughcmd.exeviabuildWindowsBatchCommandLine— a separate quoting contract the type-checks here do not affect.) - Premise Coherence: conflicts: the PR asserts a critical exploitable vulnerability that the spawn path does not support — merging it as-is would teach the scanner (and the graph) a false threat model.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: none linked (external automated security submission; no
Resolves #Nclose-target present) - Related Graph Nodes:
ai/scripts/lifecycle/resumeHarness.mjs,ai/scripts/lifecycle/windowsBatchSpawn.mjs
🔬 Depth Floor
Challenge: (1) The two // nosemgrep: comments silence detect-child-process and path-join-resolve-traversal with zero inline justification — a suppression without a recorded rationale hides the finding for every future reader and masks true positives in the same file later. (2) The createSpawnRequest validation (cmd non-empty, args all-strings) is type-checking, while the claimed attack was content injection — which cannot reach a shell on this path; it may stay only as honestly-labeled defense-in-depth, not as a fix for V-001.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: "likely exploitable … inject shell metacharacters" — contradicted by the spawn path (no
shell: true). - Scanner claims: "re-scan confirms fix" — not reproducible by reviewers; the suppressions make it structurally unreproachable.
- Linked anchors: none present.
Findings: drift flagged in Required Actions.
🧠 Graph Ingestion Notes
[KB_GAP]: Security findings need a two-sentence reachability chain — (1) the concrete input an attacker controls, (2) how it reaches the sink. Without it, pattern-match severity reads as exploitability and produces suppression-shaped fixes.[TOOLING_GAP]: First-time-contributor workflow runs need a maintainer approval; no checks reported on this branch, so no CI evidence exists either way.
🎯 Close-Target Audit
Findings: N/A — no close-target keywords; no linked ticket. If a salvage lands, a maintainer can supply the traceable ticket.
📑 Contract Completeness Audit
Findings: N/A — no public/consumed surface contract is modified (internal lifecycle helpers only); the originating context carries no Contract Ledger to audit against.
🪜 Evidence Audit
Findings: N/A — no runtime-observable AC surface; CI never ran (first-time-contributor workflows require maintainer approval).
🧪 Test-Evidence & Location Audit
- Execution evidence: no checks reported on the branch; "scanner re-scan confirms fix" is not reproducible by reviewers — and the suppressions make it structurally unreproachable.
- Reviewer falsifier: the spawn-path premise was falsified by reading the call site (no
shell: true) and its callers (internal literals) at currentdev.
Findings: author evidence gap (no runnable verification supplied; claims unverifiable as presented).
📋 Required Actions
To proceed with merging, please address the following:
- Remove both
// nosemgrep:comments. If suppressing these two rules repo-wide is genuinely desired, propose it as a scanner-configuration change with a written justification instead of source-level suppression. - Reframe the PR description: the V-001 "shell injection via
spawnRequest.args" premise is not exploitable as stated (noshell: truein the spawn path; internal literal callers only). The validation change may remain only as an honestly-labeled defense-in-depth. - Add one focused spec pinning the new
createSpawnRequestvalidation behavior (non-emptycmd, string-onlyargs) under the existing lifecycle spec family, so the change is covered if it stays.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 40 — inline scanner suppressions without rationale are a code-shape defect; the validation at least sits in the right file.[CONTENT_COMPLETENESS]: 50 — the vulnerability is described with a concrete (but incorrect) exploitation scenario; the reachability analysis that would have falsified it is missing, and there is no ticket or test coverage.[EXECUTION_QUALITY]: 60 — the type validation itself is correct and safe to keep; no CI, no specs, and the scanner claims are not reproducible by reviewers.[PRODUCTIVITY]: 20 — as delivered (suppressions included), the PR reduces the security-signal surface rather than the attack surface.[IMPACT]: 15 — small diff, but suppression-without-justification is a precedent worth blocking on principle.[COMPLEXITY]: 15 — two files, a handful of lines, low reader load.[EFFORT_PROFILE]: Maintenance — scanner-hygiene class.
Guidance for a successful next pass: for each scanner finding, write two sentences — (1) the concrete input an attacker controls, (2) how it reaches the sink. If that chain closes, fix it and we will gladly merge; if it doesn't, that's a scanner-baseline conversation, which is also welcome. Either way, please keep security-rule suppressions out of source comments unless each carries a justification. Thank you again for looking at the codebase's security posture. 🌈
[review-budget-managed]
- outcome: within-budget
- ordinary-limit: 2
- activation-issue: 15257
- activation-pr: 15307
- activated-at: 2026-07-16T20:54:31Z
Moderation record\n\nThis automated submission was closed and de-fanged under the repository's content-trust policy. The external promotional payload was removed; no engagement is requested.