{"id":"CVE-2026-102827","kind":"vulnerability","aliases":["CVE-2026-102827","GHSA-858h-whjf-mvg5"],"related":[],"title":"simple-git: unsafe-operations plugin bypass via git long-option abbreviation (--receive-p/--exe) -> command execution (residual of CVE-2026-28291)","description":"simple-git's blockUnsafeOperationsPlugin blocks dangerous git options (--upload-pack/--receive-pack/--exec/...) unless the consumer opts in via unsafe:{allowUnsafePack:true}. Detection (@simple-git/argv-parser detectVulnerableFlags) matches the parsed flag NAME against literal-spelling patterns: /--(upload|receive)-pack/ (requires the literal '-pack') and the string '--exec'. But git accepts unambiguous prefix abbreviations of long options, and expandToken (token-expander.ts) returns the LITERAL token as flag.name (it uses the spec only for needsNext, never to canonicalize). So `git push --receive-p=<cmd>` parses with flag.name='--receive-p', which /--(upload|receive)-pack/ does NOT match, yet git expands --receive-p -> --receive-pack and runs <cmd> (on a local/file remote, locally). The clone side is robust (its '--u' substring rule catches every --upload* abbreviation); the push --receive-* and --exe* abbreviations have no equivalent rule and slip through.\n\nProof of concept (latest: simple-git 3.36.0, @simple-git/argv-parser 1.1.1, default unsafe plugin ON):\nGate vulnerabilityCheck: 'push --receive-pack=touch...' -> BLOCKED; 'push --receive-pa=touch...' and 'push --receive-p=touch...' -> BYPASS (empty vulns); '--exec=' BLOCKED, '--exe=' BYPASS.\nEnd-to-end via simpleGit().push():\n  CONTROL git.push(['../bare','HEAD:refs/heads/c','--receive-pack=touch /tmp/pwned_ctrl;']) -> throws GitPluginError 'Use of --upload-pack or --receive-pack is not permitted...'; no command runs.\n  BYPASS  git.push(['../bare','HEAD:refs/heads/e2e','--receive-p=touch /tmp/pwned_e2e;']) -> NO GitPluginError; /tmp/pwned_e2e CREATED (git executed the injected command); only a later GitError surfaces.\nDirect git confirms `git push ../bare --receive-p='touch X;' HEAD:refs/heads/m` and `--exe='touch Y;'` both execute on a local/path remote.\n\nImpact: any app relying on simple-git's default unsafe-operations protection while passing attacker-influenced options/args into a git push (local/file remote, or attacker-influenced receive-pack target) can be made to execute arbitrary commands -- the exact protection CVE-2026-28291 provided, defeated by an abbreviated spelling. Same class/impact as GHSA-jcxm-m3jx-f287, on the push path.\n\nRemediation: canonicalize git option abbreviations before matching (resolve to the canonical long name via the per-task flag spec in expandToken), or match on the option stem/prefix down to the shortest unambiguous form for push receive-pack/exec (mirroring the clone-side '--u' approach). Also audit --template and -c/config-write detection for the same abbreviation gap.\n\nCredit: anir0y (independent security research).","summary":"simple-git's default protection against dangerous git options misses abbreviated spellings such as --receive-p and --exe on git push. An attacker who influences push options or arguments can make git execute an arbitrary shell command on a local or file-path remote.","severity":"critical","cvss":9.8,"epss":0.00576,"exploited":false,"exploited_at":null,"products":[{"name":"simple-git","fixed":["4.0.0"],"affected":"<= 3.36.0","ecosystem":"npm"},{"name":"simple-git project simple-git","fixed":["4.0.0"],"affected":"< 4.0.0","ecosystem":"vendor"}],"ecosystems":["npm","vendor"],"tags":["cwe-77","cwe-88","git","node","npm","package","simple-git"],"not_affected_if":["default-config-overridden","no-user-input-to-push"],"how_to_check":"- Check the installed version with `npm ls simple-git` and `npm ls @simple-git/argv-parser`; versions at or below `3.36.0` are affected.\n- Search application code for `.push(` calls that pass user-influenced options or arguments to simple-git.\n- Check whether the app pushes to local or file-path remotes.","fix":"- `simple-git` fixed in `4.0.0` (affected up to `3.36.0`).","status":"open","published_at":"2026-09-29T19:17:25+00:00","first_seen_at":"2026-10-31T16:25:54+00:00","triaged_at":"2026-10-31T16:26:41+00:00","updated_at":"2026-10-31T16:36:24+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-10-31T16:26:41Z","model":"claude-haiku-5-5","output":{"fix":"- `simple-git` fixed in `4.0.0` (affected up to `3.36.0`).","reach":"unknown","title":"simple-git: abbreviated git push options bypass unsafe-operations guard, run commands","impact":"high","summary":"simple-git's default protection against dangerous git options misses abbreviated spellings such as --receive-p and --exe on git push. An attacker who influences push options or arguments can make git execute an arbitrary shell command on a local or file-path remote.","audience":"developers","category":"package","nicknames":[],"who_cares":["simple-git","node","git","npm"],"confidence":0.8,"fix_status":"available","needs_auth":"unknown","worst_case":"Attacker runs arbitrary shell commands on the server running the app.","analyst_note":"Confirm the exact exposure of applications that forward user input to push options; see GHSA-858h-whjf-mvg5 and the linked patch.","how_to_check":"- Check the installed version with `npm ls simple-git` and `npm ls @simple-git/argv-parser`; versions at or below `3.36.0` are affected.\n- Search application code for `.push(` calls that pass user-influenced options or arguments to simple-git.\n- Check whether the app pushes to local or file-path remotes.","plain_action":"","needs_analyst":true,"not_affected_if":["no-user-input-to-push","default-config-overridden"],"who_is_affected":"Applications that use simple-git's default unsafe-operations plugin and pass attacker-influenced options or arguments into git push, especially to local or file-path remotes. Apps that never feed external input into push calls or only push to remote network hosts are less exposed, though the sources do not quantify that risk.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.000837,"input_tokens":5273,"output_tokens":619,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-102827':28A,36A '-2026':24A,27A,35A,415C '-28291':25A,416C '-77':48B '-88':50B '/argv-parser':134C,257C '/bare':298C,325C,352C '/exec':474C '/tmp/pwned_ctrl':305C '/tmp/pwned_e2e':332C,335C '1.1.1':258C '3.36.0':253C '858h':31A 'abbrevi':14A,69B,162C,232C,238C,421C,439C,491C 'accept':159C 'allowunsafepack':128C 'also':482C 'anir0y':494C 'app':372C 'approach':481C 'arbitrari':94B,409C 'argument':88B 'attack':82B,387C,398C 'attacker-influenc':386C,397C 'audit':483C 'block':110C,270C,286C 'blockunsafeoperationsplugin':109C 'bypass':8A,282C,288C,323C 'c/config-write':486C 'canon':445C 'canonic':184C,436C 'catch':229C 'class/impact':424C 'clone':221C,478C 'clone-sid':477C 'command':19A,96B,321C,341C,410C 'concept':248C 'confirm':349C 'consum':123C 'control':296C 'creat':336C 'credit':493C 'cve':23A,26A,34A,414C 'cwe':47B,49B 'danger':65B,111C 'default':62B,259C,379C 'defeat':418C 'detect':130C,487C 'detectvulnerableflag':135C 'direct':347C 'empti':283C 'end':290C,292C 'end-to-end':289C 'equival':241C 'everi':230C 'exact':412C 'exe':18A,77B,237C,287C,361C 'exec':120C,156C,285C 'execut':20A,92B,338C,365C,408C 'expand':206C 'expandtoken':167C,456C 'f287':430C 'file':102B 'file-path':101B 'flag':139C,453C 'flag.name':174C,193C 'form':468C 'gap':492C 'gate':263C 'ghsa':30A,427C 'ghsa-858h-whjf-mvg5':29A 'ghsa-jcxm-m3jx-f287':426C 'git':3A,10A,39A,42A,46A,51B,57B,60B,66B,79B,91B,107C,112C,133C,158C,186C,205C,252C,256C,337C,348C,350C,377C,392C,437C 'git.push':297C,324C 'giterror':345C 'gitpluginerror':307C,334C 'head':299C,326C,358C 'impact':370C 'independ':495C 'influenc':84B,388C,399C 'inject':340C 'jcxm':428C 'later':344C 'latest':249C 'liter':143C,151C,171C 'literal-spel':142C 'local':99B,219C 'local/file':217C,394C 'local/path':368C 'long':12A,164C,446C 'long-opt':11A 'm3jx':429C 'made':406C 'make':90B 'match':136C,203C,441C,458C 'mirror':475C 'miss':68B 'mvg5':33A 'name':140C,447C 'needsnext':181C 'never':182C 'node':52B 'npm':53B 'oper':6A,382C 'opt':124C 'option':13A,67B,86B,113C,165C,438C,461C 'options/args':389C 'p':17A,75B,190C,196C,209C,280C,330C,355C 'pa':274C 'pack':116C,119C,148C,152C,200C,212C,268C,303C,312C,316C,402C,473C 'packag':54B 'pars':138C,191C 'pass':385C 'path':103B,434C 'pattern':145C 'per':451C 'per-task':450C 'permit':319C 'plugin':7A,261C 'prefix':161C 'project':43A 'proof':246C 'protect':63B,383C,413C 'provid':417C 'push':80B,85B,187C,234C,265C,271C,277C,295C,351C,393C,433C,470C 'receiv':16A,74B,118C,147C,189C,195C,199C,208C,211C,235C,267C,273C,279C,302C,315C,329C,354C,401C,472C 'receive-p':15A,73B,188C,194C,207C,278C,328C,353C 'receive-pa':272C 'receive-pack':117C,210C,266C,301C,314C,400C,471C 'refs/heads/c':300C 'refs/heads/e2e':327C 'refs/heads/m':359C 'reli':373C 'remedi':435C 'remot':104B,218C,369C,395C 'requir':149C 'research':497C 'residu':21A 'resolv':442C 'return':169C 'robust':224C 'rule':228C,242C 'run':214C,322C 'secur':496C 'shell':95B 'shortest':466C 'side':222C,479C 'simpl':2A,56B,59B,106C,132C,251C,255C,376C 'simple':38A,41A,45A 'simple-git':1A,37A,40A,44A,55B,58B,105C,131C,250C,254C,375C 'simplegit':294C 'slip':244C 'spec':178C,454C 'spell':70B,144C,422C 'stem/prefix':462C 'string':155C 'substr':227C 'surfac':346C 'target':403C 'task':452C 'templat':484C 'throw':306C 'token':172C 'token-expander.ts':168C 'touch':269C,275C,281C,304C,331C,356C,362C 'true':129C 'u':226C,480C 'unambigu':160C,467C 'unless':121C 'unsaf':5A,127C,260C,381C 'unsafe-oper':4A,380C 'upload':115C,146C,198C,231C,311C 'upload-pack':114C,310C 'use':176C,308C 'via':9A,126C,293C,448C 'vuln':284C 'vulnerabilitycheck':264C 'whjf':32A 'x':357C 'y':363C 'yet':204C","nicknames":[],"mitigations":[],"who_affected":"Applications that use simple-git's default unsafe-operations plugin and pass attacker-influenced options or arguments into git push, especially to local or file-path remotes. Apps that never feed external input into push calls or only push to remote network hosts are less exposed, though the sources do not quantify that risk.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"first_public_at":"2026-09-29T19:17:25+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-858h-whjf-mvg5","url":"https://github.com/advisories/GHSA-858h-whjf-mvg5","severity":"high","published_at":"2026-10-05T23:47:58+00:00","modified_at":"2026-10-31T16:24:12+00:00","first_seen_at":"2026-10-31T16:25:54+00:00","fetched_at":"2026-10-31T19:12:37+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-102827","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-102827","severity":null,"published_at":"2026-09-29T19:17:25+00:00","modified_at":"2026-10-08T20:11:17+00:00","first_seen_at":"2026-10-31T16:36:24+00:00","fetched_at":"2026-10-31T16:36:24+00:00","note":null}],"documents":[{"id":33598,"url":"https://api.github.com/repos/steveukx/git-js/security-advisories/GHSA-858h-whjf-mvg5","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":33599,"url":"https://github.com/steveukx/git-js/security/advisories/GHSA-858h-whjf-mvg5","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":33600,"url":"https://github.com/steveukx/git-js/pull/1193","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":33601,"url":"https://github.com/steveukx/git-js/commit/98864c678444d9336357c844efa4fd5a7984c0d7","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":33602,"url":"https://github.com/steveukx/git-js/releases/tag/simple-git@4.0.0","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"}],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}