- Git का
--सामान्य option terminator नहीं है, बल्कि revision और pathspec को अलग करता है; इसलिए untrusted revision को सुरक्षित रूप से पास करने के लिए Git 2.24.0 से समर्थित--end-of-optionsज़रूरी है git log --end-of-options "$rev" -- "$path"में पहला marker options और revision को, जबकि बाद वाला--revision और path को अलग करता है; दोनों एक-दूसरे की जगह इस्तेमाल नहीं किए जा सकते- shell के बिना सीधे
argvarray चलाने पर भी अगर dash से शुरू होने वाला input--upload-pack,core.sshCommand,ProxyCommandजैसे options के रूप में समझ लिया जाए, तो CWE-88 argument injection हो सकता है - जांचे गए 19 package managers में 17 Git binary को default या एकमात्र तरीके से चलाते थे, लेकिन
--end-of-optionsइस्तेमाल करने वाला tool सिर्फ Go काcmd/goथा - मूल समाधान के लिए subcommand के अनुसार Git का minimum version 2.24.0·2.30.0·2.43.1 तक बढ़ाने की compatibility cost है, जबकि Git libraries argument injection boundary हटाती हैं, लेकिन upstream के checkout safety fixes को सीधे track करना पड़ता है
-- और --end-of-options में फर्क
- सामान्य Unix tools में
--option parsing के अंत को दिखाता है, इसलिएrm -- -fमें-fको force delete option नहीं बल्कि filename माना जाता है - Git शुरू से
--को revision और pathspec के separator के रूप में इस्तेमाल करता हैgit log fooमें यह अस्पष्ट है किfoobranch है या filegit log main -- README.mdका मतलबmainके उन commits से है जिन्होंनेREADME.mdको बदला
- इस design की वजह से revision position के लिए option termination marker नहीं था, और
git log "$rev"में अगर$revdash से शुरू हो, तो Git उसे option मान लेता है --end-of-optionsलाने वाले commit में बताया गया कि मौजूदा--पहले से revision और pathspec को अलग कर रहा था, इसलिए options और revision को अलग करने के लिए अलग marker चाहिए था--end-of-optionsको gitcli(7) में document किया गया है, और यह Git 2.24.0 के नवंबर 2019 release में जोड़ा गया
कमांड के हिसाब से सही उपयोग
git clone -- "$url"मेंclonePOSIX convention का पालन करता है, इसलिए URL से पहले का--option parsing रोक देता हैgit checkout "$ref" --में बाद वाला--$refको filename नहीं बल्कि revision बताता है, लेकिन यह नहीं रोकता कि$refपहले option की तरह parse हो जाए- untrusted revision और path को साथ में सुरक्षित रूप से पास करने के लिए
git log --end-of-options "$rev" -- "$path"की तरह दोनों markers इस्तेमाल करने चाहिए--end-of-optionsoptions और revision को अलग करता है--revision और path को अलग करता है
- अगर दोनों markers को एक-दूसरे का विकल्प मान लिया जाए, तो dash से शुरू होने वाले input को नहीं रोका जा सकता
हर subcommand में support का अलग समय
--end-of-optionssupport सभी Git commands में एक साथ नहीं आया, बल्कि हर subcommand में अलग-अलग जोड़ा गयाgit rev-parseअपना अलग argument parser इस्तेमाल करता है, इसलिए शुरुआती introduction के एक साल बाद Git 2.30.0 में support शुरू हुआgit checkoutऔरgit resetखुद--को interpret करते हैं, और शुरुआती implementation--end-of-optionsको argument list में छोड़ देती थी, इसलिए वे इसे reject करते थे- यह समस्या Git 2.43.1 के फरवरी 2024 release में ठीक हुई
shell के बिना भी argument injection
- Git, Mercurial और SSH में caller द्वारा तय command चलाने वाले options आधिकारिक feature के रूप में मौजूद हैं
git clone --upload-pack=<cmd>server-side binary तय करता है- हर Git call में
-c core.sshCommand=<cmd>connection command बदल देता है - Mercurial का
--config=alias.<subcmd>=!<shell>चलाए जाने वाले subcommand को मनचाहे shell script से redefine करता है - SSH का
-oProxyCommand=<cmd>proxy command तय करता है
- अगर wrapper program untrusted string को argument list में डाल दे, तो ये features attack vector बन सकते हैं
- इस तरह की विफलता CWE-88 argument injection है और shell command injection से अलग है
- यह तब भी हो सकता है जब program
system()की जगहargvarray औरexecका इस्तेमाल करे - array बिना टूटे Git तक पहुँचता है, लेकिन Git dash से शुरू होने वाले argument को option मान लेता है
- यह तब भी हो सकता है जब program
docker buildका CVE-2019-13139 ऐसा ही मामला था, जिसमें Go काos/execऔरargvarray इस्तेमाल हुआ और shell से नहीं गुज़रा- Git context URL का
#ref:dirfragmentgit fetch origin <ref>में पास हुआ, जहाँ<ref>को--upload-pack=<cmd>की तरह समझा गया
- Git context URL का
कई version control systems में दोहराई गई कमजोरी
- अगस्त 2017 में एक ही दिन चार version control systems में यही pattern सार्वजनिक हुआ
- Git का CVE-2017-1000117
- Mercurial का CVE-2017-1000116
- Subversion का CVE-2017-9800
- CVS का CVE-2017-12836
- चारों systems URL के hostname को SSH argument के रूप में पास करते थे, और
-oProxyCommand=से शुरू होने वाला hostname SSH option माना जाता था - Phabricator postmortem के अनुसार उस समय सक्रिय रूप से maintain हो रहे तीन tools में सिर्फ Subversion hostname से पहले
--जोड़ता था- Git और Mercurial hostname format validate करते थे, क्योंकि सभी SSH implementations
--को support नहीं करतीं
- Git और Mercurial hostname format validate करते थे, क्योंकि सभी SSH implementations
--के बिना code argument के dash से शुरू होने तक सामान्य दिखता और काम करता है, इसलिए यह mechanism मूल रूप से unsafe है
package managers तक पहुँचने वाला exposure path
- package managers manifest, lock file और transitive dependency metadata से Git URL या ref लेकर उसे subprocess में पास करते हैं
- Gemfile में
gem 'foo', git: '...' package.jsonमेंgithub:user/repo#refpyproject.toml,Cargo.toml,mix.exs,Package.swift,pubspec.yaml,conanfile.py,go.modमें इसके समकक्ष settings
- Gemfile में
- जुलाई 2026 के HEAD के आधार पर जांचे गए 19 package managers में 17 Git binary को default या एकमात्र path के रूप में चलाते थे
- बाकी दो default रूप से libraries इस्तेमाल करते हैं
- Cargo libgit2 इस्तेमाल करता है और
net.git-fetch-with-cliसक्षम होने पर Git process चलाता है - Poetry 1.2.0 से dulwich पर switch कर चुका है, और
system-git-clientsetting से system Git इस्तेमाल कर सकता है
- Cargo libgit2 इस्तेमाल करता है और
- Nix local repository पढ़ने में libgit2 इस्तेमाल करता है, लेकिन libgit2, git-credential helper को support नहीं करता, इसलिए fetch के लिए Git process चलाता है
- जांच में Bundler, Cargo, CocoaPods, Composer, Conan, Go, Helm, Homebrew, Mix, Nix, npm, pip, pnpm, Poetry, Pub, SwiftPM, uv, vcpkg, Yarn शामिल थे
package managers में दर्ज CVE
- इस तरह सार्वजनिक हुए package manager vulnerabilities में ये मामले शामिल हैं
- Bundler का CVE-2021-43809
- Composer का CVE-2021-29472, CVE-2022-24828
- Poetry का CVE-2022-36069
- pip का CVE-2023-5752
- CocoaPods का CVE-2022-21223, CVE-2022-24440
- Go का CVE-2025-68119
- 2022 की कई vulnerabilities खोजने वाली Snyk ने Git और Mercurial में argument injection पर research प्रकाशित की
- Sonar binary-वार खतरनाक options की सूची बनाए रखता है
वास्तविक defense status और Go का fix
- Git process चलाने वाले 17 package managers में
--end-of-optionsइस्तेमाल करने वाला tool सिर्फ Go काcmd/goथा - Go ने जून 2019 में सामान्य defense hardening के तहत repository URL से पहले
--जोड़ा - जनवरी 2026 में स्पष्ट हुआ कि सिर्फ
--काफी नहीं है, इसलिए CVE-2025-68119 के fix में--end-of-optionsको व्यापक रूप से जोड़ा गया - उसी fix में
HGPLAIN=+strictflagsभी शामिल था- यह setting Mercurial 4.4.2 के 2017 release से Mercurial की शुरुआती option parsing को सीमित करती है
- Go के fix commit में कहा गया कि इस समस्या को दोबारा आने से रोकने के लिए और संरचनात्मक बदलावों की ज़रूरत हो सकती है, लेकिन फिलहाल यह मौजूदा समस्या हल करता है
ज़्यादातर defenses vulnerability disclosure के बाद जोड़ी गईं
- बाकी package managers argument list को बचाने के लिए भी मुख्य रूप से
--या input के leading dash rejection का इस्तेमाल करते हैं - Bundler में
git cloneURL से पहले--, CVE-2021-43809 patch से जोड़ा गया - cocoapods-downloader में leading dash rejection, CVE-2022-21223 के disclosure समय के आसपास मार्च 2022 के दस दिनों में तीन commits से लागू हुआ
- Poetry की defense सितंबर 2021 में जोड़ी गई, एक साल बाद CVE मिला, और छह महीने बाद dulwich पर switch हुआ
- vcpkg अलग मामला है; Git registry support लिखे जाने के पहले दिन से
--इस्तेमाल किया गया
minimum Git version से पैदा होने वाली compatibility constraints
- Composer के CVE-2022-24828 advisory में
--end-of-optionsको सही fix बताया गया, लेकिन पुराने Git versions को support करने की ज़रूरत के कारण dash से शुरू होने वाले branch names को reject करने का रास्ता चुना गया - vcpkg का Git integration minimum version Git 2.7.4 बताता है, और Linux के लिए Homebrew का
HOMEBREW_MINIMUM_GIT_VERSION2018 में सेट किया गया 2.7.0 है - Git 2.14.3 देने वाला Amazon Linux 2, जून 2026 में end-of-life पर पहुँचा, इसलिए जिन distributions का यह lower bound पीछा कर रहा था वे अब जाकर support scope से बाहर हो रहे हैं
- Ubuntu का long-term support status भी एकसमान transition को कठिन बनाता है
- Ubuntu 18.04, Git 2.17.0 देता है और 2028 तक extended support में है
- Ubuntu 20.04, Git 2.25.1 देता है और 2030 तक extended support में है
- Git 2.25.1
git fetchमें--end-of-optionsस्वीकार करता है, लेकिनgit rev-parseमें reject करता है
--end-of-optionsपर निर्भर होने के लिए ज़्यादातर subcommands में Git 2.24.0,rev-parseके लिए 2.30.0, औरcheckoutवresetके लिए 2.43.1 minimum version चाहिए- minimum version बढ़ाने का मतलब है कि distributions के साथ आने वाले पुराने Git इस्तेमाल करने वाले users को support न कर पाना
process execution की जगह Git libraries का उपयोग
- libgit2, gitoxide, go-git, JGit, dulwich process के अंदर clone और fetch के लिए ज़रूरी Git transport protocol implement करते हैं
- अलग
argvboundary नहीं होती, इसलिए argument list में inject करने के लिए कोई target ही नहीं होता - Jujutsu Git integration के लिए gitoxide इस्तेमाल करता है और argument injection प्रकार का कोई सार्वजनिक CVE नहीं है
- अब तक की दो advisories path traversal और library से विरासत में मिले SHA-1 collision check की कमी से जुड़ी हैं
- go-git का CVE-2025-21613 सिर्फ
file://transport तक सीमित है- go-git में यही एकमात्र code path है जहाँ Git binary चलाई जाती है
- अपनी Git implementation शामिल करने का मतलब है upstream Git के checkout safety fixes को लगातार track करना; libgit2 और JGit दोनों में इससे जुड़े fixes बार-बार आए हैं
- यह cost वास्तविक है, लेकिन हर call site पर हमेशा argument validation याद रखने के बजाय मामला ठोस upstream patch flow को अपनाने का बन जाता है
Homebrew के लिए प्रस्तावित बदलाव की सीमा
- Homebrew PR minimum Git version को 2.30.0 तक बढ़ाता है और इन जगहों पर
--end-of-optionsजोड़ता हैclone,remote set-url,ls-remoteमें URL से पहलेrev-parseमें ref से पहले
checkoutऔरresetcalls नहीं बदली गईं- इन दो commands को भी सुरक्षित करने के लिए फरवरी 2024 में जारी Git 2.43.1 चाहिए
- यह version अभी कई supported distributions द्वारा दिए जाने वाले Git से नया है
1 टिप्पणियां
Lobste.rs की राय
खास तौर पर, एक
jjकमांड में सीखी गई बात दूसरी कमांडों पर भी स्वाभाविक रूप से लागू हो जाती है।git logदस्तावेज़ में अलग-अलग output options के flags की भरमार है, ऊपर से commit range syntax की “विशेष notation” और अतिरिक्त filter flags भी आपस में घुले-मिले हैं, और दूसरी Git कमांडों में ट्रांसफ़र होने वाला ज्ञान भी कम हैइसके उलट,
jj logदस्तावेज़ इतना संक्षिप्त है कि एक पेज पर भी जगह बच जाती है। इसने Git की बेतरतीब जटिलता को revision sets, file sets, और output template DSL — इन तीन चीज़ों से बदल दिया है, और ये jj भर में एकसमान तरीके से इस्तेमाल होती हैं, इसलिए यह कहीं अधिक सरल, composable और intuitive लगता है। यह मानना पड़ेगा कि Git ने 20 साल में बहुत सा अतिरिक्त बोझ जमा किया है, लेकिन jj उसे टालने के लिए कहीं बेहतर स्थिति में दिखता है--की ज़रूरत होती है, लेकिन यहाँ अगर अपना अलग variant rule भी माँगा जाए तो यह हद से ज़्यादा ख़तरनाक trap बन जाता है--क्यों चुना गया। फ़ाइलों को explicit arguments के रूप में लेने वाले साधारण तरीके की बजाय इसे चुनने के पीछे कोई छिपा हुआ design trade-off था क्या1990 के दशक की Tcl बनाम Scheme बहस को देखें तो इस मामले में शायद “worse is better” सही था। JSON और XML समेत S-expression परिवार UNIX ecosystem में लगभग जगह नहीं बना सका, जबकि Tcl के पास strings के भीतर sub-languages को layer करने का अपेक्षाकृत सिद्धांतसम्मत तरीका था