Dulwich: Symlink directory traversal in stash pop allows arbitrary file write via intermediate directory symlinks
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(parent_dir) 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 validate_path() function (line 228) only validates path component names against INVALID_DOTNAMES — it performs zero filesystem symlink detection. On dulwich 1.2.7 (latest release), build_file_from_blob() 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
- Attacker creates a repository with branch
maincontaininglink(symlink →../../.git/hooks) and branchfeaturecontaininglink/post-checkout(executable payload) - Victim clones the repository (landing on
main— symlinklinkexists in worktree) - Victim checks out
feature, makes changes, runsstash.push() - Victim checks out
main(restoring thelinksymlink) - Victim runs
stash.pop(0)— stash containslink/post-checkout os.path.exists("link")returns True (symlink to existing directory),os.makedirsskippedbuild_file_from_blob(blob, mode, "link/post-checkout")→open("link/post-checkout", "wb")follows the intermediate symlink → payload written to.git/hooks/post-checkout- 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(parent_dir) and confirm it stays within the repository root. Alternatively, use os.open() with O_NOFOLLOW on each path component.
Reported by zx (Jace)
Affected software
Click a technology to see all vulnerabilities affecting it.
| Platform | Package | Vulnerable versions | Fixed in |
|---|---|---|---|
| Python (PyPI) | dulwich | >= 0.22.5, < 1.2.8 | 1.2.8 |
References
- CVSS vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H- Weakness (CWE)
CWE-22, CWE-59- Platform
- Python (PyPI)
- Package
dulwich- Disclosed
- 02.10.2026
- Updated
- 11.10.2026 15:18
Sources and licenses
OSV / GitHub Advisory Database - GHSA-cm62-gvxx-vmxx - CC BY 4.0
Vulnerability history: dulwich
All published vulnerabilities of this package (Python (PyPI)), newest first. Shows whether this is a one-off slip or a package that needs watching.
- Total entries
- 13
- First → latest
- 03.2015 10.2026
- Without a fix
- 0
- Exploited in attacks
- 0
Severity breakdown
- Critical 3
- High 7
- Medium 2
- Low 1
Disclosures per year
- 2017: 1
- 2018: 0
- 2019: 0
- 2020: 0
- 2021: 0
- 2022: 0
- 2023: 0
- 2024: 0
- 2025: 0
- 2026: 10
earlier: 2
-
Dulwich: Symlink directory traversal in stash pop allows arbitrary file write via intermediate directory symlinks this entry
Know which vulnerabilities affect your application
With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.