fix(security): use execFileSync in gen-types + document path-injection false positives#432
Conversation
…n FP Address the 3 CodeQL findings from the first scan of main (PR #431 enabled CodeQL): - gen-types.mjs (medium, js/shell-command-injection-from-environment): the OPENAPI_URL env var was interpolated into an execSync shell string. Switch to execFileSync with an args array — no shell, nothing to inject into. It's a local dev script (CI never runs it) so the real risk was low, but this is the correct pattern regardless. node --check + eslint + prettier clean. - config_repos.py (high ×2, py/path-injection): false positives. `auth_ref` is constrained to `^[a-zA-Z0-9_-]+$` by CreateConfigRepoRequest (no slashes/dots → no traversal at the API boundary) AND _auth_ref_exists has a resolve()+relative_to() containment guard. CodeQL doesn't model the Pydantic pattern or recognize relative_to() as a sanitizer. Added a comment explaining the two guards; the alerts are dismissed as reviewed false positives. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
There was a problem hiding this comment.
Code Review
This pull request enhances security by adding documentation for a path containment guard in the backend and replacing execSync with execFileSync in the UI type generation script to prevent shell injection. The reviewer identified a cross-platform compatibility issue where spawning npx directly via execFileSync will fail on Windows, and provided a code suggestion to resolve the executable name dynamically.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // SOURCE_URL comes from the OPENAPI_URL env var, and an interpolated shell | ||
| // command would let a crafted value inject. Passing args as an array runs the | ||
| // binary directly with no shell, so there is nothing to inject into. | ||
| execFileSync('npx', ['openapi-typescript', SOURCE_URL, '-o', OUTPUT], { |
There was a problem hiding this comment.
On Windows platforms, spawning npx directly via execFileSync without a shell will fail with an ENOENT error because npx is a batch/cmd script (npx.cmd) rather than a binary executable. To ensure cross-platform compatibility for local development, resolve the executable name dynamically based on the platform.
| execFileSync('npx', ['openapi-typescript', SOURCE_URL, '-o', OUTPUT], { | |
| execFileSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', ['openapi-typescript', SOURCE_URL, '-o', OUTPUT], { |
Accept Gemini's finding: execFileSync('npx', …) ENOENTs on Windows because the
launcher is npx.cmd and there's no shell to resolve the extension. Pick the
platform-correct executable name. Preserves the no-shell args-array form (the
shell-injection fix); just restores the cross-platform parity the original
execSync had.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: SoundMindsAI <eric.starr@soundminds.ai>
Gemini Code Assist adjudicationOne finding, accepted and fixed in
CodeQL (both languages) + both |
Addresses the 3 CodeQL findings surfaced by the first scan of
main(PR #431 enabled CodeQL).gen-types.mjs— js/shell-command-injection-from-environment (medium) → fixedThe
OPENAPI_URLenv var was interpolated into anexecSyncshell string. Switched toexecFileSync('npx', [...])— no shell, so there's nothing to inject into. It's a local dev script (CI never runs it), so real risk was low, but this is the correct pattern.node --check+ eslint + prettier clean.config_repos.py— py/path-injection ×2 (high) → false positives, documented + dismissed_auth_ref_existsis guarded twice:auth_refis constrained to^[a-zA-Z0-9_-]+$byCreateConfigRepoRequest(schemas.py:1399) — no slashes or dots reach the function (a../ref gets a 422).secrets_rootviarelative_to()(also catches symlink escape / non-HTTP callers).CodeQL doesn't model the Pydantic pattern or recognize
relative_to()as a sanitizer. Added an explanatory comment; the two alerts are dismissed as reviewed false positives.Note on remaining alerts
After this, the only open code-scanning items are intrinsic/intentional Scorecard findings (branch protection relaxed on purpose, solo-dev review ratio, project age, fuzzing, OpenSSF badge, 2 command pins) plus
SASTID, which closes on its own as CodeQL accumulates run history over the next several merges.🤖 Generated with Claude Code