Open Source Security

PyPI 2FA Enrollment: Enterprise Rollout

PyPI's 2FA mandate isn't just a personal-account concern anymore — enterprises publishing Python libraries have real rollout work to do. A playbook from the front lines.

Shadab Khan
Security Engineer
6 min read

When PyPI announced in May 2023 that 2FA would be required for all accounts that publish packages, with full enforcement by end of year (PyPI blog, "2FA Required for PyPI," 26 May 2023), a lot of enterprise Python shops suddenly had a rollout problem they hadn't planned for. The consumer-grade advice — buy a YubiKey, enroll TOTP, write down your recovery codes — doesn't scale to a company with two hundred Python publishers, shared service accounts, and a security team that needs audit evidence of who has what. This is the rollout playbook I wish I'd had in June when we started ours.

What the Mandate Actually Requires

The PyPI 2FA requirement, tracked in the Warehouse issue #8090 and announced publicly in May 2023, is that any user who owns or maintains a project on PyPI must have a second authentication factor enabled. The factor can be TOTP or WebAuthn. By 1 January 2024, accounts without 2FA would lose publishing rights — still able to log in, still able to manage account settings, but unable to push new releases.

The enforcement rolled out in phases. Critical project maintainers (top 1% by downloads) had been required to enroll since July 2022 under the earlier program announced in that same year. Everyone else had the latter half of 2023 to come into compliance. The deadline held, and from January 2024 forward, unenrolled accounts found themselves locked out of twine upload.

Why Enterprise Rollouts Break

The failure modes I saw across enterprise rollouts in Q3 2023 clustered around a few specific issues.

Shared service accounts. Many organizations had long-running pypi-publisher@company.com style accounts used by CI. A single TOTP secret or WebAuthn credential on such an account creates an obvious single point of failure — if the person who enrolled it leaves the company, the account is stranded.

Personal accounts publishing corporate packages. Individual engineers had often registered company packages under their personal PyPI accounts in the early days, and those accounts still owned business-critical names. 2FA enrollment for those accounts was nobody's explicit responsibility.

Hardware procurement timelines. Enterprise security teams pushing WebAuthn for everyone hit procurement walls. Ordering 200 YubiKeys through corporate purchasing in Q3 2023, with the supply-chain hangover still lingering in the hardware-token market, was often a six-to-eight-week process.

Recovery code custody. Recovery codes are bearer credentials — anyone holding them can use them. Enterprises that stored recovery codes in shared password managers had governance questions nobody had answered.

The Rollout Plan That Worked

The rollout pattern that worked best in the organizations I saw:

Step one: inventory every PyPI account used by the organization. This is harder than it sounds. Account emails are often personal (jsmith@gmail.com), and the only authoritative source is usually the CI configuration. Pull the token list from every publishing workflow and cross-reference to PyPI account emails. This gives you the real publisher count.

Step two: decide the account-ownership policy. For each identified account, either migrate the package ownership to a corporate-email account, absorb it into a PyPI Organization, or formally accept that it remains personal. The first two are strongly preferred. The July 2023 launch of Organizations made this meaningfully easier.

Step three: provision WebAuthn hardware. TOTP is allowed, but WebAuthn is the defensible choice for a business. Each publisher account should have at least two WebAuthn credentials registered from physically separate tokens, so that losing one doesn't lock the account out. For a 200-engineer rollout, that's 400 tokens plus spares.

Step four: define recovery code custody. My recommendation is a security-team-managed secret vault (HashiCorp Vault or equivalent) with access logged and access grants requiring a documented reason. Recovery codes are not a password — they're an account-takeover credential for an account that publishes software millions of people install.

Step five: enroll, in a predictable window, with support on call. Block out a 48-hour window, have the security team available in a dedicated Slack channel, and enroll in waves of 10-20 publishers at a time. Each enrollment takes about 15 minutes when it goes smoothly and 45 minutes when it doesn't.

Step six: document and audit. After enrollment, produce evidence that each account has at least two WebAuthn credentials and that recovery codes are custody-tracked. This documentation is what your SOC 2 or ISO 27001 auditor will want next year.

The Service Account Question

Service accounts — accounts used by automation rather than humans — are where 2FA enforcement creates the most friction. PyPI's 2FA is for interactive login. Publishing via API token does not require 2FA, but creating or managing those tokens does.

The right pattern for service accounts in 2024 is to not have them at all, and to use Trusted Publishing instead (PyPI blog, "Trusted Publishers for All Packages," 20 April 2023). Trusted Publishing means a CI workflow exchanges an OIDC identity token for a short-lived PyPI credential at publish time. No long-lived account, no long-lived token, no 2FA enrollment problem.

Where Trusted Publishing isn't possible — a provider PyPI doesn't yet support, a publishing workflow that runs in an air-gapped environment — the fallback is a service account owned by a named human, with 2FA enrolled on that account, and API tokens issued and rotated under the rotation policy you'd apply to any other secret. The 2FA is on the management surface, not the publish surface.

Recovery Code Drills

A rollout isn't complete without testing the recovery path. Before declaring done, pick one test account, simulate losing the primary WebAuthn credential, and recover the account using a backup credential. Do this while someone is watching the clock, because the time-to-recovery is one of the numbers you want in your operational documentation.

If recovery takes more than 15 minutes or requires anyone outside the security team to participate, the process needs work. The point of the rollout is that a lost YubiKey on a Tuesday morning doesn't stop a release on a Tuesday afternoon.

Post-Rollout: Ongoing Hygiene

Enrollment is the start, not the end. Ongoing hygiene items a PyPI 2FA program should track:

New-hire enrollment as part of onboarding. Leaver offboarding that explicitly removes WebAuthn credentials from any accounts they held. Annual recovery code rotation. Annual WebAuthn credential audit — is each registered credential still in the custody of the person or team it's assigned to?

Without these, the 2FA posture decays quietly over 18 months as credentials go unrotated and ex-employees remain listed as second-factor holders on accounts they no longer access.

How Safeguard Helps

Safeguard tracks the PyPI packages your organization publishes and the identities publishing them, flagging any publish event from an account that isn't on your 2FA-enrolled publisher roster. For consumers, Safeguard records the publisher of each PyPI package you depend on and surfaces publishes from unenrolled or newly enrolled accounts as supply-chain events worth reviewing. For the rollout itself, Safeguard's policy engine lets you declare 2FA and Trusted Publishing as hard requirements and gate production deployments on packages that don't meet them.

Never miss an update

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