GHSA-cm62-gvxx-vmxx: Path Traversal
Summary
Dulwich's stash.py:pop() function is vulnerable to symlink directory traversal, allowing an attacker to write arbitrary files outside the repository worktree when a victim pops a stash in a malicious repository.
Root Cause
The pop() function at dulwich/stash.py:236 uses os.path.exists(parentdir) to check if a parent directory exists before writing stashed files. os.path.exists() follows symlinks, so when an intermediate directory in the path is a symlink pointing outside the worktree (e.g., link → ../../.git/hooks), the check passes and subsequent file writes resolve through the symlink.
The validatepath() function (line 228) only validates path component names against INVALIDDOTNAMES — it performs zero filesystem symlink detection. On dulwich 1.2.7 (latest release), buildfilefromblob() has no symlink protection whatsoever.
Impact
An attacker can craft a malicious repository that, when a victim clones it and performs a stash pop operation, writes attacker-controlled content to arbitrary filesystem locations. Writing to .git/hooks/post-checkout achieves Remote Code Execution on the victim's machine on the next git checkout operation.
Attack Scenario
1. Attacker creates a repository with branch main containing link (symlink → ../../.git/hooks) and branch feature containing link/post-checkout (executable payload) 2. Victim clones the repository (landing on main — symlink link exists in worktree) 3. Victim checks out feature, makes changes, runs stash.push() 4. Victim checks out main (restoring the link symlink) 5. Victim runs stash.pop(0) — stash contains link/post-checkout 6. os.path.exists("link") returns True (symlink to existing directory), os.makedirs skipped 7. buildfilefromblob(blob, mode, "link/post-checkout") → open("link/post-checkout", "wb") follows the intermediate symlink → payload written to .git/hooks/post-checkout 8. Next checkout operation triggers the hook → RCE
Suggested Fix
Before writing any file, verify that no component of the target path resolves through a symlink outside the worktree. Use os.path.realpath(parentdir) and confirm it stays within the repository root. Alternatively, use os.open() with ONOFOLLOW on each path component.
Reported by zx (Jace)
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/dulwichto a version that resolves this vulnerability.Fixed in 1.2.8 - Compensating control
Before writing any file during stash pop, resolve the target parent path with os.path.realpath(parent_dir) and verify that it remains within the repository root; alternatively, use os.open() with O_NOFOLLOW on each path component to prevent symlink traversal.
Event History
Frequently Asked Questions
Who is realistically exposed to this issue?
Users of Dulwich 1.2.7 who clone or otherwise use an attacker-controlled repository and then perform a stash pop operation are exposed. Exploitation requires the victim to interact with the malicious repository.
What does an attacker need to do to exploit it?
The attacker needs to craft repository contents so that an intermediate path component is a symlink to a location outside the worktree. When the victim pops the stash, Dulwich follows that symlink while writing the stashed file.
How could this lead to code execution?
An attacker can write controlled content to .git/hooks/post-checkout through the symlink traversal. The hook can then execute on the victim's next git checkout operation.
Which version is explicitly identified as vulnerable?
The provided data explicitly identifies Dulwich 1.2.7 as vulnerable and describes it as the latest release at the time of the advisory. A Dulwich 1.2.8 release is referenced, but the provided data does not explicitly state a complete affected or fixed version range.