Aug 7, 2026·8 min read·2 visits
GitPython prior to 3.1.58 allows arbitrary command execution when executing git commands with split_single_char_options=False due to validation desynchronization.
An unsafe option guard bypass vulnerability exists in GitPython before version 3.1.58. When keyword arguments are passed to Git commands with split_single_char_options=False, GitPython's argument validation helper fails to inspect the combined short-option value. This discrepancy allows short-option token smuggling or clustering manipulation, enabling remote attackers to bypass option blocklists and execute arbitrary system commands.
GitPython is an open-source Python library designed to provide a native programmatic interface for interacting with Git repositories. Applications rely on this package to automate complex git operations such as cloning remote repositories, checking out branches, and managing revision histories. The library acts as a high-level wrapper, serializing Python functions and keyword arguments into command-line parameters that are eventually passed to the system's local Git binary via the standard subprocess module.
Because GitPython interacts directly with a shell-executable binary, any application that passes untrusted user input directly to GitPython commands exposes a severe attack surface. To mitigate the risk of parameter injection, GitPython implements an internal security validation layer. This layer checks options against a list of dangerous parameters (such as --upload-pack or -u) that could allow external command execution. If any blocked options are detected, the system raises an exception and halts execution.
This security advisory focuses on a technical flaw in this safety validation logic designated as GHSA-WVPP-8HX9-P66J. The vulnerability is classified under CWE-88 (Improper Neutralization of Argument Delimiters in a Command) and manifests when keyword arguments are formatted with the option split_single_char_options=False. In this configuration, GitPython fails to evaluate combined short-option flags properly, introducing a logic gap that enables unauthenticated remote code execution via short-option smuggling.
When exploitation is successful, an attacker can bypass all internal safety blacklists and force the host operating system to execute arbitrary binaries or scripts. The flaw does not require authentication and can be triggered remotely if an application exposes Git wrappers (such as cloning configurations) to external web inputs. The vulnerability affects all versions of GitPython prior to version 3.1.58.
The underlying root cause of GHSA-WVPP-8HX9-P66J lies in a logical desynchronization between two key internal functions inside GitPython's execution wrapper: transform_kwargs and _option_candidates. The transform_kwargs function is responsible for converting Python keyword arguments into actual string arguments for command-line serialization. Conversely, the _option_candidates function extracts and normalizes these parameters for safety analysis, ensuring they do not match restricted elements in check_unsafe_options.
When developers supply single-character keyword arguments (such as n="value"), the split_single_char_options boolean flag controls how the parameters are serialized. If set to True, the library splits them into discrete arguments: the flag and its parameter (e.g., ["-n", "value"]). If configured to False, the serializer merges them into a single string (e.g., ["-nvalue"]). The core vulnerability is triggered when split_single_char_options=False because _option_candidates and transform_kwargs handle the merged token unsafely.
During argument parsing, _option_candidates extracted only the primary single-character key (e.g., -n) and completely discarded the attached value (e.g., uhelper). Consequently, the safety engine evaluated only the safe -n option, allowing the command to proceed. However, when transform_kwargs subsequently generated the final command string, it created the merged option -nuhelper.
When the resulting argument list is passed to the underlying git binary, the executable parses the combined string according to POSIX short-option clustering rules. Git interprets the string character by character: -n is treated as a safe option, the subsequent u is treated as a nested short option (equivalent to -u or --upload-pack), and the remaining helper string is bound as the argument for -u. By smuggling the unsafe -u option within a benign single-character key, attackers successfully bypass the blocklist.
To understand the exact mechanics of the desynchronization, we analyze the vulnerable implementation of _option_candidates in git/cmd.py alongside the corrective patch implemented in version 3.1.58. The fix was committed under hash 96a888f4d782cb2f80452148e48e60ce4af6d541.
In the vulnerable implementation, the logic for handling keyword arguments inside _option_candidates was as follows:
# Vulnerable logic inside git/cmd.py
key = str(key)
options.append(f"-{key}" if len(key) == 1 else f"--{dashify(key)}")
if len(key) == 1 and split_single_char_options:
options.extend(
str(value)
for value in values
if value is not True and value not in (False, None) and str(value).startswith("-")
)Notice that if split_single_char_options was False, the if condition was skipped entirely. The generator appended only the base flag (-{key}) to the candidate list and ignored value completely. Because the validation engine lacked visibility into the concatenated string, check_unsafe_options remained unaware of the nested command parameters.
To resolve this desynchronization, the developers restructured the conditional branches to handle the split_single_char_options=False scenario explicitly. The patch modified git/cmd.py as follows:
# Patched implementation in git/cmd.py (GitPython >= 3.1.58)
key = str(key)
if len(key) != 1:
options.append(f"--{dashify(key)}")
elif split_single_char_options:
options.append(f"-{key}")
options.extend(
str(value)
for value in values
if value is not True and value not in (False, None) and str(value).startswith("-")
)
else:
# Correctly reconstruct the merged short option for validation
options.extend(
f"-{key}" if value is True else f"-{key}{value}"
for value in values
if value is True or (value is not False and value is not None)
)This new branch ensures that when split_single_char_options=False, the exact string generated for subprocess execution (-{key}{value}) is also appended to the options candidate list. Consequently, passing n="uhelper" now produces the validation candidate -nuhelper. Since the validation engine matches candidates using substring checks, this correctly triggers a blocklist exception on the smuggled u parameter.
The implemented fix is robust for the evaluated single-character path. However, security researchers should note that long option keys (e.g., len(key) != 1) still only append --{dashify(key)} to candidates and do not inspect the associated value parameter in _option_candidates. While Git's parsing of long options is less susceptible to POSIX short-option clustering, developers must ensure that no custom command wrappers treat long-option values as secondary arguments.
Exploiting this vulnerability requires specific environment conditions. First, the target application must utilize GitPython to interact with Git repositories. Second, the application must expose an execution interface where external input directly controls keyword arguments. Third, either the application or the developer's custom configuration must specify split_single_char_options=False during command execution.
Consider a vulnerable Python web application that allows users to clone repositories and configure specific Git flags through a query parameter. The following proof-of-concept script demonstrates how an attacker can leverage this configuration to execute arbitrary system binaries:
# Vulnerable Application Context (GitPython < 3.1.58)
from git import Git
from git.exc import UnsafeOptionError
git_client = Git()
# Malicious payload designed to execute an external helper binary
# under the guise of an 'n' (no-checkout) flag value.
user_supplied_option = "utouch /tmp/pwned;git-upload-pack"
try:
# The application processes arguments with split_single_char_options disabled
git_client.clone(
"https://github.com/example/repo.git",
n=user_supplied_option,
split_single_char_options=False
)
except Exception as e:
print(f"Execution resulted in: {e}")When this script runs, the internal workflow triggers as follows:
This exploitation flow demonstrates how minor desynchronizations in argument tokenization lead directly to complete command-injection pathways, bypassing all intended blacklist validation layers.
The security impact of GHSA-WVPP-8HX9-P66J is critical, carrying an estimated CVSS v3.1 score of 9.8. Because GitPython is widely used in continuous integration and continuous deployment (CI/CD) pipelines, automated build platforms, and developer tooling, an argument injection vulnerability of this nature poses severe risks. An attacker who successfully exploits this flaw achieves unauthenticated remote code execution (RCE) within the context of the running application process.
Depending on the privileges of the host process, RCE can lead to full system compromise, lateral movement within internal networks, and unauthorized access to intellectual property such as source code repositories. In containerized environments, attackers may exploit this vector to escape containers or access cloud metadata services to harvest sensitive credentials.
To mitigate this vulnerability, system administrators and developers must take immediate action. The primary remediation strategy is upgrading the GitPython package to version 3.1.58 or higher, which incorporates the corrected _option_candidates validation logic. Upgrading can be performed via the standard Python package manager:
pip install --upgrade GitPython>=3.1.58If immediate upgrading is not feasible, developers should implement defensive programming workarounds. Avoid disabling split_single_char_options when processing untrusted inputs. Additionally, implement robust input validation filters to reject any keyword values that begin with letters matching dangerous short-options (such as u or c), or strictly sanitize input against alphanumeric character sets. Organizations can also deploy Semgrep static analysis rules within their development pipelines to flag any vulnerable occurrences of split_single_char_options=False in their source code repositories.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
GitPython gitpython-developers | < 3.1.58 | 3.1.58 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-88 |
| Attack Vector | Network |
| CVSS v3.1 | 9.8 (Critical) |
| EPSS Score | N/A |
| Impact | Remote Command Execution (RCE) |
| Exploit Status | Proof of Concept (PoC) |
| CISA KEV Status | Not Listed |
The product constructs a command-line string or command array using input from an upstream source, but it does not neutralize or incorrectly neutralizes argument delimiters, allowing an attacker to supply additional command-line arguments.
CVE-2026-54164 is a class/type confusion vulnerability (CWE-843) in API Platform Core. When processing relationships via Internationalized Resource Identifiers (IRIs) in write requests, the framework's normalizer fails to verify if the resolved resource matches the expected type. For PHP applications utilizing untyped properties, the mismatched object is silently assigned, breaking domain logic and data integrity.
GHSA-WG23-69C2-GJC8 is a critical security vulnerability discovered in the native Passkey (WebAuthn) login implementation of Craft CMS. The vulnerability allows an attacker to bypass WebAuthn's core cryptographic challenge-response and signature-counter replay protections. By intercepting a single successful passkey login request body, an attacker can replay the identical request payload to generate additional authenticated active sessions, resulting in complete account takeover.
An architectural flaw in the Footnote extension of league/commonmark allows unauthenticated remote attackers to trigger severe denial of service conditions through algorithmic complexity exploitation (O(N^2) CPU and memory exhaustion) and path-delimiter injection leading to unexpected application-level crashes.
An algorithmic complexity vulnerability in the UniqueSlugNormalizer component of the league/commonmark PHP library allows unauthenticated remote attackers to trigger severe CPU resource consumption and Denial of Service (DoS) by submitting a Markdown document containing a high volume of duplicate headings. The slug generation loop resets its sequential search index back to 1 for every collision, resulting in a quadratic execution path. This flaw affects versions from 2.0.0-beta1 up to and including 2.8.3, and is patched in version 2.9.0.
A Denial of Service vulnerability exists in the league/commonmark package for PHP when using the XML rendering subsystem. Due to unconstrained indentation based on AST depth, rendering deeply nested elements leads to asymmetric resource consumption (quadratic output size complexity).
Craft CMS contains an authenticated remote code execution vulnerability due to a sanitization bypass in its search condition configuration parser. An attacker with access to the control panel can inject unsafe Yii2 behavior configurations wrapped inside a JSON-encoded string. When decoded and merged by the application, these keys bypass the global config cleanse filter and are evaluated by the Yii2 component factory, leading to arbitrary code execution.