GitPython: git-config Option-Name Injection via = and # Characters Enables RCE
An attacker who controls the option name passed to GitPython's config writer can inject arbitrary git-config directives, including core.sshCommand, leading to remote code execution on the next git…

The problem
GitPython's _assure_config_name_safe validator applies its bracket-and-quote state machine only when label == "section". For the "option" label it falls through to a regex that rejects only [\r\n\x00], leaving =, #, ;, spaces, and brackets unblocked.
write_section at config.py:702 writes the option name verbatim into "\t%s = %s\n". An option name containing = touch /tmp/RCE # therefore produces a syntactically valid git-config line where the # comments out the intended value, forging an arbitrary directive.
Any application that forwards a caller-influenced string as the option-name argument to set_value or config_writer is vulnerable.
Proof of concept
A working proof-of-concept for this issue in GitPython, with the exact payload below.
# Attacker controls the option-name argument
with repo.config_writer() as cw:
cw.set_value("core", "sshCommand = touch /tmp/RCE #", "x")
# Results in .git/config line:
# \tsshCommand = touch /tmp/RCE # = x
# git parses this as: core.sshCommand = touch /tmp/RCE
# RCE fires on the next SSH-based git operation.The = character in the option name terminates the key field early. Git then parses sshCommand as the key and touch /tmp/RCE as the value because the trailing # = x is treated as a comment. The root cause is CWE-88/CWE-74: the option-label branch of _assure_config_name_safe never reached the character-class checks that would reject = and #.
The patch (commit a495ccd3b, PR #2204) extends the same forbidden-character set already applied to section names to cover option names as well, raising a ValueError before the name reaches the config writer.
The fix
Upgrade to GitPython 3.1.58. The fix is in commit a495ccd3b547ccd60b2187215823b72a9c0188bf (PR #2204): _assure_config_name_safe now applies the full character-safety check, including rejection of =, #, ;, [, ], and whitespace, to the "option" label as well as "section".
Reported by zx (Jace).
Related research
- high · 8.8GitPython unsafe-option guard bypass via split_single_char_options=False short-option smuggling
- high · 8.1GitPython Argument Injection via Diffable.diff Enables Arbitrary File Overwrite
- high · 8.8GitPython: OS Command Injection via Single-Character Kwarg Value Token Smuggling
- high · 8.4GitPython Command Injection and Arbitrary File Overwrite via Unguarded Git Options