The Problem: Git's Double Use of --
Most Unix tools use -- to mark the end of option parsing. rm -- -f removes a file named -f instead of passing the force flag. Git, however, repurposed -- early on to separate revisions from pathspecs. git log main -- README.md means commits on main touching that file. This left the revision position with no terminator. If a script runs git log "$rev" and $rev starts with a dash, git parses it as an option.
The fix came in git 2.24.0 (November 2019): --end-of-options. It signals to git that no more options follow, without the ambiguity of --. But support arrived per subcommand over years:
- git 2.24.0: most builtins
- git 2.30.0:
git rev-parse(its hand-rolled parser) - git 2.43.1 (Feb 2024):
git checkoutandgit reset(they parse--themselves)
Argument Injection: A Known Attack Surface
CWE-88 (argument injection) is distinct from command injection. The wrapping program builds an argv array and calls exec directly, no shell involved. Git then parses an argument as an option because it starts with a dash.
Git, Mercurial, Subversion, and CVS all had CVEs disclosed on the same day in August 2017 (CVE-2017-1000117, etc.). Each passed a URL's hostname to ssh, and a hostname starting with -oProxyCommand= became an ssh option. Phabricator's post-mortem noted that only Subversion added -- before the hostname; git and Mercurial validated the hostname format instead, partly because -- isn't supported by every ssh implementation.
Package Managers: The Gap
Package managers routinely pass git URLs or refs to subprocesses. Of 19 checked, 17 fork git as default. Only Go's cmd/go uses --end-of-options. It added -- before URLs in June 2019, but in January 2026 that proved insufficient, leading to CVE-2025-68119 and the addition of --end-of-options across the board.
Published CVEs include:
- CVE-2021-43809 (Bundler)
- CVE-2021-29472, CVE-2022-24828 (Composer)
- CVE-2022-36069 (Poetry)
- CVE-2023-5752 (pip)
- CVE-2022-21223, CVE-2022-24440 (CocoaPods)
- CVE-2025-68119 (Go)
Most guards were added as vulnerability patches, not original design. Composer's advisory explicitly names --end-of-options as the correct fix but cites support for older git versions.
Minimum Git Versions Block Adoption
Amazon Linux 2 (git 2.14.3) reached EOL last month. Ubuntu 18.04 (git 2.17.0) extended support until 2028. Ubuntu 20.04 (git 2.25.1) supports --end-of-options on git fetch but not on git rev-parse. Relying on the flag means raising minimum git to 2.24.0, 2.30.0, or 2.43.1, losing users on distribution-packaged git.
Git Libraries: No argv, No Injection
libgit2, gitoxide, go-git, JGit, and dulwich implement the wire protocol in-process. Jujutsu (uses gitoxide) has no argument-injection CVEs. go-git's only such CVE (CVE-2025-21613) is on the file:// transport, the one path that spawns git binary.
What to Do Now
If you maintain a tool that forks git with untrusted input:
- Raise minimum git to 2.30.0 (or 2.43.1 if you use checkout/reset)
- Add
--end-of-optionsbefore any untrusted ref or URL - Also set
HGPLAIN=+strictflagsfor Mercurial
The author opened a PR against Homebrew raising minimum git to 2.30.0 and adding --end-of-options before URLs in clone, remote set-url, and ls-remote.



