Описание
GitPython: Arbitrary Git Repository Creation Outside the Working Tree via Unvalidated .gitmodules Submodule Name in GitPython
Summary
GitPython computes the on-disk location of a submodule's separate Git directory (.git/modules/<name>) from the submodule's .gitmodules section name with no validation. Because that name is fully attacker-controlled content of a cloned repository, a malicious repository can set a submodule name to a traversal string (e.g. ../../../../home/victim/.something) and cause GitPython to create and initialize a full Git repository at an attacker-chosen filesystem path outside the intended clone directory. The only precondition is that a victim clones the malicious repository with GitPython and runs submodule initialization (submodule_update(init=True) / sm.update(init=True)), a very common and often automatic step. Core Git itself already blocks this exact attack class (CVE-2018-11235), but GitPython's independent reimplementation never adopted an equivalent check.
Details
src/GitPython/git/objects/submodule/util.py sm_name() strips the submodule " / " wrapper from a .gitmodules [submodule "..."] header and returns the result unchecked. Submodule.iter_items() in src/GitPython/git/objects/submodule/base.py reads this via sm_name(sms) and assigns it to sm._name; unlike the submodule path, name is never used for a tree lookup, so it is never implicitly validated. Submodule._module_abspath() then builds osp.join(parent_repo.git_dir, "modules", name) - os.path.join does not normalize ../ sequences. Submodule._clone_repo() passes this value straight to os.makedirs() and to git clone --separate-git-dir=<module_abspath>, creating and populating a full Git repository (objects, refs, hooks, config) at the escaped path. Attack prerequisite: attacker controls a repository the victim clones and initializes submodules for.
PoC
- Environment: Docker image built
FROM python:3.11-slim, withgitinstalled viaapt-get install -y git(Debian bookworm packaged version, described in the advisory as "git 2.x"; the host-side verification separately used system git2.34.1, but no exact version is pinned for the git binary inside this Docker image). GitPython is installed inside the container viapip install /src/GitPythonfrom this repository's own source, which the advisory states resolved to the officially releasedGitPython==3.1.57andgitdb==4.0.12. - Configuration / preconditions: None beyond what's described - the victim must clone the attacker's repository with GitPython and run submodule initialization (
repo.submodules+sm.update(init=True), equivalent togit submodule update --init). - Commands run (quoted verbatim from the advisory's "Confirmed test run" section):
(Per the Dockerfile, docker run executes /work/run_all.sh, which in turn runs build_attacker_repo.sh, then poc_gitpython.py, then poc_control_realgit.sh.)
4. Full source of the PoC script (GHSA/testing/poc_gitpython.py), verbatim:
- Exact captured terminal output (verbatim, from the original advisory's "Confirmed test run (Docker, released package)" section):
- Payload: the attacker rewrites the
.gitmodulessection header from[submodule "legit_dir"]to[submodule "../../../../../../tmp/gitpython_poc_escaped_root/modules_dir"](built bybuild_attacker_repo.sh, part of the harness inGHSA/testing/). The malicious part is the../../../../../../traversal sequence embedded in the submodule name (not the tree-validatedpath), which becomes the on-disk target for the submodule's separate git directory. - Expected vs. observed: A safe implementation (as demonstrated by the real
gitCLI control run) rejects the submodule name with "ignoring suspicious submodule name" and refuses to create anything outside the repository. GitPython instead created the escape-target directory and a fully-initialized Git repository at/tmp/gitpython_poc_escaped_root/modules_dir, confirmed byescape_target exists after update: Trueand its listed contents. - Security impact demonstrated: arbitrary filesystem directory and Git-repository creation at an attacker-chosen absolute path outside the victim's intended clone directory, populated with attacker-controlled content sourced from the submodule's own (also attacker-controlled)
url.
Impact
Path traversal (CWE-22) / external control of file path (CWE-73) leading to arbitrary directory and Git-repository creation outside the intended clone directory. Integrity impact is High (attacker chooses destination path and, via the submodule URL, much of the written content); Confidentiality impact is None (only creation was demonstrated); Availability impact is Low-Medium (disk-exhaustion potential). No authentication is required; the attacker only needs to control a repository the victim clones and initializes submodules for - a routine, often fully-automatic operation in CI pipelines, IDE integrations, and dependency-management tooling.
Ссылки
- https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-hmq2-w58f-27jc
- https://nvd.nist.gov/vuln/detail/CVE-2026-76222
- https://github.com/gitpython-developers/GitPython/pull/2202
- https://github.com/gitpython-developers/GitPython/commit/4299c990e1ca21896f9485277caf7bb0ae5b404c
- https://github.com/gitpython-developers/GitPython/commit/e4b8e7d026ca6abb4cf604f8e77093432ce23c06
- https://github.com/gitpython-developers/GitPython/releases/tag/3.1.58
- https://github.com/pypa/advisory-database/tree/main/vulns/gitpython/PYSEC-2026-3784.yaml
- https://www.vulncheck.com/advisories/gitpython-before-path-traversal-via-gitmodules-submodule-name
Пакеты
GitPython
<= 3.1.57
3.1.58
Связанные уязвимости
GitPython before 3.1.58 fails to validate submodule names from .gitmodules files, allowing attackers to create Git repositories at arbitrary filesystem paths outside the intended clone directory. Attackers can craft malicious repositories with traversal sequences in submodule names that GitPython processes during submodule initialization, creating attacker-controlled Git repositories at escaped filesystem locations.
GitPython before 3.1.58 fails to validate submodule names from .gitmodules files, allowing attackers to create Git repositories at arbitrary filesystem paths outside the intended clone directory. Attackers can craft malicious repositories with traversal sequences in submodule names that GitPython processes during submodule initialization, creating attacker-controlled Git repositories at escaped filesystem locations.
GitPython before 3.1.58 fails to validate submodule names from .gitmodules files, allowing attackers to create Git repositories at arbitrary filesystem paths outside the intended clone directory. Attackers can craft malicious repositories with traversal sequences in submodule names that GitPython processes during submodule initialization, creating attacker-controlled Git repositories at escaped filesystem locations.
GitPython before 3.1.58 fails to validate submodule names from .gitmod ...
Уязвимость функции sm_name() файла src/GitPython/git/objects/submodule/util.py библиотеки Python для взаимодействия с git-репозиториями GitPython, позволяющая нарушителю оказать воздействие на целостность и доступность защищаемой информации