В git есть малоизвестный флаг --end-of-options. Его добавили ещё в ноябре 2019 года в версии 2.24.0, но многие о нём просто не знают. Проблема в том, что в большинстве Unix-утилит -- означает конец опций: rm -- -f удалит файл с именем -f, а не выполнит принудительное удаление. Но в git двойное тире занято — оно разделяет ревизии и пути (pathspecs). git log main -- README.md означает коммиты на ветке main, затрагивающие файл README.md. А вот позиция ревизии осталась без терминатора: если в git log "$rev" переменная $rev начинается с тире, git воспримет её как опцию. Это и стало причиной появления --end-of-options — разделителя между опциями и ревизиями.
Эта штука критична для безопасности. Многие программы — особенно пакетные менеджеры — передают непроверенные URL и refs из манифестов напрямую в git. Если такой URL начинается с тире, он превращается в опцию. Есть целый класс уязвимостей — CWE-88, аргумент-инъекция. Это не команда-инъекция, оболочка тут ни при чём: программа собирает массив argv и вызывает exec. CVE-2019-13139 в docker build — классика: URL с фрагментом #ref:dir добрался до git fetch origin <ref> как --upload-pack=<cmd>.
Из 19 проверенных пакетных менеджеров 17 форкают бинарник git. Только один из них использует --end-of-options — Go (cmd/go). Он сначала добавил -- перед URL в июне 2019, но в январе 2026 этого оказалось мало, и пришлось ставить --end-of-options повсеместно как фикс для CVE-2025-68119. Остальные менеджеры либо используют --, либо просто проверяют входные строки на ведущее тире. И почти всегда это заплатка для конкретной CVE, а не предусмотрительность. Composer, например, прямо пишет в advisory: правильный фикс — --end-of-options, но он поддерживает древние версии git, поэтому просто банит ветки, начинающиеся с тире.
Минимальная версия git — отдельная боль. --end-of-options требует 2.24.0 для большинства команд, 2.30.0 для git rev-parse и 2.43.1 для checkout и reset. Ubuntu 18.04 с git 2.17.0 ещё в extended support до 2028, Ubuntu 20.04 с 2.25.1 — до 2030. Поднять минималку — отрезать кучу пользователей.
Альтернатива — не форкать git, а использовать библиотеки: libgit2, gitoxide, go-git, JGit, dulwich. У них нет аргументной инъекции, потому что нет границы argv. У go-git есть CVE-2025-21613 — и она как раз на том единственном участке кода, где он форкает git (транспорт file://). Правда, библиотеки тоже требуют патчинга: за каждым релизом git нужно тянуться.
Автор даже открыл PR в Homebrew — поднять минимальный git до 2.30.0 и добавить --end-of-options перед URL в clone, remote set-url и ls-remote, а также перед refs в rev-parse. checkout и reset пока не трогают — для них нужна версия 2.43.1, а это слишком свежо для многих дистрибутивов.