GHSA-9rj7-rf2p-w77r
HIGHGHSA-9rj7-rf2p-w77r is a high-severity (CVSS 7.5) remote code execution vulnerability in gitpython. O3 Security confirms whether GHSA-9rj7-rf2p-w77r is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
GitPython: Unguarded git option forwarding in Repo.init enables arbitrary command execution via --template clone hooks
Blast Radius
gitpythonReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Repo.init() forwards **kwargs verbatim to git init with no unsafe-option guard and no allow_unsafe_options parameter. git init --template=<dir> copies <dir>/hooks/* into the new repo's .git/hooks, so an attacker-controlled template kwarg plants a hook that executes on the next git operation → arbitrary code execution. --template is already recognized as unsafe for clone (it is on unsafe_git_clone_options, and GHSA-6p8h-3wgx-97gf covers the clone path), but Repo.init is a distinct method that never received a guard and needs an independent fix.
Root Cause
Repo.init(path, mkdir, odbt, expand_vars, **kwargs) is a bare git.init(**kwargs) (git/repo/base.py:1435) with no check_unsafe_options and no allow_unsafe_options.
Impact
Arbitrary code execution (hook fires on next git op) at the privileges of the host process. Two preconditions raise attack complexity (AC:H): the app must forward a template= kwarg (KEY control) AND the attacker must stage an executable hook directory at a known path — the same profile GHSA-6p8h-3wgx-97gf accepted as HIGH for the clone path. Default allow_unsafe_options is irrelevant here because Repo.init has no guard at all.
Proof of Concept
# attacker stages /evil/hooks/post-commit (executable)
from git import Repo
Repo.init(path, template="/evil")
# next commit runs /evil/hooks/post-commit -> ACE
Attack Chain
- Entry: attacker stages
/evil/hooks/post-commit(executable) and gets the app to callRepo.init(path, template='/evil'). - Check: NONE on
Repo.init. Bypass proof: base.py:1435 is a baregit.init(**kwargs). argv (observed):['git','init','--template=/evil']. - Sink: git copies
/evil/hooks/post-commit→<repo>/.git/hooks/post-commit. - Impact: next commit runs the hook → arbitrary code execution.
Bypass Evidence
Independently reproduced (gate harness): Repo.init(dst, template='<evil>') → argv ['git','init','--template=<evil>'] unguarded; hook copied into .git/hooks/post-commit; after git commit the INIT_ACE marker was created. --separate-git-dir=<path> is a parallel arbitrary-redirect vector through the same unguarded sink (value control only).
Affected Versions
GitPython <= 3.1.57 (unguarded git.init(**kwargs) present verbatim on the latest release tag).
Suggested Fix
Add a check_unsafe_options guard (with an allow_unsafe_options parameter) to Repo.init, consulting a denylist that includes --template and --separate-git-dir (path-taking / hook-installing options).
Reported by zx (Jace) — GitHub: @manus-use
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | gitpython | all versions | 3.1.58 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for gitpython. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update gitpython to 3.1.58 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-9rj7-rf2p-w77r is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-9rj7-rf2p-w77r is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-9rj7-rf2p-w77r. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-9rj7-rf2p-w77r in your dependencies?
O3 detects GHSA-9rj7-rf2p-w77r across PyPI dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.