Supply-chain security

npm trusted publishing finally covers dist-tags, if you ask nicely

npm trusted publishing finally covers dist-tags, if you ask nicely

Picture the npm maintainer who did the hard work: moved publishing to OIDC, deleted the automation token from the password manager, celebrated with coffee. Then shipped a patch and had to run npm dist-tag add from a laptop because the shiny new trusted publishing flow could push versions but not point latest at them. Awkward.

That gap closed this week. On 2026-09-30, GitHub announced that npm trusted publishing can now manage dist-tags through the same short-lived OIDC credentials it already uses to publish, instead of requiring a long-lived access token sitting somewhere unpleasant.

What the opt-in actually does

The announcement is narrow and specific. Each trusted publishing configuration on an npm package gets a new permission, labelled Allow npm dist-tag. Turn it on, and workflows authenticating with that configuration can promote a version to latest or move the next and beta pointers from CI, authenticated by the same OIDC token that would have published a version.

A few details worth pinning down:

  • The permission is off by default on both brand-new configurations and the ones you set up months ago. Nothing in your current setup silently gained new rights.
  • It is independent of direct publishing permissions. A staging-only configuration can be granted dist-tag management without also being allowed to publish, and vice versa.
  • Authorization triggers when an incoming OIDC token matches any configuration with the permission on.
  • Classic token-based dist-tag management keeps working. If you have a cron job somewhere that still uses an automation token, nothing changes for it today.

Why dist-tags are the loose brick

Publishing a version is only half of a release. The other half is pointing latest at it, because npm install your-pkg with no range resolves against latest. Whoever can rewrite latest can quietly aim an entire ecosystem at a different artifact.

That is the lateral-move path supply-chain attackers love. Steal a publish token and you can publish your-pkg@6.6.6, sure. But if you can also run npm dist-tag add your-pkg@6.6.6 latest, every unpinned install now pulls your version until a human notices. Historically that second step still needed a classic token, which meant most teams kept one around specifically for retagging, defeating the point of OIDC for publishing in the first place.

With dist-tag ops on OIDC, the "we moved to trusted publishing but kept one legacy token for tagging" footnote finally goes away, assuming you flip the box.

Turning it on without turning it loose

Two decisions sit under that single checkbox.

Which configurations get the power. The ergonomic failure mode is to tick Allow npm dist-tag on every configuration, including the one your preview workflow uses, because somebody will eventually need to retag during an incident and it is easier to pre-grant. That reproduces the problem OIDC was supposed to solve: broadly-scoped standing authority. The safer shape is a dedicated release configuration (bound to a specific workflow, a protected environment, maybe a manual approval) that is the only one allowed to retag, with publish-only configurations handling day-to-day versions.

What triggers it. Because the permission matches on the OIDC token's claims (repository, workflow, environment, and friends), what you are really doing is deciding which Actions runs are allowed to call the retag endpoint. Pin the configuration to a specific workflow file at a specific path and gate that workflow on an environment with required reviewers. The checkbox is only as strict as the token claims you check it against.

A worth-saying caveat: existing dist-tag automation that still relies on a long-lived token is not disabled by any of this. Shutting that path off is a separate decision you have to make, usually by revoking the token after you have moved the automation across. Shipping the new permission does not retire the old one for you.

How other registries and platforms handle release tags

Dist-tags are an npm concept, but "mint a short-lived credential in CI, use it to update a release pointer" is a pattern now, not a feature. A rough map:

  • PyPI trusted publishing was the reference implementation. It covers uploads, and effectively covers "which version pip installs by default" because PyPI picks the highest non-yanked version, with no mutable tag in the middle. Different model, same primitive: OIDC from your CI, no long-lived token sitting in a secret store.
  • RubyGems trusted publishing mirrors PyPI closely: gem push authenticated via OIDC from a GitHub Actions workflow bound to specific claims. Yanks and ownership changes are a separate authority there; the retag analogue is less of an issue because the "default" version is computed, not pointed-at.
  • GitLab CI reaches npm by federating its own ID tokens to the registry's OIDC trust. It is the better fit if your source of truth is a GitLab project and you want the publishing job's claims (project_path, ref, protected branch) to flow into the configuration you tie to the package. The new dist-tag permission applies the same way, because the gate is on npm's side.
  • CircleCI OIDC can do the same against npm's trust configuration, matching on CircleCI-specific claims. Honest trade-off: if your release workflow already lives on GitHub Actions, there is no real reason to add CircleCI to the path.
  • Jenkins does not get OIDC federation for free. Teams usually bolt on a plugin that mints an OIDC token the runner can present, or (more commonly) still ship a classic token into the agent. If you are on self-hosted Jenkins and this new permission matters to you, the honest answer is that the work is upstream of the checkbox.
  • Buddy is one option if you want the OIDC-emitting job and the retag step to live in the same place as the rest of your delivery pipeline, and you want environment-scoped approvals around a npm dist-tag action instead of inside a workflow file. A minimal shape:
# buddy.yml, illustrative shape only
- action: "Promote to latest"
  type: "BUILD"
  docker_image_name: "node"
  docker_image_tag: "lts"
  trigger_condition: "ON_EVERY_PUSH"
  trigger_conditions:
    - trigger_condition: "VAR_IS"
      trigger_variable_key: "GIT_REF"
      trigger_variable_value: "refs/tags/v*"
  execute_commands:
    - "npm whoami"
    - "npm dist-tag add $PACKAGE@$VERSION latest"

The point of listing six options is that none of them is "the best" in the abstract. Which one you pick is a function of where your source of truth already lives, how your approval model is shaped, and how much appetite you have for owning a plugin to make OIDC work.

The uncomfortable bit

The press release reads like a win, and it is. One less long-lived token in one less secret store is one less thing to rotate and one less thing to steal. But opt-in defaults mean the ecosystem benefit lands when maintainers actually open the settings panel and tick the box, not on 2026-09-30. Until then, every package that previously held an automation token for tagging is still holding it, OIDC or not.

Go turn it on. Then go delete the token.

Source: GitHub Changelog (github.blog)

Related
Security & supply chain

GTIG's agentic threat report is a CI/CD problem, not just an AI problem

Google's Threat Intelligence Group documents DUSTMAKER, an OIDC-stealing supply-chain payload from UNC6780 that ships valid SLSA Build 3 attestations. The moment a signed provenance line stops being a defence is the moment CI/CD owners have to rethink runner trust.

September 10, 2026
Security & supply chain

Docker Hub gets OIDC federation for GitHub Actions, retiring the PAT-in-a-secret pattern

Docker has added OpenID Connect authentication for GitHub Actions on Team, Business and Docker Hardened Images plans, so workflows push and pull images with a short-lived per-run token instead of a stored Personal Access Token. It closes off one of the last static credentials still sitting in most Actions repos.

August 1, 2026
Security & supply chain

The npm worm that shipped with valid SLSA provenance

A DevOps.com analysis of the Miasma npm worm makes an uncomfortable case: signing and provenance told the honest truth, and the pipeline still shipped malware. When the build platform itself is the attack surface, a green attestation is a description of the failure, not a defence against it.

July 22, 2026

Turn this into your pipeline. Build it on Buddy.

Start free