Skip to content

fix(security): harden git argv against second-order command-line injection#8

Merged
kreneskyp merged 3 commits into
mainfrom
fix/git-argv-hardening
Jun 28, 2026
Merged

fix(security): harden git argv against second-order command-line injection#8
kreneskyp merged 3 commits into
mainfrom
fix/git-argv-hardening

Conversation

@kreneskyp

Copy link
Copy Markdown
Contributor

Closes #6. Resolves the 3 high-severity CodeQL js/second-order-command-line-injection alerts in src/resolve.ts (pre-existing on main, in the git resolver — not from the discovery/npm features).

Problem

Source-descriptor fields (repo, url, ref, sha) flow into the git argv via execFileSync. That avoids a shell, but git interprets a leading-- value as an option (e.g. a ref of --upload-pack=<cmd> or --output=…) — second-order argument injection.

Fix

  • src/sources.ts: added the reqArg guard (rejects leading -; mirrors the PR feat: resolve npm sources via npm pack #3 precedent, not yet on main) + a new optArg for optional fields. In normalizeSource: reqArg on github.repo, git.url, git-subdir.url, url.url; optArg on ref/sha for every git variant. Rejection (not an argv -- separator), since git checkout doesn't accept -- cleanly before a ref.
  • normalizeSource runs before any git invocation (clone/fetch/checkout) — confirmed and preserved.
  • Spec: FR-004 argument-injection Behavior note, FR-004-CON-3, FR-004-AC-8; matrix rows + TC-022 in spec/tests.md.

Gates

  • Tests: 23 passed; src/** 100% coverage. TC-022 written Red-first (confirmed failing pre-fix).
  • ESLint + Prettier clean on all touched files; vite + dts build clean.
  • quire validate clean (pre-existing duplicate-archetype warnings only).
  • All 3 CodeQL alert sites now reached only via guarded fields.

Note: repo-wide make lint is pre-broken in this env (corepack pnpm 10.33.4 vs 11.5.2; pre-existing prettier drift in untouched workflow/quire files). Touched files all pass.

🤖 Generated with Claude Code

kreneskyp and others added 2 commits June 27, 2026 19:25
…ction

Source-descriptor fields flow into the `git` argv via `execFileSync`:
`repo`/`url` reach `git clone`/`git fetch` and `ref`/`sha` reach
`git checkout --detach <wanted>`. `execFileSync` avoids a shell, but `git`
itself treats a leading-`-` argument as an option (e.g. a `ref` of
`--upload-pack=<cmd>`), so an option-like value is a second-order argument
injection (CodeQL js/second-order-command-line-injection, 3 high alerts in
src/resolve.ts).

Extend the `reqArg` guard (reject a leading `-`) to every source field that
reaches the git argv, applied in `normalizeSource` before any git invocation:
- `reqArg` on github.repo, git.url, git-subdir.url, url.url
- new `optArg` on the optional ref/sha of every git variant (rejected rather
  than escaped, since `git checkout` does not accept `--` cleanly before a ref)

`resolveSource` already calls `normalizeSource` first, so the guard runs ahead
of clone/fetch/checkout for all three alert sites.

Spec: add FR-004-CON-3 + FR-004-AC-8 (argv injection guard) and TC-022 rows;
src/** stays at 100% coverage; quire validate clean.

Closes #6

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two bypasses of the second-order command-line-injection guard found in
review:

F1: reqArg validated the RAW field, but toGitUrl does raw.trim() before
the value reaches `git clone`/`git fetch`. A leading-whitespace-then-dash
payload (e.g. " --upload-pack=… ext://x") passed the raw startsWith("-")
check yet trimmed to a git option at the argv (and toGitUrl passed it
through unwrapped on its `://`). Affected github.repo, git.url,
git-subdir.url. Fix: guard the TRIMMED value so the value validated is
the value that reaches the argv.

F2: git-subdir.path used req (non-empty only), so an option-like path
("--stdin", "-X") reached `git sparse-checkout set <path>` as a flag.
Fix: validate it with reqArg too.

Adds TC-023 (trim-bypass on repo/url) and TC-024 (option-like subdir
path); updates FR-004-CON-3 + AC-9/AC-10 and the test matrix. 100% src
coverage retained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconcile the git argv-injection hardening (PR #8) with the npm source
resolution that landed on main (PR #3).

- src/sources.ts: unify to one trimmed `reqArg` guard used on both the npm
  `package` field (#3) and the git argv fields (#8: repo/url/path + optArg
  on ref/sha).
- spec/functional/FR-004: keep #3's npm ACs/CONs; renumber #8's additions
  after the highest existing id — CON-3→CON-5, AC-8/9/10→AC-14/15/16.
- spec/tests.md: renumber #8's git TCs after the npm block —
  TC-022/023/024→TC-029/030/031; update FR-coverage, Test Index, Constraint
  Boundary, Error-Path tables and coverage counts.
- tests/index.test.ts: update the three guard tests' TC tags to
  TC-029/030/031 so spec and code agree 1:1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kreneskyp kreneskyp merged commit 44b8d0a into main Jun 28, 2026
5 checks passed
kreneskyp added a commit that referenced this pull request Jun 28, 2026
… + fix CodeQL

Integrate main's npm-source-resolution (PR #3) and git-security (PR #8) work
with the plugin-discovery feature (search.ts). Resolved conflicts in
spec/spec.md, spec/non-functional/NFR-003, and spec/tests.md so both main's
npm/git content and the discovery content survive.

Renumber the discovery test cases off main's TC-001..TC-031 block: the
contiguous discovery block TC-022..TC-060 shifts +10 to TC-032..TC-070
(uniform map, relative order preserved). Updated every occurrence across
tests.md (FR/NFR coverage, Test Index, Constraint Boundary, Error-Path,
Edge Cases, coverage-summary prose), the discovery FR files (FR-008..FR-012),
and the TC tags in tests/search.test.ts. FR-004 (main) left intact.

Fix 4 HIGH CodeQL js/incomplete-url-substring-sanitization alerts in
tests/search.test.ts by replacing url.includes("<host>.com") routing checks
with strict `new URL(url).host === "<host>"` comparisons.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[plugins][security] Harden git argv against command-line injection (3 CodeQL high alerts)

1 participant