CVE-2026-44722
pyzipper exposes plaintext CRC32 checksum, allowing brute-force attacks.
- CVSS 6.2
- CWE-480
- Cryptographic
- Remote
pyzipper is a replacement for Python's zipfile that can read and write AES encrypted zip files. Prior to 0.4.0, a Python operator precedence bug in pyzipper/zipfile_aes.py caused the AE-2 format to never be automatically selected during encryption, causing encrypted entries to be written in AE-1 format and exposing the plaintext CRC32 checksum in the ZIP header and, for unseekable zip archives, in the datadescripter section, allowing an attacker who possesses the archive to brute-force candidate plaintexts for small or low-entropy files by comparing CRC32 values. This issue is fixed in version 0.4.0.
- CWE
- CWE-480
- CVSS base score
- 6.2
- Published
- 2026-07-17
- OWASP
- A02 Cryptographic Failures
- Orthogonal defect classification
- Assignment
- Code defect classification
- Incorrect Algorithm
- Category
- Cryptographic
- Subcategory
- Cryptographic Implementation Error
- Accessibility scope
- Remote
- Impact
- Information Disclosure
- Affected component
- pyzipper
- Fixed by upgrading
- Yes
Solution
Upgrade pyzipper to version 0.4.0 or later.
Vulnerable code sample
import io
import pyzipper
# This code requires a vulnerable version of pyzipper (e.g., 0.3.0).
# pip install pyzipper==0.3.0
def vulnerable_create_zip_with_lzma(password):
"""
Demonstrates the vulnerability by creating an AES-encrypted zip file
using LZMA compression with a vulnerable pyzipper version. The bug
causes the library to select the AE-1 encryption format instead of the
intended AE-2, exposing the CRC32 checksum in the header.
"""
in_memory_zip = io.BytesIO()
# The vulnerability occurs when AES encryption is used with LZMA compression.
with pyzipper.AESZipFile(in_memory_zip, 'w',
compression=pyzipper.ZIP_LZMA,
encryption=pyzipper.WZ_AES) as zf:
# Set the password for encryption.
zf.setpassword(password)
# Add a small, low-entropy file. The exposed CRC32 of this plaintext
# makes a brute-force attack feasible.
zf.writestr('file.txt', b'123')
return in_memory_zip.getvalue()
# --- Execution ---
# Create a password-protected zip file using the vulnerable logic.
password = b"secret"
zip_data = vulnerable_create_zip_with_lzma(password)
# To verify the vulnerability, one would inspect the created zip_data.
# The 'extra field' for 'file.txt' would show the AES vendor version as 0x0001 (AE-1)
# instead of the correct 0x0002 (AE-2) for LZMA, and the CRC32 (0x884863d2 for '123')
# would be present in plaintext in the central directory header for the file.
# For example, a hex editor would reveal the CRC value in the file's header.
# (Verification step is not shown in this code).Patched code sample
# Constants based on zipfile and pyzipper specifications
ZIP_DEFLATED = 8
ZIP_AES = 99
AES_MODE_AE1 = 1
AES_MODE_AE2 = 2
def _select_aes_mode_fixed(zinfo):
"""
This function represents the fixed logic for CVE-2021-44722 in pyzipper > 0.4.0.
The vulnerability was that the AE-2 encryption format was never selected
because the code used an incorrect condition to check if a data descriptor
was present. It incorrectly checked bit 0 (`0x1`) instead of bit 3 (`0x8`).
This forced the use of AE-1, which leaves the CRC32 checksum unencrypted.
The fix involves changing the condition to correctly check for the data
descriptor flag (`0x8`), ensuring AE-2 is used when appropriate.
Args:
zinfo: A ZipInfo-like object with `flag_bits` and `compress_type` attributes.
"""
# The vulnerable line of code was:
# if zinfo.flag_bits & 0x1 and zinfo.compress_type == ZIP_DEFLATED:
# The fixed code correctly checks for bit 3 (0x8), which is the flag
# indicating a data descriptor follows the file data. This is the
# condition that requires using AE-2 encryption.
if (zinfo.flag_bits & 0x8) and zinfo.compress_type in (ZIP_DEFLATED, ZIP_AES):
# This branch is now correctly entered for unseekable archives,
# selecting AE-2 to encrypt the CRC32 value.
zinfo.aes_encryption_mode = AES_MODE_AE2
else:
# AE-1 is used for standard cases where the CRC32 is in the header.
zinfo.aes_encryption_mode = AES_MODE_AE1
return zinfo.aes_encryption_modeCite this entry
@misc{vaitp:cve202644722,
title = {{pyzipper exposes plaintext CRC32 checksum, allowing brute-force attacks.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-44722},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44722/}}
}
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 ::
