You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

numpy np.load β€” crafted .npz leaks an uncaught NotImplementedError (unsupported ZIP compression method)

Out-of-contract exception / DoS. Distinct from the separate zipfile.BadZipFile npz finding.

  • Target: numpy (PyPI)
  • Verified versions: numpy 2.5.1 (venv, Python 3.13.12) and numpy 2.3.5 (system, Python 3.13.12) β€” identical behavior
  • Component: numpy/lib/_npyio_impl.py β€” load() (~line 471) routes ZIP-prefixed files to NpzFile; NpzFile.__getitem__ (line 245)
  • Class: Uncaught / out-of-contract exception on untrusted model-file input β†’ denial of service
  • CWE: CWE-248 (Uncaught Exception) / CWE-755 (Improper Handling of Exceptional Conditions)

Summary

np.load() on a file that begins with the ZIP prefix (PK\x03\x04) is unconditionally routed to NpzFile. The NpzFile constructor succeeds and returns a normal-looking object whose .files correctly lists every member. The archive therefore passes any load-time validation a caller performs.

The crash fires later, on member access. NpzFile.__getitem__ does:

# numpy/lib/_npyio_impl.py  (line 245)
def __getitem__(self, key):
    ...
    if magic == self.zip.open(key).read(len(magic)):   # (elided)
        ...
    with self.zip.open(key) as bytes:      # <-- NO translation of ZIP-layer exceptions
        ...

numpy silently assumes every member uses a compression method the stdlib zipfile can read. If a member's compression-method field (in both the local file header and the central-directory record) is set to a value zipfile does not support β€” e.g. 99, or 6/imploded, anything outside STORED / DEFLATED / BZIP2 / LZMA β€” then zipfile.ZipExtFile.__init__ β†’ _get_decompressor β†’ _check_compression raises:

NotImplementedError: That compression method is not supported

NotImplementedError is a subclass of RuntimeError. It is not in np.load's documented Raises contract (OSError, UnpicklingError, ValueError, EOFError) and is not a subclass of any of them, so it propagates unchanged out of np.load(...)[key].

Why this is distinct from the BadZipFile npz finding

A fix that catches zipfile.BadZipFile (as the separate npz report proposes) does not cover this bug:

  • Different exception type: NotImplementedError vs BadZipFile.
  • Different failure point: raised during decompressor selection inside zip.open(), before any read / CRC check β€” so a BadZipFile-only handler never sees it.

TEST 3 below hardens the wrapper with BadZipFile and the crash still escapes, proving the two findings are not the same defect.

Impact

Any library or service that calls np.load() on an attacker-supplied .npz and later touches a member β€” the normal usage pattern β€” is vulnerable to an unhandled-exception DoS that is invisible to load-time archive validation. A closely-related second instance shares the identical missing-translation root cause and is reachable non-adversarially: because np.savez_compressed writes DEFLATE members, a truncated or corrupt compressed .npz makes f['data'] raise an uncaught zlib.error (see SECONDARY below).

PoC

Build a valid single-member ZIP_STORED .npz containing data.npy (a real uint8 array [1,2,3]) with numpy's own zipfile, then hex-patch the 2-byte compression-method field to 99 in both the local file header (offset i+8 after PK\x03\x04) and the central-directory record (offset j+10 after PK\x01\x02). Result is a 247-byte .npz.

import numpy
f = numpy.load('poc_unsupported_compression.npz', allow_pickle=False)  # SUCCEEDS
assert f.files == ['data']                                             # archive looks valid
f['data']            # -> NotImplementedError: That compression method is not supported
  • Negative control: the byte-for-byte identical archive without the method patch loads cleanly and returns [1 2 3].
  • Distinctness control: wrapping in except (OSError, ValueError, EOFError, UnpicklingError, BadZipFile) still crashes.

Files in this repo: verify_final.py (self-contained harness that regenerates all artifacts), poc_unsupported_compression.npz, poc_corrupt_deflate.npz, ctrl_valid.npz.

Captured evidence (verbatim) β€” numpy 2.5.1, Python 3.13.12

=== ENV ===
numpy 2.5.1 python 3.13.12
np.load Raises contract (docstring): OSError, UnpicklingError, ValueError, EOFError

=== PoC written: .../poc_unsupported_compression.npz (247 bytes) ===

=== TEST 1: np.load returns NpzFile fine (constructor OK) ===
  np.load OK, type: NpzFile files: ['data']

=== TEST 2: member access f['data'] -> full traceback ===
  *** OUT-OF-CONTRACT *** builtins.NotImplementedError: That compression method is not supported
  MRO: ['NotImplementedError', 'RuntimeError', 'Exception', 'BaseException', 'object']
  --- verbatim traceback ---

=== TEST 3: defensive wrapper that ALSO catches BadZipFile still crashes ===
  *** STILL ESCAPES even a BadZipFile-hardened wrapper ***: builtins.NotImplementedError

=== NEGATIVE CONTROL: identical archive without the compress-method patch loads fine ===
  ctrl f['data'] = [1 2 3]

=== SECONDARY (related, distinct type): corrupt DEFLATE member -> zlib.error ===
  -> zlib.error: Error -3 while decompressing data: invalid code lengths set | MRO tail: ['Exception', 'BaseException', 'object']

done

Full stderr traceback (TEST 2):

Traceback (most recent call last):
  File "verify_final.py", line 34, in <module>
    arr=f['data']
        ~^^^^^^^^
  File ".../numpy/lib/_npyio_impl.py", line 245, in __getitem__
    with self.zip.open(key) as bytes:
         ~~~~~~~~~~~~~^^^^^
  File "/usr/lib/python3.13/zipfile/__init__.py", line 1724, in open
    return ZipExtFile(zef_file, mode + 'b', zinfo, pwd, True)
  File "/usr/lib/python3.13/zipfile/__init__.py", line 905, in __init__
    self._decompressor = _get_decompressor(self._compress_type)
                         ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/zipfile/__init__.py", line 801, in _get_decompressor
    _check_compression(compress_type)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/zipfile/__init__.py", line 781, in _check_compression
    raise NotImplementedError("That compression method is not supported")
NotImplementedError: That compression method is not supported

Reproduced identically on system numpy 2.3.5, Python 3.13.12.

SECONDARY (same root cause, distinct type, non-adversarial)

A member with a corrupt DEFLATE stream makes f['data'] raise an uncaught zlib.error: Error -3 while decompressing data: invalid code lengths set. zlib.error is likewise outside np.load's Raises contract. This is realistic even without an attacker because np.savez_compressed produces DEFLATE members, so a truncated/corrupt compressed .npz triggers it.

Suggested fix

In NpzFile.__getitem__, translate ZIP-layer decompression failures (NotImplementedError, zlib.error, BadZipFile, EOFError) raised by self.zip.open(key) / subsequent reads into an in-contract OSError/ValueError (BadZipFile already is an OSError), so member access honors the documented Raises contract.

Dedup note

  • Distinct from the separate .npz BadZipFile load-contract finding (different exception type and failure point; TEST 3 proves a BadZipFile-only fix leaves this open).
  • Distinct from the .npy header findings (bool/shape TypeError, descr-tuple IndexError, shape int overflow) β€” those are .npy header-parse bugs, not the .npz/ZIP decompression path.
  • No known CVE covers an uncaught NotImplementedError/zlib.error from NpzFile member access.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support