fix(tgit): shell-quote every gf CLI arg to prevent injection#60
Merged
Merged
Conversation
gfExec built `bash -c "<gfPath> <args.join(' ')>"`. Only the MR title and
description were shell-quoted (in gfMrCreate); repo, source/target branch,
reviewers, and the clone local-path were interpolated raw. A repo or
branch value containing shell metacharacters (`;`, `|`, `$()`, …) was
therefore executed by `bash -c`.
Example — gfMrCreate({ repo: "team/repo;echo PWNED", ... }) produced the
command:
gf mr create -R team/repo;echo PWNED -s feat ...
which runs `echo PWNED` when gfExec spawns it. Verified with a real bash
invocation + fake gf: the old cmd executes the injected `echo` and gf
receives split args; the fixed cmd passes `team/repo;echo PWNED` as a
single literal argument and nothing extra runs.
Fix: shell-quote every token (including the binary path) centrally in
gfExec, and drop the now-redundant per-call shellQuote() in gfMrCreate.
The two-segment `gf repo clone` path through gfExec is covered by the
same change; the multi-segment git-clone path already used a spawnSync
argv array.
Added a regression test asserting repo/source/target metacharacters are
single-quoted as single tokens with no unquoted `;`/`|` left for bash.
Existing gf-cli tests (newline preservation, single-quote escaping, URL
extraction) still pass. `npm test` 1440 passed; `tsc --noEmit` clean.
Co-Authored-By: Claude <noreply@anthropic.com>
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.
Summary
gfExec(src/providers/tgit/gf-cli.ts) runs the gf CLI viabash -c "<gfPath> <args.join(' ')'>". Only the MR title and description were shell-quoted (ingfMrCreate); repo, source/target branch, reviewers, and the clone local-path were interpolated raw. A repo or branch value containing shell metacharacters (;,|,$(), backticks, …) was therefore executed bybash -c.The values originate from user input (
--repo, branch names, reviewers), so this is an argument-injection / arbitrary-command-execution vector.Proof (real bash + fake
gf)gfMrCreate({ repo: "team/repo;echo PWNED", source: "feat", target: "master", title: "my title" })Before — the constructed command is:
bash -cprintsPWNED …(the injectedechoruns) andgfreceives split args:After — every token is single-quoted:
nothing extra executes and
gfreceives the value as one literal argument:Fix
Shell-quote every token (including the binary path) centrally in
gfExec, and drop the now-redundant per-callshellQuote()ingfMrCreate:This keeps the existing
bash -cexecution mechanism (chosen for launcher compatibility) and covers every call site at once:gf repo clonepath (gfExec(['repo','clone', repo, localPath])) is now safe.spawnSync('git', [...])argv array (no shell) — unchanged.Tests
gf-cli.test.ts) asserting repo/source/target metacharacters are single-quoted as single tokens, with no unquoted;/|remaining forbash -cto interpret. Fails on the old code (team/repo;echo PWNEDwas unquoted).gf-cli.test.tscases (newline preservation in description, single-quote escaping, MR-URL extraction) still pass — the title/description quoting result is unchanged.npm test→ 1440 passed;tsc --noEmit→ clean.Co-Authored-By: Claude noreply@anthropic.com