Moderate severityNVD Advisory· Published Mar 6, 2026· Updated Mar 6, 2026
pypdf: Inefficient decoding of ASCIIHexDecode streams
CVE-2026-28804
Description
pypdf is a free and open-source pure-python PDF library. Prior to version 6.7.5, an attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the /ASCIIHexDecode filter. This issue has been patched in version 6.7.5.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pypdfPyPI | < 6.7.5 | 6.7.5 |
Affected products
1Patches
1648c627d2657SEC: Improve the performance of the ASCIIHexDecode filter (#3666)
2 files changed · +27 −28
pypdf/filters.py+21 −28 modified@@ -35,6 +35,7 @@ __author__ = "Mathieu Fenniak" __author_email__ = "biziqe@mathieu.fenniak.net" +import binascii import math import os import shutil @@ -343,34 +344,26 @@ def decode( """ if isinstance(data, str): data = data.encode() - retval = b"" - hex_pair = b"" - index = 0 - while True: - if index >= len(data): - logger_warning( - "missing EOD in ASCIIHexDecode, check if output is OK", __name__ - ) - break # Reached end of string without an EOD - char = data[index : index + 1] - if char == b">": - break - if char.isspace(): - index += 1 - continue - hex_pair += char - if len(hex_pair) == 2: - retval += bytes((int(hex_pair, base=16),)) - hex_pair = b"" - index += 1 - # If the filter encounters the EOD marker after reading - # an odd number of hexadecimal digits, - # it shall behave as if a 0 (zero) followed the last digit. - # For every even number of hexadecimal digits, hex_pair is reset to b"". - if hex_pair != b"": - hex_pair += b"0" - retval += bytes((int(hex_pair, base=16),)) - return retval + + # Stop at EOD + eod = data.find(b">") + if eod == -1: + logger_warning( + "missing EOD in ASCIIHexDecode, check if output is OK", + __name__, + ) + hex_data = data + else: + hex_data = data[:eod] + + # Remove whitespace + hex_data = b"".join(hex_data.split()) + + # Pad if odd length + if len(hex_data) % 2 == 1: + hex_data += b"0" + + return binascii.unhexlify(hex_data) class RunLengthDecode:
tests/test_filters.py+6 −0 modified@@ -1043,3 +1043,9 @@ def test_runlengthdecode__decode_limit(): # Use a very low limit for this exact comparison, otherwise *pytest* takes ages to render a failure diff. with mock.patch("pypdf.filters.RUN_LENGTH_MAX_OUTPUT_LENGTH", uncompressed_size): assert RunLengthDecode.decode(encoded) == b"A" * uncompressed_size + + +@pytest.mark.timeout(10) +def test_asciihexdecode__speed(): + encoded = (b"41" * 1_200_000) + b">" + ASCIIHexDecode.decode(encoded)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-9m86-7pmv-2852ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-28804ghsaADVISORY
- github.com/py-pdf/pypdf/commit/648c627d2657447dfb1773412af05a0a5103b98fghsax_refsource_MISCWEB
- github.com/py-pdf/pypdf/pull/3666ghsax_refsource_MISCWEB
- github.com/py-pdf/pypdf/releases/tag/6.7.5ghsax_refsource_MISCWEB
- github.com/py-pdf/pypdf/security/advisories/GHSA-9m86-7pmv-2852ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.