VAITP Dataset

← Back to the dataset

CVE-2026-47712

Dulwich path traversal via unsanitized commit subjects in format_patch.

  • CVSS 3.3
  • CWE-22
  • Input Validation and Sanitization
  • Remote

Dulwich is a pure-Python implementation of the Git file formats and protocols. Starting in version 0.24.0 and prior to version 1.2.5, 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. This is fixed in Dulwich 1.2.5. Users should upgrade to 1.2.5 or later. 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 use stdout=True and write the patch to a destination they control, rather than letting format_patch choose the filename; validate the chosen path before opening – e.g. compare os.path.realpath(returned_path) against os.path.realpath(outdir) and reject any patch whose resolved path is not inside outdir; and/or pre-screen commits and refuse to format any whose subject's first line contains /, \, .., or other characters that are not safe on the target filesystem.

CVSS base score
3.3
Published
2026-06-10
OWASP
A01 Broken Access Control
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Dulwich
Fixed by upgrading
Yes

Solution

Upgrade Dulwich to version 1.2.5 or later.

Vulnerable code sample

import os

def get_summary_vulnerable(subject_line):
    """
    This function simulates the vulnerable get_summary method from older
    Dulwich versions. It only replaces spaces with dashes and does not
    sanitize path traversal characters like '..' or '/'.
    """
    return subject_line.replace(' ', '-')

def format_patch_vulnerable(outdir, commit, index):
    """
    This function demonstrates the CVE-2026-47712 vulnerability.
    It constructs a patch filename from a commit's subject line without
    sanitization, allowing a malicious subject to write a file outside
    of the intended `outdir`.
    """
    # Get the summary from the commit subject. This summary is not sanitized.
    summary = get_summary_vulnerable(commit['subject'])

    # Construct the filename. A malicious summary can contain '..' parts.
    # Example: "0001-../../tmp/pwned.patch"
    patch_filename = f"{index:04d}-{summary}.patch"

    # os.path.join will process the ".." parts, leading to path traversal.
    # The resulting path will point outside the 'outdir'.
    malicious_path = os.path.join(outdir, patch_filename)

    print(f"Intended directory: {os.path.abspath(outdir)}")
    print(f"Maliciously constructed path: {os.path.abspath(malicious_path)}")

    # Attempt to write the file to the traversed path.
    try:
        # Create parent directories if they don't exist (e.g. /tmp/)
        os.makedirs(os.path.dirname(malicious_path), exist_ok=True)
        with open(malicious_path, 'w') as f:
            f.write(f"This file was created via path traversal.\n")
            f.write(f"Commit Subject: {commit['subject']}\n")
        print(f"\n[SUCCESS] Vulnerability exploited.")
        print(f"File created at: {os.path.abspath(malicious_path)}")
    except Exception as e:
        print(f"\n[ERROR] Could not create file: {e}")


# --- PoC Demonstration ---

if __name__ == "__main__":
    # The directory where patches are supposed to be saved.
    safe_output_directory = "patches_dir"
    os.makedirs(safe_output_directory, exist_ok=True)

    # A mock commit object with a malicious subject line.
    # The '..' will be interpreted by os.path.join to traverse directories.
    malicious_commit_object = {
        'subject': '../../../../tmp/maliciously_created_file'
    }

    # Execute the vulnerable function with the malicious input.
    format_patch_vulnerable(
        outdir=safe_output_directory,
        commit=malicious_commit_object,
        index=1
    )

Patched code sample

def get_sanitized_summary(first_line):
    """
    Mirrors git's format_sanitized_subject to make a subject line safe
    for use as a filename component. This is the logic that fixes the
    path traversal vulnerability.
    """
    # Keep only [A-Za-z0-9._], collapse runs of other characters to a single -
    summary = "".join(
        c if c.isalnum() or c in "._" else "-" for c in first_line
    )

    # Collapse consecutive '.' or '-' to a single one
    while ".." in summary:
        summary = summary.replace("..", ".")
    while "--" in summary:
        summary = summary.replace("--", "-")

    # Strip trailing './-'
    summary = summary.rstrip(".-")

    # Limit length for convenience
    return summary[:72]

Payload

../../tmp/pwned

Cite this entry

@misc{vaitp:cve202647712,
  title        = {{Dulwich path traversal via unsanitized commit subjects in format_patch.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-47712},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-47712/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::