A security control designed to eliminate long-lived software publishing credentials contained a weakness that could allow a different GitHub repository to publish to a trusted npm package. Bloom Security uncovered the issue during its SlugFest investigation, demonstrating an attack that relied on reclaiming a repository address rather than stealing credentials.
The researchers found more than 1,500 vulnerable npm packages with over 10 million combined downloads. They also determined that the issue remained exploitable for more than 120 days after disclosure, before Bloom confirmed that a fix had been implemented.
The vulnerability highlights a fundamental distinction in software security: verifying a name is not the same as verifying the identity of the entity behind it.
The Promise of Trusted Publishing
npm Trusted Publishing was introduced to address a longstanding problem in open-source software distribution: the use of long-lived automation tokens to authorize package releases.
These tokens can be stored in continuous integration environments and reused across publishing workflows. If exposed, they may give an attacker the ability to distribute malicious code under a legitimate package name.
Trusted Publishing replaces this model with OpenID Connect. A GitHub Actions workflow requests an OIDC token, presents it to npm’s exchange endpoint, and receives a short-lived publishing credential. npm made the feature generally available in July 2025.
Bloom’s research found that the underlying approach was not the problem. Instead, the weakness involved the information npm initially stored when a maintainer configured a trusted publisher.
Where Repository Identity Broke Down
When setting up Trusted Publishing, a maintainer associates a package with a GitHub repository using its owner and repository name, such as owner/repository. The configuration also includes the expected workflow filename and may include a GitHub Actions environment.
GitHub provides immutable numerical identifiers for repositories and their owners. Unlike repository names, these identifiers remain stable when repositories are renamed or transferred.
According to Bloom, npm’s initial trust configuration did not record the immutable identifiers until the repository had successfully published a package version. Before that first publication, the registry relied on the repository slug and workflow filename to evaluate the publishing request.
That created a specific weakness. If the original repository was renamed, transferred, or deleted before publishing, its former address could become claimable. An attacker who obtained the same address could create a new repository that appeared to satisfy the stored trust configuration even though GitHub assigned it a different repository identifier.
The vulnerability therefore depended on both a reclaimable slug and a trust binding that had not yet been used for a successful publication.
Reproducing the Attack
Bloom tested the issue end-to-end using a researcher-controlled npm scope and GitHub repositories. The researchers published to the npm package from a second repository belonging to a different organization. The two repositories shared the slug, but they were not the same repository.
The attack sequence was straightforward under the vulnerable conditions. First, the attacker claimed the freed repository address and created a workflow with the filename expected by the package’s Trusted Publisher configuration. The workflow then requested an OIDC token containing the reclaimed slug and the new repository’s immutable identifier.
The attacker submitted that token to npm’s exchange endpoint. Because the original binding relied on the slug and workflow filename, the registry could issue a valid temporary publishing credential without establishing that the token came from the originally intended repository.
No legitimate maintainer credential was required. The attacker did not need to compromise the maintainer’s npm account or GitHub account, either.
Why Package Signing Is Not the Whole Answer
A successful publishing attack can have consequences beyond unauthorized access to a package registry. The attacker may release a malicious version under the existing package name, inheriting its established reputation and relationships with dependent projects.
The release could include a postinstall hook that executes code when a developer or continuous integration system installs the package. If other packages depend on the compromised release, the exposure can extend through the dependency chain.
Bloom also highlighted a potential weakness in how downstream systems evaluate provenance. An attacker can produce a provenance attestation associated with their own repository. If a verification system checks only whether the package is signed, rather than whether the attested source matches the repository expected by the maintainer, the attestation may not establish the origin that consumers assume it does.
The distinction is between confirming that a release has an attestation and confirming that it came from the correct source.
The Scope of the Exposure
Bloom developed a scanner to identify packages with Trusted Publishing configured and test whether their associated repositories and owners were claimable.
The investigation found more than 1,500 vulnerable packages, with over 10 million total downloads and more than one million downloads per month. Those numbers refer to packages using the publishing feature, not the entire npm registry. Bloom did not release a list of affected packages because the issue remained prevalent at the time of its research.
The same investigation also examined how AI agents could increase the consequences of a compromised release. Across large enterprises, Bloom measured approximately 70 agent-installed packages per endpoint each month and close to 350 on developer machines. These totals exclude transitive dependencies.
Automated installation can make a malicious release easier to distribute because an agent may select and install a dependency without requiring a person to inspect its source or publishing history.
The Fix and the Disclosure Process
Bloom reported the issue through GitHub’s HackerOne program on June 6, 2026. The vulnerability was triaged and validated on June 9. On July 8, the last response before remediation, the team said it was working on a fix and assessing the issue’s risk and severity.
After six additional enquiries, including a mediation request through HackerOne, Bloom decided to prepare the findings for publication. The researchers sent the material to npm before publishing and repeated their test, discovering that a fix had been implemented. npm later confirmed the remediation and apologized for the lack of communication.
Bloom recommended resolving the GitHub repository and owner identifiers when trust is created, storing them alongside the slug, and requiring the repository identifier in the OIDC token to match the stored value during credential exchange. The research notes that PyPI’s Warehouse already implements this pattern. It also states that the issue affected npm’s GitLab Trusted Publishing implementation.
The Broader Lesson for Trust Systems
Repository names are useful identifiers for people, but they are not permanent proof of ownership. A secure publishing system must verify that a release originates from the repository that was originally authorized, even when names and ownership arrangements change.
For maintainers, Bloom recommends reviewing existing trust bindings, removing and recreating them after repository changes, and monitoring for unexpected publishing events. For registry operators, the research underscores the importance of validating immutable identities from the moment a trust relationship is established.
SlugFest demonstrates how a seemingly narrow omission can undermine an otherwise useful security mechanism. Short-lived credentials reduce exposure to stolen secrets, but the authorization process must still establish that the party requesting them is the right one.


