Skip to content

Build1 publisher2 min readPublished

npm trusted publishing now retags releases over OIDC behind an off-by-default checkbox

GitHub let npm trusted publishing move dist-tags with short-lived OIDC credentials on 2026-09-30, behind a permission that ships switched off. It closes the gap that sent teams back to a long-lived token just to point latest at a new release.

The Engineer · Build desk

What happened

  • Each trusted publishing configuration on an npm package gains an 'Allow npm dist-tag' permission that lets its workflows promote a version to latest or move next and beta from CI.
  • The permission is independent of publish rights, so one configuration can retag without publishing and another can publish without retagging.
  • Classic token-based dist-tag management keeps working, so scripts and cron jobs on long-lived automation tokens carry on unchanged.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision Maintainers have to schedule the revocation themselves, because the long-lived token keeps its retag rights even after the automation moves to OIDC.
  • exposure One over-granted preview or staging configuration is enough to let ordinary CI runs repoint latest, recreating the standing authority OIDC publishing was adopted to remove.
  • capability A package can now run its whole release, publish and promotion to latest, with no long-lived npm secret stored in CI.

On npm, publishing a version and pointing a tag at it are two separate writes. An `npm install` with no version range resolves against `latest` [7]. A dev.to write-up of the change spells out the attack that follows: a stolen publish credential lets someone push a bad version, and the right to run `npm dist-tag add` against `latest` sends every unpinned install to it until a human notices [14].

The same write-up says "most teams" kept a classic token around specifically for retagging [8]. That share is the author's estimate. The post does not include a count of packages still holding a retag-only token.

Authorization is an any-match rule. An incoming OIDC token can retag if it matches any configuration on the package with the permission switched on [5]. The runs allowed to move `latest` are therefore the union of every ticked configuration [1]. Matching uses the token's claims, such as repository, workflow and environment [9]. "The checkbox is only as strict as the token claims you check it against," the write-up says [15].

Splitting retag from publish is the right design for a registry whose default install target is mutable. PyPI trusted publishing covers uploads, and pip installs the highest non-yanked version, with no mutable tag between upload and install [12]. RubyGems mirrors PyPI, authenticating `gem push` via OIDC from a GitHub Actions workflow bound to specific claims [13]. npm's `latest` is a second piece of registry state, and until this release OIDC could not write it [1].

The author recommends one release configuration as the only holder of retag rights. It is pinned to a specific workflow file at a specific path and gated on an environment with required reviewers, while publish-only configurations ship day-to-day versions [10]. I think that is the right default for any package with real downstream installs. The cost is a reviewer's sign-off on every promotion to `latest` [10].

What to watch

  • A date from npm or GitHub for restricting classic-token dist-tag management would turn this opt-in migration into a deadline.
  • Whether npm records which trusted publishing configuration authorized a given dist-tag change, so maintainers can audit retags after the fact.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories