Action not permitted
Modal body text goes here.
Modal Title
Modal Body
PYSEC-2026-3995
Vulnerability from pysec - Published: 2026-08-13 12:17 - Updated: 2026-09-29 08:45GitPython versions before 3.1.54 contain an arbitrary file overwrite vulnerability in the Diffable.diff method that fails to validate git options passed through kwargs. Attackers can supply the --output argument via the other parameter or output kwarg to write patch content to attacker-chosen file paths at process privilege level.
| Name | purl | gitpython | pkg:pypi/gitpython |
|---|
{
"affected": [
{
"ecosystem_specific": {},
"package": {
"ecosystem": "PyPI",
"name": "gitpython",
"purl": "pkg:pypi/gitpython"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.1.54"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"0.1.7",
"0.2.0-beta1",
"0.3.0-beta1",
"0.3.0-beta2",
"0.3.1-beta2",
"0.3.2",
"0.3.2.1",
"0.3.2.RC1",
"0.3.3",
"0.3.4",
"0.3.5",
"0.3.6",
"0.3.7",
"1.0.0",
"1.0.1",
"1.0.2",
"2.0.0",
"2.0.1",
"2.0.2",
"2.0.3",
"2.0.4",
"2.0.5",
"2.0.6",
"2.0.7",
"2.0.8",
"2.0.9",
"2.0.9.dev0",
"2.0.9.dev1",
"2.1.0",
"2.1.1",
"2.1.10",
"2.1.11",
"2.1.12",
"2.1.13",
"2.1.14",
"2.1.15",
"2.1.2",
"2.1.3",
"2.1.4",
"2.1.5",
"2.1.6",
"2.1.7",
"2.1.8",
"2.1.9",
"3.0.0",
"3.0.1",
"3.0.2",
"3.0.3",
"3.0.4",
"3.0.5",
"3.0.6",
"3.0.7",
"3.0.8",
"3.0.9",
"3.1.0",
"3.1.1",
"3.1.10",
"3.1.11",
"3.1.12",
"3.1.13",
"3.1.14",
"3.1.15",
"3.1.16",
"3.1.17",
"3.1.18",
"3.1.19",
"3.1.2",
"3.1.20",
"3.1.22",
"3.1.23",
"3.1.24",
"3.1.25",
"3.1.26",
"3.1.27",
"3.1.28",
"3.1.29",
"3.1.3",
"3.1.30",
"3.1.31",
"3.1.32",
"3.1.33",
"3.1.34",
"3.1.35",
"3.1.36",
"3.1.37",
"3.1.38",
"3.1.4",
"3.1.40",
"3.1.41",
"3.1.42",
"3.1.43",
"3.1.44",
"3.1.45",
"3.1.46",
"3.1.47",
"3.1.48",
"3.1.49",
"3.1.5",
"3.1.50",
"3.1.51",
"3.1.52",
"3.1.53",
"3.1.6",
"3.1.7",
"3.1.8",
"3.1.9"
]
}
],
"aliases": [
"CVE-2026-73624",
"GHSA-fjr4-x663-mwxc"
],
"details": "GitPython versions before 3.1.54 contain an arbitrary file overwrite vulnerability in the Diffable.diff method that fails to validate git options passed through kwargs. Attackers can supply the --output argument via the other parameter or output kwarg to write patch content to attacker-chosen file paths at process privilege level.",
"id": "PYSEC-2026-3995",
"modified": "2026-09-29T08:45:48.211663Z",
"published": "2026-08-13T12:17:27.617Z",
"references": [
{
"type": "ADVISORY",
"url": "https://www.vulncheck.com/advisories/gitpython-before-arbitrary-file-overwrite-via-diff"
},
{
"type": "EVIDENCE",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
}
],
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
BREW-OPENTIMESTAMPS-CLIE… (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:30 – Updated: 2026-09-30 09:27 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.61",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "opentimestamps-client",
"purl": "pkg:brew/opentimestamps-client"
},
"ranges": [
{
"events": [
{
"introduced": "0.7.2"
},
{
"fixed": "0.7.2_4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.61",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.61"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-opentimestamps-client-CVE-2026-73624",
"modified": "2026-09-30T09:27:56Z",
"published": "2026-08-14T09:30:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-OTTERDOG-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:30 – Updated: 2026-09-30 09:29 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "otterdog",
"purl": "pkg:brew/otterdog"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.1"
},
{
"fixed": "1.3.4_2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-otterdog-CVE-2026-73624",
"modified": "2026-09-30T09:29:35Z",
"published": "2026-08-14T09:30:57Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-PYGITUP-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:35 – Updated: 2026-09-30 19:32 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "pygitup",
"purl": "pkg:brew/pygitup"
},
"ranges": [
{
"events": [
{
"introduced": "1.5.0"
},
{
"fixed": "2.4.0_4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-pygitup-CVE-2026-73624",
"modified": "2026-09-30T19:32:46Z",
"published": "2026-08-14T09:35:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-SHALLOW-BACKUP-CVE-… (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:39 – Updated: 2026-10-01 09:04 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "shallow-backup",
"purl": "pkg:brew/shallow-backup"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.1"
},
{
"fixed": "6.6_4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-shallow-backup-CVE-2026-73624",
"modified": "2026-10-01T09:04:07Z",
"published": "2026-08-14T09:39:16Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-SNAKEMAKE-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:39 – Updated: 2026-09-30 11:03 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "snakemake",
"purl": "pkg:brew/snakemake"
},
"ranges": [
{
"events": [
{
"introduced": "5.5.3"
},
{
"fixed": "9.23.1_2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-snakemake-CVE-2026-73624",
"modified": "2026-09-30T11:03:18Z",
"published": "2026-08-14T09:39:19Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-SNOWFLAKE-CLI-CVE-2… (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:40 – Updated: 2026-09-30 09:56 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "snowflake-cli",
"purl": "pkg:brew/snowflake-cli"
},
"ranges": [
{
"events": [
{
"introduced": "3.4.1"
},
{
"fixed": "3.24.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-snowflake-cli-CVE-2026-73624",
"modified": "2026-09-30T09:56:04Z",
"published": "2026-08-14T09:40:25Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-STANDARDEBOOKS-CVE-… (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:44 – Updated: 2026-09-30 08:58 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.59",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "standardebooks",
"purl": "pkg:brew/standardebooks"
},
"ranges": [
{
"events": [
{
"introduced": "2.9.2"
},
{
"fixed": "4.0.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.59",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.59"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-standardebooks-CVE-2026-73624",
"modified": "2026-09-30T08:58:58Z",
"published": "2026-08-14T09:44:16Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-TACH-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:45 – Updated: 2026-09-30 09:31 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "tach",
"purl": "pkg:brew/tach"
},
"ranges": [
{
"events": [
{
"introduced": "0.19.7"
},
{
"fixed": "0.35.0_2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-tach-CVE-2026-73624",
"modified": "2026-09-30T09:31:42Z",
"published": "2026-08-14T09:45:05Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-TARTUFO-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:45 – Updated: 2026-10-01 11:08 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.62",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "tartufo",
"purl": "pkg:brew/tartufo"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0"
},
{
"fixed": "6.0.0_4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.62",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.62"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-tartufo-CVE-2026-73624",
"modified": "2026-10-01T11:08:05Z",
"published": "2026-08-14T09:45:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
BREW-TERN-CVE-2026-73624 (GHSA-FJR4-X663-MWXC)
Vulnerability from osv_homebrew – Published: 2026-08-14 09:45 – Updated: 2026-09-30 10:50 – Source websiteSummary
Diffable.diff() forwards **kwargs straight into diff/diff_tree with no check_unsafe_options guard. Diffable is mixed into Commit, Tree, IndexFile, and Submodule, giving a broad surface. git diff --output=<path> writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.
Root Cause
diff.py:188-283 builds and runs the diff command with no check_unsafe_options anywhere in the method (grep-confirmed). Additionally diff.py:265 does args.insert(0, other), placing the caller-supplied other ref BEFORE the -- separator, so a value of --output=/path is parsed by git as an option — a value-only control path requiring no kwarg key.
Impact
Overwrite/corrupt any file at process privilege with attacker-chosen path (e.g. ~/.ssh/authorized_keys, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill's rule, controlling WHICH file is overwritten = I:H regardless of content constraints.
Proof of Concept
# Key-control:
commit.diff(other_commit, output='/home/app/.ssh/authorized_keys') # victim overwritten with diff (105 bytes verified)
# Value-control (attacker controls only the ref string):
commit.diff(other='--output=/home/app/.ssh/authorized_keys') # 14-byte victim -> 146 bytes of diff-tree output
Attack Chain
- Entry (value-control):
commit.diff(other=<user ref>)withother = "--output=/home/app/.ssh/authorized_keys". Guard: none inDiffable.diff. Bypass proof: nocheck_unsafe_optionsin the method body (grep);otherinserted pre---at diff.py:265. - Sink:
git diff-tree <sha> --output=/home/app/.ssh/authorized_keys -r ...-> git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.
Bypass Evidence
Live-verified on HEAD (tag 3.1.53): both key-control (output=) and value-control (other='--output=...') overwrote a victim file with real diff-tree content; argv confirmed ['git','diff-tree','<sha>','--output=/victim','-r',...]. This is the same value-control model GHSA-956x deemed fix-worthy for iter_commits(rev='--output=') — but diff is a distinct, unguarded sink NOT touched by that fix.
Affected Versions
<= 3.1.53
Suggested Fix
Add check_unsafe_options to Diffable.diff (mirroring iter_commits/archive), and/or place --end-of-options before the other ref so it cannot be parsed as an option.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"ecosystem_specific": {
"fix": null,
"range_state": "affected",
"resource": "gitpython",
"resource_purl": "pkg:pypi/gitpython@3.1.45",
"upstream_fixed_in": "3.1.54"
},
"package": {
"ecosystem": "Homebrew",
"name": "tern",
"purl": "pkg:brew/tern"
},
"ranges": [
{
"events": [
{
"introduced": "0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/gitpython@3.1.45",
"name": "gitpython",
"resource": "gitpython",
"strategy": "registry",
"subject_version": "3.1.45"
}
]
},
"details": "## Summary\n`Diffable.diff()` forwards `**kwargs` straight into `diff`/`diff_tree` with **no** `check_unsafe_options` guard. `Diffable` is mixed into `Commit`, `Tree`, `IndexFile`, and `Submodule`, giving a broad surface. `git diff --output=\u003cpath\u003e` writes real patch content to an attacker-chosen path, enabling arbitrary file overwrite.\n\n## Root Cause\n`diff.py:188-283` builds and runs the diff command with no `check_unsafe_options` anywhere in the method (grep-confirmed). Additionally `diff.py:265` does `args.insert(0, other)`, placing the caller-supplied `other` ref BEFORE the `--` separator, so a value of `--output=/path` is parsed by git as an option \u2014 a value-only control path requiring no kwarg key.\n\n## Impact\nOverwrite/corrupt any file at process privilege with attacker-chosen path (e.g. `~/.ssh/authorized_keys`, configs, lockfiles). Content is real diff/patch bytes (attacker-influenced). Per the skill\u0027s rule, controlling WHICH file is overwritten = I:H regardless of content constraints.\n\n## Proof of Concept\n```python\n# Key-control:\ncommit.diff(other_commit, output=\u0027/home/app/.ssh/authorized_keys\u0027) # victim overwritten with diff (105 bytes verified)\n# Value-control (attacker controls only the ref string):\ncommit.diff(other=\u0027--output=/home/app/.ssh/authorized_keys\u0027) # 14-byte victim -\u003e 146 bytes of diff-tree output\n```\n\n## Attack Chain\n1. Entry (value-control): `commit.diff(other=\u003cuser ref\u003e)` with `other = \"--output=/home/app/.ssh/authorized_keys\"`. Guard: none in `Diffable.diff`. Bypass proof: no `check_unsafe_options` in the method body (grep); `other` inserted pre-`--` at diff.py:265.\n2. Sink: `git diff-tree \u003csha\u003e --output=/home/app/.ssh/authorized_keys -r ...` -\u003e git opens+truncates the target then writes diff content. Impact: overwrite/corrupt any file at process privilege (attacker chooses the path). Verified argv and victim overwrite live.\n\n## Bypass Evidence\nLive-verified on HEAD (tag 3.1.53): both key-control (`output=`) and value-control (`other=\u0027--output=...\u0027`) overwrote a victim file with real diff-tree content; argv confirmed `[\u0027git\u0027,\u0027diff-tree\u0027,\u0027\u003csha\u003e\u0027,\u0027--output=/victim\u0027,\u0027-r\u0027,...]`. This is the same value-control model GHSA-956x deemed fix-worthy for `iter_commits(rev=\u0027--output=\u0027)` \u2014 but `diff` is a distinct, unguarded sink NOT touched by that fix.\n\n## Affected Versions\n`\u003c= 3.1.53`\n\n## Suggested Fix\nAdd `check_unsafe_options` to `Diffable.diff` (mirroring `iter_commits`/`archive`), and/or place `--end-of-options` before the `other` ref so it cannot be parsed as an option.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "BREW-tern-CVE-2026-73624",
"modified": "2026-09-30T10:50:19Z",
"published": "2026-08-14T09:45:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-fjr4-x663-mwxc"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/pull/2180"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/commit/1d51b891d7f236044a6aa17498ec682b63dad6e6"
},
{
"type": "PACKAGE",
"url": "https://github.com/gitpython-developers/GitPython"
},
{
"type": "WEB",
"url": "https://github.com/gitpython-developers/GitPython/releases/tag/3.1.54"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "GitPython: Arbitrary file overwrite via git diff --output argument injection in Diffable.diff (key- and value-controlled)",
"upstream": [
"GHSA-fjr4-x663-mwxc",
"CVE-2026-73624",
"PYSEC-2026-3995"
]
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.