Patch Forecast
Yellow warning
Plan into this sprint.

GHSA-5fqc-mrg8-w798

Dulwich: Symlink directory traversal in filter-branch index_filter via cross-commit state persistence

Risk score
57/100
CVSS
8.6 v3.1
Published
2 Oct 2026

Open in the live forecast Today's forecast

What to know

What it is
Dulwich's filter_branch.py CommitFilter._apply_index_filter() is vulnerable to symlink directory traversal. When processing commit history, materialized tree entries (including symlinks) persist in the working directory between commits, allowing a symlink from an ancestor commit to redirect file writes from a descenda…
Affected
dulwich (pip) >= 0.23.1, <= 1.2.7
Fix
Upgrade dulwich to 1.2.8 or later.
Exploitation
No known exploitation

Story map

Story map: dulwichTHE FLAWSTHE FIXGHSA-5fqc-mrg8-w798Dulwich: Symlink directorytraversal in filter-branchindex_filter via cross-commit…CVSS 8.6GHSA-8mcx-5rqc-vhmfDulwich: Arbitrary File Write(RCE) on Windows viaUnvalidated Drive Letters in…CVSS 8.8GHSA-8w8g-wq8h-fq33Dulwich: Symlinkwrite-through incheckout(paths=[]) via raw…CVSS 8.6GHSA-cm62-gvxx-vmxxDulwich: Symlink directorytraversal in stash pop allowsarbitrary file write via…CVSS 8.6FixUpgrade dulwich to 1.2.9 orlater.Who is exposeddulwich (pip) < 1.2.9AMBER · PATCH THIS WEEKdulwichdulwich/index.py (Methods:validate_path_element_ntfs,_tree_to_fs_path)dulwich/porcelain/__init__.py(Method:_checked_worktree_path) AHigh-severity Path Traversal…Where it standsPublic proof of conceptCONNECTS TOSame weaknessPath traversal (CWE-22)397 other warnings in 30 days →
Story map: the flaws, the fix, how it unfolded and what it connects to. Boxes link to the record or article.

At a glance

dulwich: Amber, patch this week. dulwich/index.py (Methods: validate_path_element_ntfs, _tree_to_fs_path) dulwich/porcelain/__init__.py (Method: _checked_worktree_path) A High-severity Path Traversal vulnerability exists in Dulwich's checkout logic when running on Windows. The functions responsible for validating NTFS paths strictly reject .git varia…

The flaws

  • GHSA-5fqc-mrg8-w798: Dulwich: Symlink directory traversal in filter-branch index_filter via cross-commit state persistence (CVSS 8.6)
  • GHSA-8mcx-5rqc-vhmf: Dulwich: Arbitrary File Write (RCE) on Windows via Unvalidated Drive Letters in Tree Paths (CVSS 8.8)
  • GHSA-8w8g-wq8h-fq33: Dulwich: Symlink write-through in checkout(paths=[]) via raw os.open bypasses all symlink protections (CVSS 8.6)
  • GHSA-cm62-gvxx-vmxx: Dulwich: Symlink directory traversal in stash pop allows arbitrary file write via intermediate directory symlinks (CVSS 8.6)

The fix

Fix: Upgrade dulwich to 1.2.9 or later.

Who is exposed: dulwich (pip) < 1.2.9

Where it stands

  • Public proof of concept

Connects to

Why it is Yellow

  • CVSS 8.6 high
  • On your watchlist: PyPI

Affected packages

PackageEcosystemVulnerableFixed in
dulwichpip>= 0.23.1, <= 1.2.71.2.8

References

Original description

## Summary Dulwich's `filter_branch.py` `CommitFilter._apply_index_filter()` is vulnerable to symlink directory traversal. When processing commit history, materialized tree entries (including symlinks) persist in the working directory between commits, allowing a symlink from an ancestor commit to redirect file writes from a descendant commit to arbitrary filesystem locations. ## Root Cause `_apply_index_filter()` at `dulwich/filter_branch.py:212` calls `build_index_from_tree(".", tmp_index_path, ...)` which materializes all tree entries to the current working directory. The `finally` block (line 229-230) only cleans up the temporary index file (`os.unlink(tmp_index_path)`) — NOT the filesystem files written to CWD. When `process_commit()` processes parents recursively first (line 260), files materialized from ancestor commits persist and affect processing of descendant commits. On dulwich 1.2.7, `build_file_from_blob()` has no symlink protection, and `validate_path_element` only validates name patterns, not filesystem state. ## Impact An attacker can craft a malicious repository where running `filter_branch` with an index filter writes attacker-controlled content to arbitrary filesystem locations via symlink traversal. This achieves RCE if the write targets `.git/hooks/`. ## Attack Scenario 1. Attacker creates a repository where commit history (linearized) has: - Ancestor commit: tree entry `evil` (mode 120000, symlink → `/target_dir`) - Descendant commit: tree entry `evil/payload` (mode 100644, attacker content) 2. Victim clones repository and runs `filter_branch` with an index filter 3. `process_commit()` processes ancestor first → materializes `evil` as symlink to `/target_dir` in CWD 4. CWD is NOT cleaned between commits 5. Processing descendant: `os.path.exists("./evil")` → True (symlink exists). `build_file_from_blob(blob, mode, "./evil/payload")` → `open("./evil/payload", "wb")` follows intermediate symlink → writes to `/target_dir/payload` ## Suggested Fix Clean the CWD between commit iterations in `_apply_index_filter()`, or verify that no intermediate path components are symlinks before writing files. Reported by **zx (Jace)**

Last activity 2 Oct 2026. Patch Forecast updates every hour.