To roll back, find the last version your lockfile history shows as good, pin it explicitly, rebuild from a clean install, and verify the result. Do not rely on the registry to remove the bad version for you. Yank, deprecate and retract signal a problem, but they leave existing lockfile builds untouched.
Why the registry action is not your rollback
Package registries give maintainers several ways to flag a release. None of them reaches into your repository.
| Ecosystem | Flag | What it does | What it leaves alone |
|---|---|---|---|
| npm | deprecate | Adds a warning shown to anyone who tries to install it | Installs still succeed |
| PyPI | yank (PEP 592) | Installers ignore the file unless it is the one match for an exact pin or lock file entry | Pinned and locked installs keep working |
| Cargo | yank | Stops Cargo selecting the version by default | Existing lock files and direct downloads |
| Go | retract | Stops go get and go mod tidy upgrading to it | Builds that already depend on it keep working |
The pattern is deliberate. PEP 592 explains that deleting a file would break users who pinned a specific version, so yanking was designed to protect people who follow pinning practice. The cost is that if your lockfile already holds the bad version, your builds keep using it.
Step 1: find the last good version
Your own history is the source of truth. Search the lockfile commit history for the package and note the version before the suspect one, plus the date it entered. If the incident report gives a time window, pick a version published before it, and confirm with the maintainers' notes rather than guessing.
git log -p --follow -- package-lock.json | grep -n "example-package"
Step 2: pin explicitly, then rebuild clean
Set the dependency to the exact good version in the manifest, not a range. A range lets a resolver walk forward to a new release on the next install.
For npm, npm ci is built for this. The npm documentation says it needs an existing lockfile, exits with an error if the lock and package.json disagree, removes any existing node_modules first, and never writes to package.json or the lock files. After you commit the corrected lock, use it in every pipeline.
For pip, hash-checking mode is the matching control. The pip documentation says hashes in a requirements file protect against remote tampering, and that it is all or nothing: giving a hash to any requirement turns the mode on for all of them.
pip install --require-hashes -r requirements.txt
Step 3: verify what you actually built
Rolling back in the manifest is not the same as rolling back in the artifact. After the rebuild, list installed versions from the built image or bundle, not from the repository. Check that the bad version is absent, that no transitive path pulls it back in, and that caches on runners and mirrors do not still serve it.
Step 4: record the decision
Write down the pinned version, the reason, who approved it, and the condition for moving forward again. A rollback with no exit condition tends to become a permanent pin on an aging release.
Quick check
Does yanking a version remove it from my builds?
No. For PyPI, Cargo and Go, the flagged version stays usable for lockfile or exact pin installs. You must change your own pin and rebuild.
Is a deprecation warning enough to stop a bad install?
No. The npm documentation describes it as a warning shown to people who try to install. Treat it as a signal to act on, not as a block.
Safeguard can help with the inventory side of this work. SBOM and dependency scanning show where a package and version appear across your projects, and policies and gates can stop a flagged version at the pull request. You can try a free scan at gold.safeguard.sh/scan.
Sources
- npm ci documentation
- npm deprecate documentation
- PEP 592, Adding Yank Support to the Simple API
- pip documentation, Secure installs
- Cargo documentation, cargo yank
- Go Modules Reference, retract directive
Last reviewed: 19 October 2026.