high

CVE

Not assigned

CWE

CWE-346, CWE-863

Affected Surface

  • More than 1,500 npm packages that had Trusted Publishing configured against GitHub repository slugs that later became claimable before the binding's first successful publish, according to Bloom Security's scan
  • npm packages using GitHub or GitLab trusted publishing where maintainers renamed, transferred, or deleted the bound project before completing an initial validating publish
  • Consumers and internal controls that treat a green provenance attestation as sufficient without separately checking that the attested repository is still the repository the project meant to trust

The strongest new npm story from the last three days is not a poisoned tarball. It is a trust-binding flaw in the control plane that decides who is allowed to publish the next tarball.

Bloom Security’s “SlugFest” write-up shows that npm Trusted Publishing used the repository slug and workflow basename as the effective authorization check until the first successful publish validated the binding. If a maintainer created that trust relationship, then renamed, transferred, or deleted the bound repository before the first publish happened, the old owner/repo path could become claimable by someone else. The attacker did not need the maintainer’s npm token. They did not need the maintainer’s GitHub account. They only needed the abandoned slug and a matching workflow file name.

What was affected

Bloom says its registry-wide scan found more than 1,500 exposed npm packages with more than 10 million total downloads and more than 1 million monthly downloads. The researchers did not publish a package list while the issue was still live, so this is one of the few supply-chain stories where the exact package inventory matters less than the trust pattern:

package has Trusted Publishing configured
  -> binding points at owner/repo plus workflow file name
  -> maintainer renames, transfers, or deletes that repo before first publish
  -> old slug becomes claimable
  -> attacker recreates the slug and matching workflow file
  -> registry issues a valid publish credential

Help Net Security reports that Bloom’s vulnerable set included security tools, auth packages, and cryptographic packages. That is enough to treat this as a registry-wide control failure, not a niche CI bug.

The affected projects fall into three practical groups:

  1. packages that had an unvalidated Trusted Publishing binding against a GitHub slug that later became claimable
  2. packages using the same model through GitLab, which Bloom says had the same weakness
  3. downstream consumers whose provenance checks stopped at “the package is signed” rather than “the package is signed by the repository this project is actually supposed to come from”

How Trusted Publishing worked, and where it broke

The normal Trusted Publishing story is sound. A release workflow gets a short-lived OIDC token from GitHub Actions, then exchanges that token at npm for a publish credential that expires within minutes. That design removes long-lived npm tokens from CI.

The problem was the identity record npm stored before first use. Bloom says the binding effectively captured fields like:

repository: owner/repo
workflow_ref.file: release.yml
environment: optional environment name

GitHub’s OIDC token already carried stronger identifiers:

{
  "repository": "owner/repo",
  "repository_id": "123456789",
  "repository_owner_id": "987654321",
  "workflow_ref": "owner/repo/.github/workflows/release.yml@refs/heads/main"
}

The repository ID and owner ID are the durable claims. They survive renames and transfers. The slug does not.

Before the fix, npm did not bind to those immutable IDs until the first successful publish validated the relationship. That left a gap where the registry could still see a token whose repository claim matched the stored slug, even though the numeric repository identity behind that slug belonged to a completely different project.

The attack path needed no stolen credential

Bloom’s reproduction is mechanically simple:

victim package trusts owner/repo + release.yml
  -> victim later frees that owner/repo slug
  -> attacker creates a new repository at the same slug
  -> attacker adds .github/workflows/release.yml
  -> workflow requests id-token: write
  -> GitHub mints an OIDC token for the attacker's repository
  -> npm checks the slug and workflow basename, sees a match, and returns a publish credential

A minimal publish workflow can be ordinary-looking:

permissions:
  id-token: write
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm publish

That is what makes this bug worth reading closely. Nothing in the exploit path looks like credential theft because no credential theft is required. The attack wins by inheriting a stale trust relationship.

Why provenance could still look green

A Trusted Publishing compromise is not the same thing as an unsigned publish. The attacker still goes through the normal OIDC exchange path, so the resulting release can carry a valid provenance attestation.

The catch is what that attestation proves.

attestation says:
  this package was published by GitHub Actions
  from repository X

it does not say:
  repository X is still the maintainer's intended repository

If your verification logic only checked “is there a valid attestation?” then SlugFest could still produce a green answer. The repository in the attestation would be the attacker’s reclaimed slug, not the original repository the maintainer thought they had trusted.

That same pattern shows up in other 2026 package incidents. Provenance proves origin. It does not prove that your authorization boundary was modeled correctly when the publish right was granted.

What GitHub and npm changed

GitHub’s October 2 changelog says unvalidated npm trusted-publishing configurations now expire after 48 hours. npm’s documentation now says a newly created Trusted Publisher must complete its first successful publish within two days, and that first publish binds the configuration to the repository’s immutable identity.

GitHub also says npm now rejects trusted-publishing tokens from issue_comment events, alongside the earlier pull_request_target restriction.

That helps for newly created or still-unvalidated bindings. It does not change the operational lesson:

human-readable name != immutable identity

Any publish control that authorizes by slug first and numeric identity later is taking avoidable risk.

What to check

If you maintain npm packages, start with the trust bindings themselves:

npm trust list

Look for bindings that still point at repositories you renamed, transferred, or deleted. If the binding refers to an old slug, delete it and recreate it against the current repository.

Then audit release workflows for the token-exchange preconditions:

rg -n 'id-token:\\s*write|npm publish|workflow_dispatch|release\\.ya?ml' .github/workflows

For consumers and internal package-security teams, provenance review needs one extra step. Do not stop at “the package has an attestation.” Verify that the attested repository is the repository you intended to trust.

Response guidance

  1. Enumerate every package you publish with Trusted Publishing and confirm the bound repository still belongs to you.
  2. Recreate any binding that points at a renamed, transferred, or deleted repository slug.
  3. Treat repository deletion or transfer as a publishing-authorization event, not just a source-control cleanup task.
  4. Review provenance validation logic in internal tooling so it checks repository identity, not just attestation presence.
  5. If your organization publishes through GitLab as well, review those bindings too. Bloom says the same weakness existed there.

SlugFest shows where this class of control usually fails. The token exchange can be correct while the name-to-publisher binding just before it is wrong.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References