NumPy is the numerical foundation of the entire Python data and scientific-computing ecosystem. Its n-dimensional array type and vectorized operations sit beneath pandas, scikit-learn, TensorFlow, PyTorch, SciPy, and effectively every data pipeline written in Python. On PyPI it is among the most-downloaded packages in existence, almost always arriving as a transitive dependency you never explicitly chose. Because NumPy is so foundational, teams tend to assume it is boring from a security standpoint — but it has a genuinely dangerous deserialization behavior, and it also illustrates something important about CVE triage: several of its published advisories are disputed by the maintainers, and knowing which are real changes how you prioritize.
The notable historical CVEs
NumPy's security-relevant history is smaller than its download count suggests, and its most important entry is about deserialization. These are all real, published advisories:
- CVE-2019-6446 —
numpy.loadused Python'spicklemodule by design, so loading a crafted.npy/.npzfile could execute arbitrary code. In response, NumPy changed the default of theallow_pickleparameter fromTruetoFalsein1.16.3, so loading no longer silently deserializes pickled objects. This CVE is disputed by the maintainers, who note that pickle-based loading is a documented feature intended for trusted, authenticated sources — but the risk to code that loads untrusted arrays is real, and the default change is the practical fix. - CVE-2017-12852 — a denial of service in
numpy.pad, where certain inputs could drive the function into an effectively non-terminating loop. - CVE-2021-33430 — a reported buffer overflow in the
numpy.f2pyFortran-interface tooling. This one is also disputed, as it concerns a component that processes developer-supplied source rather than untrusted runtime input.
The honest summary: NumPy's one durable, widely-applicable security concern is numpy.load on untrusted data. Many of its other CVEs are either disputed as documented behavior or require the attacker to already control inputs to developer-facing tooling — which is why blindly treating every NumPy advisory as urgent produces mostly noise.
Common misuse and risks
numpy.load(untrusted, allow_pickle=True). Explicitly re-enabling pickle to load an object array from an untrusted.npy/.npzfile is equivalent to runningeval()on that file. This is the pattern that turns CVE-2019-6446 into a real compromise.- Assuming
.npyfiles are inert data. A.npyfile can contain a pickled Python object, not just numbers, so treating it as a safe interchange format for untrusted input is a mistake. - Loading arrays received over the network or from uploads. Any array whose bytes an attacker can influence is a potential deserialization vector if pickle is enabled.
- Stale transitive NumPy. Because it sits beneath so many libraries, an old NumPy can linger in an environment, though its security impact is usually smaller than that of the libraries above it.
How to use NumPy safely
Set the version floor: run a current NumPy release (the 2.x line in 2026), and never operate below 1.16.3, the release that flipped allow_pickle to default False. Staying current also picks up the steady stream of correctness and hardening fixes in the C core.
Then handle serialized data deliberately:
- Never set
allow_pickle=Truewhen loading data you do not fully trust. Keep the safe default. If you only need numeric arrays, the default already refuses to unpickle objects. - Use a non-executable format for untrusted interchange. Prefer plain
.npynumeric arrays (with pickle disabled), or a schema-validated format, over pickled object arrays for anything crossing a trust boundary. - Bound and validate inputs to functions that have shown DoS behavior, and cap the size of arrays constructed from external data to limit resource exhaustion.
- Pin and monitor, but triage NumPy findings with reachability in mind — several advisories are disputed and do not warrant an emergency bump.
How to monitor NumPy with SCA and reachability
NumPy is in essentially every Python data project's dependency tree, so a version-based scanner will flag it everywhere — and because several of its CVEs are disputed or require trusted-input assumptions, that raw list is mostly noise. The question that decides urgency is narrow: does your code call numpy.load with allow_pickle=True on input an attacker can influence?
Safeguard's software composition analysis resolves your full Python dependency graph and adds call-path reachability, so a NumPy deserialization advisory that touches a real loading path in your code is separated from a disputed CVE sitting behind tooling you never expose. Griffin AI explains why a given finding does or does not matter for your codebase — including when a disputed CVE can be safely deprioritized — and autonomous auto-fix opens a tested pull request when a version bump is genuinely warranted. Developers run the same analysis locally and in CI with the Safeguard CLI.
Bring continuous, prioritized dependency analysis to your Python and data services — get started free or read the documentation.
Frequently Asked Questions
Which NumPy version is safe in 2026?
Run a current release on the 2.x line, and never operate below 1.16.3. That 1.16.3 release changed the allow_pickle default to False, which is the practical fix for the numpy.load deserialization risk (CVE-2019-6446). Staying current also picks up ongoing hardening in the C core.
Is numpy.load safe to use?
Yes, as long as you keep the default allow_pickle=False and do not re-enable it for untrusted data. A .npy/.npz file can embed a pickled Python object, so loading one with pickle enabled from an untrusted source can execute arbitrary code — treat that exactly like running eval() on the file.
Why are some NumPy CVEs marked disputed?
Because they describe documented behavior (like pickle-based loading, intended for trusted sources) or require the attacker to already control developer-facing tooling inputs (like the f2py report). Disputed does not mean fictional, but it does mean the advisory often does not apply to how your code actually uses NumPy — which is why reachability-based triage matters here.
How do I know if a NumPy CVE actually affects my app?
Use reachability-aware SCA. It traces whether your code reaches the risky behavior — chiefly numpy.load with allow_pickle=True on attacker-influenced input — so a genuinely exploitable path is separated from the disputed advisories that do not apply to your usage.