Trusted Publishing is the good advice. Instead of keeping a long-lived npm token in a secret store where it can be stolen, a package trusts a specific GitHub repository, and a workflow in that repository gets a short-lived credential when it publishes. No token to leak.
Researchers at Bloom Security found that npm was identifying that repository by its name.
Names are not identifiers
A GitHub repository has a permanent numeric id and a human-readable name. The id never changes. The name is a label the owner can rename, transfer, or release by deleting the repository — and once released, anyone can take it.
npm's Trusted Publishing checked the name.
So the attack is: find a package whose trusted publisher points at a repository that has been renamed, transferred away, or deleted. Create a repository with that old name. Add a GitHub Actions workflow matching what the trust relationship expects. Publish.
Claiming a released repository name this way yields a valid publishing credential for somebody else's existing npm package, obtained without stealing a single maintainer credential. Nothing was phished and no token leaked. The trust relationship simply pointed at a label, and the label had changed hands.
The researchers call it SlugFest.
What it could and could not do
Precision matters here because the headline reads worse in one direction and better in another.
It could not create new packages under someone else's name. It could publish new versions of existing packages — which is worse, because an existing package has installs, a dependency graph, and automation that will fetch the new version without anyone looking at it.
More than 1,500 packages configured for Trusted Publishing were exposed, with over 10 million combined downloads.
Bloom reports no observed exploitation in the wild, and confirmed the technique worked under its own controlled test. Whether anyone used it before the fix is unknown and, given the mechanism leaves no trace of theft, may stay unknown.
This is the dangling-pointer problem again
A name that outlives the thing it pointed at is a pattern this site keeps arriving at from different directions. A DNS record left pointing at infrastructure nobody owns any more is the version that gets written about most, and it is the same failure: a reference held by label rather than by identity, and a label that can be re-registered.
The uncomfortable part is where it turned up. Trusted Publishing exists because credentials get stolen; it is the hardened replacement. The flaw was not in the thing security people warned about. It was in the thing they recommended instead.
That is not an argument against adopting it. It is an argument for reading what a new trust mechanism actually trusts.
The binding breaks at the moment nobody is looking
Think about when a repository gets renamed, transferred or deleted.
A maintainer hands a project to somebody else. A company is acquired and its repositories move into a new organisation. A team restructures and tidies its namespace. Somebody archives a side project from four years ago and deletes it.
Every one of those is a moment when the publishing trust relationship is the last thing anybody checks, and several of them are moments when the person who now owns the package was not there when the binding was made. They inherited a package that trusts a name they have never heard of.
That is why the exposure is not a handful of careless maintainers. It is the ordinary lifecycle of open-source projects, applied to a mechanism that assumed names are stable.
The fix, and what it does not cover
GitHub's change, published on 2 October: an unvalidated Trusted Publishing configuration now expires 48 hours after creation and can no longer authorise publishing. A configuration stops expiring once it has successfully published at least once. If yours expires, recreate it for a fresh window.
npm also now rejects Trusted Publishing tokens from GitHub Actions issue_comment events, alongside the existing restriction on pull_request_target.
The limit is in the word "new". The expiry closes the window for configurations created from now on. It does not retroactively re-bind the ones that already exist, and GitHub's statement does not say whether configurations that had already published were bound to a repository id after the change.
So maintainers still have to check their own.
What to do
- Run npm trust list for your packages and confirm every repository listed still resolves to one you control.
- If a repository has been renamed, transferred, or had its owner change, delete the trust binding and create it again. The old one may be pointing at a name you no longer hold.
- Before deleting a repository that publishes a package, remove its Trusted Publisher configuration first. Deleting the repo releases the name while the trust relationship is still live.
- If you maintain something with meaningful install counts, this is worth doing today rather than at the next audit.
What is not established
- Whether anyone exploited this before the fix. No in-the-wild use has been reported, and the mechanism would not leave obvious evidence.
- Whether existing configurations that had already published are now bound by repository id. GitHub has not said.
- How many of the 1,500 exposed packages had a trust binding pointing at a genuinely claimable name, as opposed to one still held by the maintainer.
- Whether other registries that adopted the same pattern verify by name or by id.