{"id":"CVE-2026-67324","aliases":["GHSA-v396-v7q4-x2qj","PYSEC-2026-3947"],"url":"https://o3.security/vulnerability/CVE-2026-67324","summary":"GitPython 3.1.50 Authentication Bypass via Joined Short Options","details":"`GitPython` version `3.1.50` blocks unsafe `git clone` options such as `--upload-pack`, `-u`, `--config`, and `-c` unless callers explicitly pass `allow_unsafe_options=True`. However, the default unsafe-option gate does not recognize joined short-option forms such as `-u/path/to/helper`.\n\nGit itself accepts `-u<upload-pack>` as the short form of `--upload-pack=<upload-pack>`. As a result, `Repo.clone_from(..., multi_options=[\"-u<helper>\"], allow_unsafe_options=False)` can execute the helper command even though the equivalent long option is blocked.\n\nAffected package:\n\n- Ecosystem: PyPI\n- Package: `GitPython`\n- Confirmed affected version: `3.1.50`\n- Repository: `gitpython-developers/GitPython`\n- Current PyPI version during triage: `3.1.50`\n\nRelevant behavior:\n\n- `Repo.unsafe_git_clone_options` correctly lists `--upload-pack`, `-u`, `--config`, and `-c` as unsafe clone options.\n- `Repo._clone()` splits `multi_options` with `shlex.split(\" \".join(multi_options))` and then calls `Git.check_unsafe_options(...)`.\n- `_canonicalize_option_name(\"-u/path/to/helper\")` returns a string beginning with `u...`, not the canonical short option `u`, so it does not match the blocked `-u` entry.\n- Git accepts the same joined short option as `--upload-pack=<helper>` and executes the helper during clone.\n\nPreconditions:\n\nAn application must pass attacker-influenced clone options into `Repo.clone_from(..., multi_options=...)` while relying on GitPython's default unsafe-option gate to block command-executing options.\n\nThe local PoC uses only a local bare Git repository and a local helper script. It does not contact any third-party service.\n\nLocal reproduction:\n\nThe PoC creates a disposable bare Git repository, a helper script, and a sentinel file path. It first confirms that the long `--upload-pack=<helper>` form is blocked by GitPython. It then calls `Repo.clone_from(..., multi_options=[\"-u<helper>\"], allow_unsafe_options=False)`.\n\nObserved sanitized output:\n\n```text\ngitpython_version=3.1.50\ngit_version=git version 2.53.0.windows.1\ntmp_dir=<tmp>\nlong_upload_pack_gate=BLOCKED:UnsafeOptionError\njoined_short_upload_pack_gate=ALLOWED\nclone_result=EXPECTED_EXCEPTION:GitCommandError\nsentinel_exists=True\nsentinel_text=GITPYTHON_UNSAFE_OPTION_BYPASS\n```\n\nThe clone fails because the helper exits nonzero, but the sentinel file proves that Git executed the helper despite `allow_unsafe_options=False`.\n\nImpact:\n\nAn attacker who controls `multi_options` can bypass GitPython's default `allow_unsafe_options=False` protection and execute a local command via Git's `--upload-pack` / `-u` clone option. This is a residual bypass of an explicit GitPython security boundary, not merely a case where a caller opted into unsafe behavior.\n\nDuplicate / related advisory checks:\n\n- OSV query for `PyPI/GitPython` version `3.1.50` returned no vulnerabilities.\n- The repository's public advisories include related unsafe Git option issues, including `GHSA-x2qx-6953-8485` / `CVE-2026-42284` and `GHSA-rpm5-65cw-6hj4` / `CVE-2026-42215`. Their public affected ranges are marked as fixed before 3.1.50.\n- `GHSA-x2qx-6953-8485` describes validating `multi_options` before `shlex.split(...)`. GitPython 3.1.50 now validates after splitting, but the joined short option `-u<value>` still bypasses because the validator canonicalizes it to `u<value>` rather than `u`.\n- `GHSA-rpm5-65cw-6hj4` describes unsafe underscored kwargs such as `upload_pack=...`. The current PoC uses `multi_options=[\"-u<helper>\"]` against 3.1.50 and does not depend on underscored kwargs.\n- GitHub issue search for `upload-pack unsafe options` found historical related items, including CVE-2022-24439 and the earlier unsafe-options gate work, but no public issue describing this current joined-short-option residual bypass in 3.1.50.\n- GitHub issue search for `multi_options unsafe` found PR #2130, which fixed splitting of `multi_options` before checking. The current issue remains after that split because `-u<value>` is treated as option name `u<value>`, not blocked short option `u`.\n- GitHub issue searches for `u<upload-pack> unsafe` and `-cfoo` returned no results.\n\nSuggested remediation:\n\nWhen checking unsafe Git options, parse joined short options that take values. For clone, `-uVALUE` and `-cKEY=VALUE` should be canonicalized to `u` and `c` respectively before comparing against the unsafe option set.\n\nA safer approach is to maintain command-specific metadata for unsafe short options and recognize the bare option, split form, joined form, and long `--option=<value>` / `--option <value>` forms.","published":"2026-08-01T12:22:18.154Z","modified":"2026-10-21T02:59:02.036392788Z","cvss":null,"epss":{"score":0.0038,"percentile":0.31766,"asOf":"2026-09-17"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"gitpython","fixedVersion":"3.1.51"}],"fix":{"url":"https://github.com/gitpython-developers/GitPython/pull/2162","label":"gitpython-developers/GitPython#2162"},"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/67xxx/CVE-2026-67324.json"},{"type":"ADVISORY","url":"https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-v396-v7q4-x2qj"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-67324"},{"type":"ADVISORY","url":"https://www.vulncheck.com/advisories/gitpython-authentication-bypass-via-joined-short-options"},{"type":"WEB","url":"https://github.com/gitpython-developers/GitPython/pull/2162"},{"type":"PACKAGE","url":"https://github.com/gitpython-developers/GitPython"},{"type":"WEB","url":"https://github.com/gitpython-developers/GitPython/releases/tag/3.1.51"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-21T02:59:02.036392788Z"}}