Know every vulnerabilitybefore it knows you.
DevGuard continuously monitors your dependencies and alerts you when CVEs like this one affect your stack — with real-time threat intelligence built for developers.
GHSA-9rj7-rf2p-w77r
No affected components available
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
The vulnerability can be exploited over the network without needing physical access. It is difficult for an attacker to exploit this vulnerability and may require special conditions. An attacker needs basic access or low-level privileges. No user interaction is needed for the attacker to exploit this vulnerability. The impact is confined to the system where the vulnerability exists. There is a high impact on the confidentiality of the information. There is a high impact on the integrity of the data. There is a high impact on the availability of the system.
Exploitation attempts have been detected. Elevated vigilance and prompt remediation are advised.
Probability that this vulnerability will be exploited in the wild within the next 30 days.
We did not find any exploit available. Neither in GitHub repositories nor in the Exploit-Database.
Browse More
Continuously monitor your dependencies and get alerted when vulnerabilities like this one affect your stack.
Checkout DevGuard