JustAppSec
Back to news

PyPI fixes two High-severity auth bugs found in Trail of Bits audit

3 min readPublished 01 May 2026Source: Socket

TL;DR - PyPI's Warehouse backend had two High-severity authorization bugs: any org Member could invite new Owners by POSTing to a read-only-protected endpoint, and project transfers left orphaned TeamProjectRole records that silently granted upload rights to teams in the old org.

What happened

Warehouse is the open-source web app that runs PyPI - handling authorisation, uploads, metadata validation, and distribution for the entire Python package ecosystem.

Trail of Bits completed PyPI's second external security audit. The engagement surfaced 14 findings in total: two High, one Medium, seven Low, four Informational. Socket reported that most findings are remediated, with two still open at time of writing. The two High-severity issues are both fixed.

FindingWhat an attacker doesImpactStatus
Org role management bugPOST to manage_organization_roles with role_name=OwnerLow-priv Member sends Owner invitations; target accepts and gains admin controlFixed
Project transfer stale accessRely on orphaned TeamProjectRole records after transferHidden ProjectsUpload rights survive the transfer; malicious releases become possibleFixed

Bug 1: org Members could invite Owners

manage_organization_roles handled both GET and POST under a single permission configuration requiring only Permissions.OrganizationsRead. On POST, the handler called _send_organization_invitation and used the caller-supplied role_name directly. Any org Member could therefore send invitations for Owner, Manager, or Billing Manager roles. If the recipient accepted the emailed link, they gained full administrative control - including managing projects and trusted publishers, and removing the original owner.

The fix splits the configuration: GET still requires OrganizationsRead; POST now requires OrganizationsManage. Trail of Bits also wrote a CodeQL query to catch similar patterns where state-changing POST handlers are only gated on read-level permissions.

Bug 2: stale upload permissions after project transfers

When a project was transferred or removed from an organisation, PyPI deleted the OrganizationProject junction record but left the org-scoped TeamProjectRole records untouched. During ACL evaluation, PyPI granted permissions to every matched TeamProjectRole for the project without checking whether the team still belonged to the project's current organisation. A stale Maintainer role was enough to grant ProjectsUpload - sufficient to push a malicious release. Those orphaned records were invisible to the receiving organisation and never surfaced in collaborator lists.

PyPI fixed this by deleting TeamProjectRole records for the departing organisation before removing the OrganizationProject junction record, and by adding ACL filters that verify team organisation matches the project's current organisation before granting permissions. PyPI also audited existing database records and found no evidence of dangling permissions from prior transfers.

Other findings

Beyond the two High-severity items, Trail of Bits identified Trusted Publishing replay edge cases (one Medium, one Low) involving jti anti-replay storage in Redis versus JWT decode leeway. A separate finding noted that wheel-embedded metadata (.dist-info/METADATA) is extracted for PEP 658 serving but not validated against the form-derived metadata. That gap remains open. It creates a tooling blind spot where PyPI's JSON API can show no dependencies while pip still installs dependencies based on the served wheel metadata.

Registry-side authorisation bugs and stale permissions are worth paying attention to at the ecosystem level. They can turn routine maintainer operations - invites, transfers, uploads - into supply-chain compromise paths.

Who is impacted

  • Any organisation using PyPI Organizations, particularly those with a large Member population or frequent role changes.
  • Projects transferred between organisations or removed from org ownership before the fix - stale access may have persisted during that window.
  • Maintainers using PyPI Trusted Publishing (OIDC-based uploads) who should treat OIDC token handling, CI logs, and build artefacts as sensitive.
  • Security and dependency tooling that relies solely on PyPI's JSON API for dependency metadata - PEP 658 wheel metadata can diverge from what the API reports.

What to do now

  • Review PyPI organisation governance:
    • confirm who currently holds Owner, Manager, and Billing Manager roles
    • check for unexpected pending invitations and recent role changes
  • Audit recent project transfers:
    • review transfer history and confirm no unexpected uploads occurred shortly after a transfer
    • treat unexpected post-transfer uploads on high-value packages as a supply-chain incident signal
  • Harden Trusted Publishing usage:
    • avoid leaking OIDC tokens via CI logs, build artefacts, or misconfigured runners
    • restrict who can modify CI workflows that mint OIDC tokens for PyPI publishing
  • Treat metadata surfaces as potentially inconsistent:
    • if you gate dependency risk decisions on PyPI JSON API output, validate against the metadata your installer actually consumes (for example, PEP 658 metadata for wheels)
  • Incorporate PyPI's remediation and audit guidance into your maintainer runbooks for org management, project transfers, and publishing workflows.

Related


Content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly, send corrections to [email protected]. Always consult official documentation and validate key implementation decisions before making design or security choices.

Need help?Get in touch.