Sep 8, 2026·6 min read·4 visits
GitPython failed to block the `--separate-git-dir` parameter during cloning operations, allowing attackers to write arbitrary git repository directories and potentially execute arbitrary code.
GitPython prior to version 3.1.59 contains a path traversal vulnerability via parameter injection. The clone denylist did not restrict the `--separate-git-dir` option, allowing attackers to write repository metadata to arbitrary system paths.
GitPython is a Python library used to interact with Git repositories by acting as a process wrapper for the system's git command-line binary. This architecture requires strict input validation because raw command parameters passed to Git can modify execution behavior or perform file operations outside the intended working directory. To protect applications, GitPython implements parameter denylists to block dangerous options from being executed.
The vulnerability identified as CVE-2026-78677 resides in the library's cloning filters. Specifically, the library failed to block the dangerous --separate-git-dir option inside the unsafe_git_clone_options denylist. Because of this omission, applications that accept remote inputs or user-controlled configuration parameters and pass them to clone functions are susceptible to path traversal.
The vulnerability affects all versions of GitPython prior to version 3.1.59. If successfully exploited, attackers can write repository metadata to arbitrary locations on the local filesystem. This capability can lead to unauthorized directory creation, configuration manipulation, and potential arbitrary code execution.
The root cause of CVE-2026-78677 is the missing entry for the --separate-git-dir option inside GitPython's clone-specific safety filter. When invoking cloning operations via Repo.clone() or Repo.clone_from(), the library checks the user-provided arguments against a hardcoded list of unsafe parameters. If a parameter matches the denylist, an UnsafeOptionError is thrown, unless allow_unsafe_options is explicitly set to True.
Because the option --separate-git-dir was omitted from unsafe_git_clone_options, GitPython allowed this option to bypass the safety check. The command execution engine built the git shell command containing the unchecked parameter. Interestingly, the library already blocked this parameter in other contexts, such as unsafe_git_init_options for repository initialization, illustrating an inconsistency in the filter implementation.
The --separate-git-dir parameter instructs the git binary to store the repository's database, objects, refs, and configuration at a path separate from the actual working directory. Instead of creating a standard .git folder inside the clone target, git writes a plaintext .git file referencing the external path. This behavior allows attackers to write repository files to any directory where the executing process has write permissions.
The vulnerability is located in git/repo/base.py, where unsafe_git_clone_options is defined. In vulnerable versions, this array only contained -c, --template, and --bundle-uri. The commit b68afff45af0f49e79a3e2d2162018986b37ad5d resolved this issue by appending the --separate-git-dir option to the denylist.
Below is the diff showing the addition of the validation filter:
# git/repo/base.py
class Repo:
unsafe_git_clone_options = [
"-c",
# Can install hooks that execute during clone:
"--template",
+ # Redirects the repository metadata to a caller-controlled path:
+ "--separate-git-dir",
# Fetches from an additional caller-controlled URI:
"--bundle-uri",
]To support submodule initialization, which utilizes --separate-git-dir internally, the developers had to adjust git/objects/submodule/base.py. The update checks user-provided options against the denylist before programmatically injecting the required argument:
# git/objects/submodule/base.py
if cls._need_gitfile_submodules(repo.git):
+ if not allow_unsafe_options:
+ Git.check_unsafe_options(Git._option_candidates([], kwargs), repo.unsafe_git_clone_options)
+ multi_options = kwargs.get("multi_options")
+ if multi_options:
+ Git.check_unsafe_options(
+ shlex.split(" ".join(cast("Sequence[str]", multi_options))),
+ repo.unsafe_git_clone_options,
+ )
+ allow_unsafe_options = True
kwargs["separate_git_dir"] = module_abspathExploitation of CVE-2026-78677 requires a target application to expose parameters of Repo.clone() or Repo.clone_from() to user input. This input can be provided via API calls, config files, or custom command structures where user-controlled dictionaries are unpacked as keyword arguments. If the application passes these arguments directly to GitPython, the validation bypass can be achieved.
To execute the attack, the adversary provides the parameter separate_git_dir mapped to a target filesystem path, such as a web directory or a system configuration path. The git process executes and creates the metadata structure at the specified target directory. The primary payload is written to the remote repository, which is cloned during the process.
Once the repository metadata is placed in the designated path, the attacker can exploit downstream triggers. By placing specific configurations or git hooks inside the target directory, the attacker can force code execution. When the local application or system runs subsequent git commands on that repository, the malicious hooks are invoked automatically.
The impact of CVE-2026-78677 is evaluated as High, with a CVSS v3.1 base score of 7.5 and a CVSS v4.0 score of 8.7. The primary hazard is path traversal leading to arbitrary directory and file write operations on the local host. Because the execution is driven by git, the file creation inherits the permissions of the application process running the GitPython library.
In multi-tenant environments, such as continuous integration (CI) platforms, source code hosting services, or automated analysis pipelines, this vulnerability allows sandbox escape. By writing files outside the designated workspace, attackers can overwrite configuration files, replace source code, or pollute web assets. This capability directly leads to system compromise.
Furthermore, because git metadata directories contain executable hooks (such as post-checkout or pre-commit), directing the metadata to a known directory can result in arbitrary code execution. When the host environment runs subsequent commands that interact with the corrupted repository directory, the configured hooks run local scripts automatically under the context of the executing user.
The primary remediation strategy is upgrading GitPython to version 3.1.59 or later. This release adds --separate-git-dir to the global cloning denylist, effectively blocking unauthorized directory redirection. If upgrading is not immediately possible, organizations should sanitize all user-supplied inputs to filter out keys resembling separate_git_dir or separate-git-dir.
A critical review of the patch in git/objects/submodule/base.py reveals a potential parsing discrepancy. The validation of multi_options relies on joining list elements with spaces and then parsing them with shlex.split. If an attacker can inject custom quotes or spaces into the list elements, the behavior of shlex.split might deviate from the underlying shell interpreter.
To ensure complete protection, developers should avoid forwarding untrusted, raw keyword arguments or list configurations directly to GitPython's process wrappers. Implementing a strict schema validation layer on the application side provides a defense-in-depth barrier against parameter injection variants.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
GitPython gitpython-developers | < 3.1.59 | 3.1.59 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network |
| CVSS Score | 7.5 (v3.1) / 8.7 (v4.0) |
| EPSS Score | 0.0043 (0.43%) |
| Impact | Path Traversal, Remote Code Execution (RCE) |
| Exploit Status | poc |
| KEV Status | Not Listed |
The product uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize elements within the pathname that can cause the pathname to resolve to a location outside of the restricted directory.
A command-line option injection vulnerability in GitPython allows low-privilege or unauthenticated actors to read arbitrary local files. The flaw resides in the TagReference.create() function, which fails to evaluate positional arguments against the library's unsafe-option denylist, enabling the execution of native git commands with injected option flags.
CVE-2026-72925 is a critical vulnerability in the SWC HTML minifier (@swc/html and swc_html_minifier) where safe Unicode-escaped characters in embedded JSON script tags are normalized into raw, unescaped characters during optimization, causing browser-side HTML injection and Cross-Site Scripting.
A critical logical flaw in the Natural Language Toolkit (NLTK) allows attackers to bypass the application-level directory sandbox. This vulnerability enables unauthenticated directory enumeration and arbitrary local file or SQLite database access.
An improper integrity verification vulnerability exists in the Natural Language Toolkit (NLTK) library up to and including version 3.9.4. The library's download utility writes remote ZIP packages directly to disk and extracts their contents onto the filesystem before executing cryptographic checksum validation. An attacker capable of intercepting or manipulating the download stream can exploit this behavior to perform arbitrary file writes, directory traversal, or execute untrusted serialized content.
A critical Server-Side Request Forgery (SSRF) bypass vulnerability exists in CodeWhale before version 0.8.64 (and version 0.8.41 in the 0.8.x branch) due to a Time-of-Check to Time-of-Use (TOCTOU) bug in its DNS pre-flight validation mechanism. By returning a temporary resolution failure during validation and subsequently resolving to restricted IPs during HTTP execution, attackers can bypass security rules.
An argument injection vulnerability in CodeWhale (CVE-2026-75912 / GHSA-c6mw-8xh8-gpq6) allows unauthenticated remote attackers to execute arbitrary option commands on the git binary. By passing malicious command-line flags inside git_blame and git_show tool helper functions, an attacker can bypass typical access controls to read arbitrary local system files via the underlying git process.