dulwich.porcelain.format_patch(outdir=...) derives each patch filename from the commit's subject line. Prior to this fix, get_summary only replaced spaces with dashes - path separators (/, ), parent-directory components (..), and other filename-hostile characters (e.g. :) were preserved verbatim and passed straight into os.path.join(outdir, f"{i:04d}-{summary}.patch").
A malicious commit subject could therefore direct the generated patch file outside the requested outdir. Reduced examples:
Related issues from the same root cause:
Anyone calling porcelain.format_patch (or the dulwich format-patch CLI) against untrusted commits - for example, a service that runs format-patch over user-supplied repositories or pull requests - could have patch files written to attacker-chosen locations within the process's write permissions.
Fixed in Dulwich 1.2.5. Users should upgrade.
dulwich.patch.get_summary now mirrors git's format_sanitized_subject: only [A-Za-z0-9._] are kept, runs of other characters collapse to a single -, consecutive . collapse to a single ., trailing ./- are stripped, and the result is length-limited. This makes the returned string safe to embed as a filename component, so format_patch can no longer be steered out of outdir via the commit subject.
Until upgrading, callers that pass untrusted commits to porcelain.format_patch can:
| Score | Percentile |
|---|---|
| 0.01% | 1.12% |
| Base score | Version | Severity | Vector |
|---|---|---|---|
| 3.3 | 3.1 | — |
|
| Type | Value |
|---|---|
| GHSA | GHSA-555p-6grf-mh7f ↗ |
| CVE | CVE-2026-47712 ↗ |
| CWE id | Name |
|---|---|
| CWE-22 | Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') |
Vulnerable version ranges and first patched releases as published by GitHub.
| Ecosystem | Package | Vulnerable range | First patched | Vulnerable functions |
|---|---|---|---|---|
| pip | dulwich | >= 0.24.0, < 1.2.5 | 1.2.5 | — |