OSV 1.4.0 · github-reviewed · 修改于 2026-08-07 23:36
发布时间
2026-08-07 23:36
GitHub 审查时间
2026-08-07 23:36
NVD 发布时间
—
源文件
advisories/github-reviewed/2026/08/GHSA-9rj7-rf2p-w77r/GHSA-9rj7-rf2p-w77r.json
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.
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.
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.
# attacker stages /evil/hooks/post-commit (executable)
from git import Repo
Repo.init(path, template="/evil")
# next commit runs /evil/hooks/post-commit -> ACE
/evil/hooks/post-commit (executable) and gets the app to call Repo.init(path, template='/evil').Repo.init. Bypass proof: base.py:1435 is a bare git.init(**kwargs). argv (observed): ['git','init','--template=/evil']./evil/hooks/post-commit → <repo>/.git/hooks/post-commit.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).
GitPython <= 3.1.57 (unguarded git.init(**kwargs) present verbatim on the latest release tag).
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