Fix the bug, release it under a new version number, tell users which versions are affected and which are fixed, and decide carefully whether to yank old releases. PyPI does not let you replace published files, so the fix always ships as a new release.
Why the order matters
Users can only upgrade to something that exists. So the first deliverable is the fixed release, with a version number that makes the boundary obvious. A patch version is the natural choice. Our post on post releases versus patch versions explains why a post release is a poor fit for a code fix.
The PyPI help page says a distribution filename can never be reused, even after deletion, and that this guarantees a given file cannot be changed later by a maintainer or a malicious party. That rule is a feature for your users, and it means you cannot quietly patch a bad file in place.
Steps
- Fix and test. Add a regression test that fails without the fix.
- Pick the version. Use the next patch number, or whatever your versioning policy says for a fix.
- Build and check. Run the build, list the artifacts, and run
twine check. See our pre upload checklist. - Publish from CI with a trusted publisher, not a long lived token.
- Write the advisory. State affected versions, the fixed version, a short description of impact, and a workaround if one exists.
- Decide on yanking using the rules below.
- Tell users in the changelog, release notes and your security contact channel.
Should you yank vulnerable releases?
PyPI's yanking docs list a security vulnerability as one reason to consider yanking, alongside a release that is broken or violates its compatibility guarantees. They also say yanking should be done sparingly because it can disrupt downstream users.
What yanking does: a yanked release is ignored by installers unless it is the only release matching a specifier that uses exact equality. So a user who pins the vulnerable version still gets it. A user with a range gets pushed to the fixed version.
| Choice | Effect | Trade off |
|---|---|---|
| Do not yank | Old release stays selectable by ranges | Users with loose ranges may still resolve to it |
| Yank with a reason | Ranges skip it, exact pins still work | PyPI strongly encourages a reason that explains the yank |
| Delete | Pinned installs break | Permanent and disruptive, rarely justified |
Yanking only supports whole releases on PyPI, not individual files. Yanking does not free storage either.
A middle path for a serious flaw is to yank the vulnerable releases with a reason that names the fixed version, and keep the fixed release one step away.
Getting data to scanners
PyPI states that it receives vulnerability reports from the Open Source Vulnerabilities project, which ingests from the Python Packaging Advisory Database. If you think the data for your project is wrong, the help page says to file an issue with details. So advisory records are the channel through which scanners learn about your fix.
If you maintain the advisory, make the affected range precise. A range that is too wide creates false alarms for users, and a range that is too narrow leaves real users unwarned.
Try it yourself
Click through it at your own pace, or open it full screen.
Follow a finding from detection to resolution, and note what information the fixed version provides to the person triaging it.
Safeguard's dependency scanning, reachability analysis and fix pull requests help downstream teams adopt your fix. Fix PRs are off by default, with every category on Manual. You can try a free scan.
Quick check
Can I patch the bad file under the same version?
No. PyPI does not allow filename reuse, so ship a new version.
Does yanking stop people installing the vulnerable version?
Not if they pin that exact version. Yanked releases are skipped except when they are the only match for an exact equality specifier.
Where do scanners get PyPI vulnerability data?
PyPI says it comes from the Open Source Vulnerabilities project, which ingests the Python Packaging Advisory Database.
Sources
- Yanking, PyPI Docs
- PyPI help, FAQ
- Storage Limits, PyPI Docs
- Version specifiers, Python Packaging User Guide
Last reviewed: 19 October 2026.