Safeguard
Security Guides

pandas Security Guide (2026)

pandas is the backbone of Python data analysis — and while its own CVE record is thin, the read_pickle deserialization risk is real, the query/eval expression engine invites injection, and most 'pandas findings' actually live in its dependency tree.

Priya Mehta
Security Researcher
6 min read

pandas is the backbone of data analysis in Python. Its DataFrame and Series types sit under nearly every notebook, ETL job, feature pipeline, and analytics service written in the language, and it arrives transitively through scikit-learn workflows, dashboards, and data-engineering frameworks. On PyPI it is one of the most-downloaded packages in existence, and it is almost never a dependency you chose deliberately — it comes along with everything else. Because pandas is so ubiquitous and so obviously "just data wrangling," teams assume it is inert from a security standpoint. Its own published CVE record is genuinely thin, but that thinness hides two real behaviors worth understanding — pickle-based loading and the expression engine behind query/eval — and it obscures where most pandas-tagged findings actually come from: the heavy native dependency tree beneath it.

The notable historical CVEs

pandas has very few advisories of its own, and the one that matters is about deserialization:

  • CVE-2020-13091pandas.read_pickle used Python's pickle module by design, so loading a crafted pickle file could execute arbitrary code. A malicious object implements a __reduce__ method that returns a callable such as os.system with attacker-chosen arguments; when pandas unpickles it, that command runs. The issue affects pandas through 1.0.3 and is addressed from 1.0.4 onward. Like the analogous NumPy advisory, this CVE is disputed by the maintainers, who note that read_pickle is documented as unsafe and intended for trusted input — but the risk to code that loads untrusted pickles is real.

The honest summary is that pandas' own attack surface is small and centers on read_pickle. Most vulnerability findings that show up tagged "pandas" are really in the libraries it pulls in — NumPy, PyArrow, and the native compression and parsing stacks — so triaging a pandas advisory well means knowing which layer it actually lives in.

Common misuse and risks

  • pandas.read_pickle on untrusted input. Loading a pickle whose bytes an attacker can influence is equivalent to running eval() on that file. This is the pattern that turns CVE-2020-13091 into a real compromise, and pickles received over the network, from uploads, or from a shared cache are all vectors.
  • Interpolating untrusted strings into DataFrame.query() or pandas.eval(). These evaluate an expression against your frame. If you build the expression by concatenating user input, you have created an injection surface — the expression can reference variables and, with the Python engine, reach beyond simple filtering.
  • Treating every parser as safe. read_csv, read_json, read_html, read_excel, and friends parse attacker-influenced bytes and can trigger resource exhaustion or expose bugs in the underlying native libraries.
  • Stale transitive pandas. Because it sits beneath so much tooling, an old pandas — and, more importantly, its old NumPy and PyArrow companions — can linger in an environment long after you have upgraded your own code.

How to use pandas safely

Set the version floor: run a current pandas release (the 2.x line in 2026) and never operate below 1.0.4, the release that addressed the read_pickle advisory. Staying current also keeps the native dependency stack fresh, which is where the real exposure usually lives.

Then handle serialized data and expressions deliberately:

  • Never call read_pickle on data you do not fully trust. Prefer a non-executable interchange format — Parquet, CSV, or a schema-validated JSON — for anything crossing a trust boundary. A pickle is code, not data.
  • Do not build query/eval expressions from untrusted input. Filter with the DataFrame API (boolean masks, .loc) instead of string expressions, or strictly allow-list the columns and operators a user may reference.
  • Bound and validate parser inputs. Cap file sizes and row counts when reading external data, and validate schemas so a malformed upload cannot exhaust memory.
  • Pin and monitor the whole tree. Lock pandas and its dependencies, and triage findings by which layer they touch — a NumPy or PyArrow CVE beneath pandas is usually the one that matters.

How to monitor pandas with SCA and reachability

pandas is in essentially every Python data project, so a version-based scanner will flag it and its dependencies everywhere — and because its own headline CVE is disputed and documented behavior, that raw list is mostly noise. The questions that decide urgency are narrow: does your code call read_pickle on input an attacker can influence, do you interpolate untrusted strings into query/eval, and are the native libraries beneath pandas patched?

Safeguard's software composition analysis resolves your full Python dependency graph — including the NumPy and PyArrow layers you never chose directly — and adds call-path reachability, so a deserialization advisory that touches a real loading path is separated from a disputed CVE sitting behind an API you never call. Griffin AI explains why a given finding does or does not matter for your codebase, including when a disputed advisory 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, and teams comparing approaches can see how this differs from a version-only scanner on the Snyk comparison.

Bring continuous, prioritized dependency analysis to your Python and data services — get started free or read the documentation.

Frequently Asked Questions

Which pandas version is safe in 2026?

Run a current release on the 2.x line, and never operate below 1.0.4, the version that addressed the read_pickle deserialization advisory (CVE-2020-13091). Just as important, keep the native dependencies beneath pandas — NumPy and PyArrow in particular — current, since that layer is where most real pandas-tagged exposure lives.

Is pandas.read_pickle safe to use?

Only on data you fully trust. A pickle can embed a Python object whose deserialization runs arbitrary code, so calling read_pickle on an untrusted file is equivalent to running eval() on it. For anything crossing a trust boundary, use a non-executable format such as Parquet or CSV instead.

Can DataFrame.query() or pandas.eval() be exploited?

They can be misused. Both evaluate an expression against your data, so interpolating untrusted user input into the expression string creates an injection surface. Filter with the DataFrame API instead, or strictly allow-list the columns and operators a caller may reference rather than passing raw strings through.

How do I know if a pandas CVE actually affects my app?

Use reachability-aware SCA. It traces whether your code reaches the risky behavior — chiefly read_pickle on attacker-influenced input, or untrusted expressions in query/eval — and it tells you when a finding actually lives in a dependency like NumPy or PyArrow, so you fix the layer that matters instead of chasing a disputed advisory.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.