Skip to content

PyPI's Second Audit Found 14 Bugs. Two Remain.

April 16, 2026·Tim Hopper

PyPI completed its second external security audit today. Trail of Bits found 14 issues in the Warehouse codebase: 2 High, 1 Medium, 7 Low, 3 Informational, 0 Critical. Twelve were patched. Two were accepted as known gaps. The work was funded by the Sovereign Tech Agency, with remediation by PSF’s Mike Fiedler through Alpha-Omega support.

An audit of PyPI is an audit of the index infrastructure, not of the packages hosted on it. None of the findings describe malware in the wild. The patched bugs are the predictable part; the accepted ones are where the signal lives.

PyPI doesn’t validate wheel METADATA against the upload form

When you upload a wheel to PyPI, two independent metadata records land. The form-declared metadata populates the database and the JSON API that tools like pip-audit query. The .dist-info/METADATA file embedded inside the wheel is served separately under PEP 658 so installers can resolve dependencies without downloading the wheel bytes.

PyPI never compares the two. An attacker who controls an upload can embed Requires-Dist entries in the wheel’s METADATA that uv or pip will install, while anyone querying PyPI’s JSON API sees a different dependency list. A vulnerability scanner that trusts the JSON API would miss those hidden dependencies entirely.

The fix requires rewriting the upload path and backfilling the archive, so PyPI deferred it. If you build tooling that audits packages by querying the index, this is a gap worth knowing about.

API tokens skip IP bans

PyPI admins can IP-ban abusive uploaders. The session authentication policy checks the ban list; the API token (macaroon) path doesn’t. An API token issued before the ban continues working from the banned address.

This is narrow. PyPI uses IP bans sparingly, and account disables are a stronger tool when a bad actor is identified. The useful takeaway is that PyPI’s session path and its token path are different code, and they don’t always enforce the same rules.

The high-severity bugs are patched

The two High-severity findings were internal permission bugs. One let any organization member invite new Owners because GET and POST shared a read-only permission check on the same view. The other left stale team permissions behind when a project moved between organizations, so the previous org’s team members silently kept Owner access. Both are patched, and Mike Fiedler audited historical transfers to confirm no project was affected in practice.

What to do about it

Nothing new. If your release workflow already uses Trusted Publishing, attaches attestations, and pins dependencies with hashes, you’re covered against the threats the audit surfaced. If it doesn’t, the LiteLLM incident from three weeks ago is the reason to start.

Last updated on

Please submit corrections and feedback...