{"id":"GHSA-jm78-9fvv-mhgr","title":"GitPython: git-config OPTION-name injection via =/#/whitespace bypasses name validator, enabling forged core.sshCommand/hooksPath (RCE)","summary":"GitPython: git-config OPTION-name injection via =/#/whitespace bypasses name validator, enabling forged core.sshCommand/hooksPath (RCE)","severity":"high","cvss":8.8,"cwe":["CWE-74","CWE-88"],"vendor":"GitPython","product":"GitPython","ecosystem":"pip","affected":["GitPython <= 3.1.57"],"patched":["GitPython 3.1.58"],"published":"2026-08-07","updated":"2026-08-07","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-jm78-9fvv-mhgr","references":[{"url":"https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-jm78-9fvv-mhgr"},{"url":"https://github.com/gitpython-developers/GitPython/pull/2204"},{"url":"https://github.com/gitpython-developers/GitPython/commit/a495ccd3b547ccd60b2187215823b72a9c0188bf"},{"url":"https://github.com/gitpython-developers/GitPython/releases/tag/3.1.58"},{"url":"https://github.com/advisories/GHSA-jm78-9fvv-mhgr"}],"tags":["ghsa","pip"],"ingestedAt":"2026-08-07T16:14:42.360Z","slug":"GHSA-jm78-9fvv-mhgr","body":"## Overview\n\n## Summary\nGitPython's config-name validator only neutralizes CR/LF/NUL for the `\"option\"` label; it does not reject `=`, `#`, `;`, `[`, `]`, or whitespace in an **option name**. `write_section` writes the option name verbatim into the config file, so an option name such as `sshCommand = touch <cmd> #` is written as `\\tsshCommand = touch <cmd> # = <value>`, which git parses as `core.sshCommand = touch <cmd>` (the trailing `#` comments out the intended value). This forges arbitrary config directives (`core.sshCommand`, `core.hooksPath`, `alias.*`) → RCE on the next git operation. This is a distinct field (option name, not section name) and distinct character class (`=`/`#`/space, not newline/bracket) from GHSA-3rp5-jjmw-4wv2 (section-name bracket injection) and GHSA-mv93-w799-cj2w / GHSA-v87r-6q3f-2j67 (newline injection).\n\n## Root Cause\n`_assure_config_name_safe(name, label)` (`git/config.py:897`) applies the bracket/quote state machine ONLY when `label == \"section\"`; for the `\"option\"` label it falls through with just the `UNSAFE_CONFIG_CHARS_RE = [\\r\\n\\x00]` regex. `write_section` then writes the option name verbatim into `\"\\t%s = %s\\n\"` (config.py:702).\n\n## Impact\nArbitrary git-config directive injection → remote code execution via `core.sshCommand` (fires on any ssh git operation, no staged file needed) or `core.hooksPath` (with a staged hook). Requires the embedding application to forward a caller-influenced OPTION NAME into the config writer (name-control model, the same name-control model accepted by the related published advisories GHSA-3rp5-jjmw-4wv2 and GHSA-mv93-w799-cj2w). Default configuration.\n\n## Proof of Concept\n```python\nwith repo.config_writer() as cw:\n    cw.set_value(\"core\", \"sshCommand = touch /tmp/RCE #\", \"x\")\n# git config --get core.sshCommand  ->  touch /tmp/RCE\n```\n\n## Attack Chain\n1. Entry: app calls config writer with attacker-controlled OPTION name: `set_value(\"core\", \"sshCommand = touch /tmp/RCE #\", \"x\")`.\n2. Check: `_assure_config_name_safe(option, \"option\")` @ config.py. Guard: regex matches only `[\\r\\n\\x00]`; bracket/quote state machine is gated on `label==\"section\"`. Bypass proof: `=`,`#`,space pass → no `ValueError`.\n3. Sink: `write_section` writes `\"\\tsshCommand = touch /tmp/RCE # = x\\n\"` (config.py:702).\n4. Impact: git parses `core.sshCommand=touch /tmp/RCE` → arbitrary code execution on next git op.\n\n## Bypass Evidence\nIndependently reproduced (gate harness): `set_value('core','sshCommand = touch <RCE> #','x')` → no `ValueError`; file line `sshCommand = touch <RCE> # = x`; `git config --get core.sshCommand` → `touch <RCE>` (rc=0). Also verified `core.hooksPath` via both `GitConfigParser` and `repo.config_writer()`. Fix-commit read: bracket/quote checks are inside `if label == \"section\"`; the `\"option\"` label is not covered.\n\n## Affected Versions\n`GitPython <= 3.1.57` (validator present verbatim on the latest release tag).\n\n## Suggested Fix\nApply the section-name safety checks (reject `=`, `#`, `;`, `[`, `]`, whitespace) to the `\"option\"` label as well, or validate the fully-rendered config line after substitution.\n\n---\nReported by **zx (Jace)** — GitHub: @manus-use\n\n## Affected packages\n\n- `GitPython <= 3.1.57`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `GitPython 3.1.58`","depth":"twilight","depthScore":48,"depthScoreParts":{"impact":48.4,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}