Skip to main content

Command Palette

Search for a command to run...

Software publishing is moving beyond long-lived tokens

Package registries are replacing reusable CI secrets with workload identity, short-lived credentials, provenance, and staged approval.

Updated
22 min readView as Markdown
Software publishing is moving beyond long-lived tokens

Publishing software used to depend on a secret.

A maintainer created an API token in a package registry, copied it into a CI secret store, and allowed a workflow to use it every time a release was published. The token might remain valid for months or years. It might have access to one package, several packages, or an entire organization.

The model was simple.

It was also fragile.

A reusable publishing token can leak through logs, compromised dependencies, malicious workflow changes, exposed build environments, copied configuration, or a maintainer's local machine. Once stolen, it can often be reused from somewhere else until it expires or someone notices and revokes it.

That risk is no longer theoretical enough to ignore.

Package registries and CI platforms are moving toward a different model called trusted publishing. Instead of storing a permanent registry credential, the release workflow proves its own identity using OpenID Connect, or OIDC. The registry verifies claims about the CI provider, repository, workflow, environment, and other context. It then issues a short-lived, tightly scoped credential for that release.

The workflow does not need to remember a registry password.

It proves what it is.

This model is already available across npm, PyPI, RubyGems, NuGet, and other ecosystems. npm trusted publishing reached general availability in 2025 and supports GitHub Actions, GitLab CI/CD, and CircleCI. In 2026, npm added staged publishing, allowing CI to submit a package into a review queue while requiring a human maintainer with two-factor authentication to approve the final release.

This is more than a token replacement.

Software publishing is becoming an identity, policy, and provenance system.

Why package publishing outgrew static tokens

Long-lived tokens became common because automation needed a non-interactive credential.

A human maintainer could authenticate with a password and two-factor authentication, but a release workflow needed something it could use without waiting for a person. Registries solved this by issuing API tokens.

The CI configuration usually looked like this:

- name: Publish package
  run: npm publish
  env:
    NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

The workflow was automated, but the security model was still based on possession of a secret.

Whoever had the token could act as the publisher.

A static secret has a long attack window

A long-lived token may remain usable long after it is copied.

If an attacker steals it today, they may be able to use it tomorrow, next week, or next month. The registry usually cannot tell whether the request came from the intended CI workflow or from an unrelated machine.

A registry can reduce the risk with scoped tokens, expiration dates, two-factor authentication, and secret scanning. Those controls help, but they do not change the basic model.

The token is still a reusable bearer credential.

If you possess it, the registry may trust you.

Rotation creates operational debt

Security teams often respond to reusable credentials by requiring regular rotation.

That sounds simple until an organization publishes hundreds of packages through many workflows.

Every token has a lifecycle:

  • Creation

  • Scope assignment

  • Secret storage

  • Distribution to the correct workflow

  • Rotation

  • Revocation

  • Incident response

  • Offboarding

  • Audit

Rotation can fail in several ways.

A new token is created but not installed in every workflow. An old token remains active after replacement. A package is maintained by a team that no longer exists. A release job silently depends on a token nobody remembers. A token with organization-wide access is reused because per-package management feels too expensive.

The more packages an organization owns, the more credential management starts to look like infrastructure.

Secrets are copied into systems that do not need permanent authority

A release job may run for a few minutes.

Why should it hold a credential that remains valid for months?

The mismatch is important.

A workflow needs temporary permission for one action. A long-lived token gives it persistent authority before, during, and after the release.

Trusted publishing closes that gap.

Token scope often grows for convenience

Maintainers know least privilege is important.

Real workflows still drift toward broad access.

One token may publish many packages. One organization secret may be shared across repositories. A token may have bypass-two-factor privileges because CI cannot complete an interactive challenge. An old automation token may keep write access after the workflow is retired.

This is not always negligence. It is often a usability problem.

When secure credential management is hard, teams choose the path that keeps releases working.

A better publishing model should reduce both risk and maintenance.

Package publishing is a high-value supply chain boundary

A package release is not an ordinary API call.

A compromised release can reach thousands or millions of downstream users. A malicious version may be installed automatically through dependency updates, build pipelines, developer machines, and production deployments.

That makes publishing credentials unusually valuable.

The attacker does not need to compromise every consumer. They only need to compromise the publisher once.

The software supply chain turns one publishing action into widespread distribution.

That is why package registries are moving away from credentials that can be copied and reused anywhere.

How trusted publishing changes authentication

Trusted publishing replaces secret possession with workload identity.

The CI platform becomes an identity provider. During the release job, it creates a short-lived OIDC token containing signed claims about the running workload.

The package registry verifies those claims against a policy configured by the package owner.

If the identity matches, the registry issues temporary publishing authority.

The important change is that the release authority is created just in time.

There is no permanent registry secret sitting in the repository settings.

OIDC tokens describe the workload

An OIDC identity token can include claims such as:

  • Token issuer

  • Intended audience

  • Repository owner

  • Repository name

  • Workflow file

  • Commit reference

  • Branch or tag

  • Environment

  • Job identity

  • CI project or pipeline identifier

The exact claim set depends on the provider.

A registry policy might say:

Allow the workflow release.yml in repository acme/payments-sdk to publish package @acme/payments-sdk when the workflow runs in the npm-production environment.

That is much more specific than:

Allow anyone with this token to publish.

The workflow identity is cryptographically signed by the CI platform. The registry verifies it without sharing a permanent secret with the workflow.

Short-lived credentials reduce replay value

PyPI documents that the API tokens created through its trusted publishing flow expire no more than 15 minutes after authorization. NuGet describes temporary API keys valid for one hour and issued through a one-token, one-key exchange.

The exact lifetime varies by registry.

The principle is the same.

A stolen short-lived credential has a small reuse window. It is also scoped to the publishing operation and package policy.

This does not make theft harmless. OIDC tokens and temporary credentials are still sensitive. An attacker who steals one quickly may use it before expiration.

But the damage window is much smaller than with a token that remains active for months.

npm trusted publishing is now a practical workflow

npm trusted publishing currently supports:

  • GitHub Actions on GitHub-hosted runners

  • GitLab CI/CD on GitLab.com shared runners

  • CircleCI Cloud

npm's current documentation requires npm CLI 11.5.1 or later and Node.js 22.14.0 or later for trusted publishing.

A package owner configures the trusted publisher in npm by selecting the CI provider and identifying the allowed repository and workflow. npm can also restrict the relationship to direct publishing, staged publishing, or both.

A minimal GitHub Actions publishing workflow looks like this:

name: Publish package

on:
  release:
    types: [published]

permissions:
  contents: read
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: npm-production

    steps:
      - name: Check out source
        uses: actions/checkout@v6

      - name: Set up Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 24
          registry-url: https://registry.npmjs.org

      - name: Install dependencies
        run: npm ci

      - name: Test package
        run: npm test

      - name: Build package
        run: npm run build

      - name: Publish package
        run: npm publish --access public

There is no NPM_TOKEN secret.

The id-token: write permission allows GitHub Actions to request an OIDC token for the job. npm detects the supported OIDC environment and performs the trusted publishing exchange.

The workflow still needs protection. Removing the registry token does not make the workflow safe by itself.

Trusted publishing is spreading across ecosystems

This is not an npm-only feature.

PyPI calls the model Trusted Publishers and supports identity exchange from providers including GitHub Actions, GitLab CI/CD, Google Cloud, and ActiveState. RubyGems supports trusted publishing from GitHub Actions. NuGet is rolling out a similar trusted publishing policy based on GitHub Actions OIDC.

The OpenSSF has published guidance for package repositories to adopt the same architecture.

Registry Trusted publishing model Typical CI identity
npm OIDC exchange for short-lived publishing authority GitHub Actions, GitLab CI/CD, CircleCI
PyPI OIDC Trusted Publishers GitHub Actions, GitLab CI/CD, Google Cloud, ActiveState
RubyGems OIDC exchange for short-lived gem API token GitHub Actions
NuGet OIDC exchange for temporary API key GitHub Actions

The implementations are not identical, but the architectural direction is consistent.

Registries are learning to trust workload identities instead of stored credentials.

The CI workflow becomes part of the authorization boundary

With a static token, the main security object is the secret.

With trusted publishing, the main security object is the workflow identity and the code that can invoke it.

This changes what maintainers need to protect.

The release workflow file, branch protection, environment rules, tag creation, repository permissions, and reusable workflow dependencies all become part of the publishing authorization path.

That is not a drawback. Those controls were already important.

Trusted publishing makes the real trust boundary explicit.

Identity is not integrity

Trusted publishing answers an important question:

Did this publishing request come from the workflow identity that the package owner authorized?

It does not answer every supply chain question.

It does not prove that the source code is safe. It does not prove that the dependencies are safe. It does not prove that the workflow built the intended files. It does not guarantee that a maintainer's repository account was not compromised.

Authentication is one layer.

A mature publishing pipeline also needs provenance, review, and verification.

Build provenance is signed metadata describing how an artifact was produced.

It may include:

  • Source repository

  • Commit SHA

  • Workflow

  • Build environment

  • Triggering event

  • Artifact digest

  • Build instructions

npm can automatically generate provenance attestations when trusted publishing is used with supported providers. Its documentation currently lists GitHub Actions and GitLab CI/CD for provenance generation.

GitHub artifact attestations use OIDC identity and Sigstore to create signed claims about build artifacts. For public repositories, the generated bundle is also recorded in a public transparency log.

Provenance lets consumers verify that the package was built by the expected workflow from the expected repository and commit.

It does not prove the code was good.

It makes the origin inspectable.

Trusted publishing and provenance solve different problems

Control Question it answers
Trusted publishing Is this workflow identity authorized to publish?
Provenance Where and how was this artifact built?
Artifact signature Has the artifact changed since it was signed?
SBOM Which components and dependencies are included?
Review and branch protection Who approved the source and workflow changes?
Staged publishing Did a human approve the exact package before release?
Deploy policy Is this artifact allowed into the target environment?

These controls reinforce each other.

Trusted publishing without provenance authenticates the publisher but gives consumers less information about the artifact.

Provenance without verification creates metadata nobody uses.

A signed artifact without a protected build workflow may faithfully prove that an attacker-controlled workflow produced it.

Supply chain security depends on connected controls.

Staged publishing adds proof of presence

npm staged publishing became generally available in May 2026.

Instead of making a package immediately installable, the CI workflow uploads the prebuilt package tarball into a stage queue. A maintainer reviews and approves it with two-factor authentication before the version becomes public.

This separates automation from final release authority.

The CI system can build and submit the package, but it cannot silently make it public if the trusted publisher is configured for stage-only access.

A recommended npm design is:

  1. Configure a trusted publisher that allows npm stage publish but not direct npm publish.

  2. Let CI build, test, and upload the package to the stage queue.

  3. Require a maintainer to inspect and approve the exact staged artifact.

  4. Publish the already staged tarball without rebuilding it.

This provides two different assurances:

  • The package came from the authorized workflow.

  • A human maintainer was present for the final release.

Build once and promote the same artifact

A common release mistake is rebuilding at every stage.

The artifact tested in CI may not be byte-for-byte identical to the artifact published later. Dependency resolution, timestamps, environment differences, generated files, or compromised release infrastructure can change the result.

A stronger pipeline builds once, records the digest, stages that artifact, and promotes the same bytes.

The package digest becomes the identity of the release artifact.

The release pipeline should not quietly replace it after approval.

Provenance becomes valuable when policy checks it

GitHub's artifact attestation documentation is clear that generating attestations alone does not create the full security benefit. Consumers or deployment systems need to verify them.

A policy might require:

  • Artifact digest matches the downloaded package

  • Provenance issuer is GitHub Actions

  • Repository belongs to the expected organization

  • Workflow is an approved reusable workflow

  • Build originated from a protected branch or signed tag

  • Environment matches production release policy

  • Attestation is present and cryptographically valid

This is where publishing security starts to connect with deployment security.

A package is not trusted merely because it exists in a registry. It is accepted because its identity and provenance match policy.

What trusted publishing does not solve

Trusted publishing removes one dangerous class of long-lived publishing secret.

It does not make the release pipeline invulnerable.

The attack surface moves from token storage toward source control, workflow authorization, CI execution, and dependency integrity.

Teams need to understand that shift.

A malicious workflow can still publish malicious software

If an attacker can modify the authorized workflow or the source code it builds, the workflow identity may still be valid.

The registry sees the correct repository and workflow. It cannot know that the workflow was changed maliciously unless surrounding controls prevent or detect that change.

Protect release workflows with:

  • Branch protection

  • Required pull-request reviews

  • CODEOWNERS for workflow files

  • Protected tags

  • Restricted release permissions

  • GitHub environment approvals where appropriate

  • Minimal repository write access

  • Audit logging

  • Security review for reusable workflows

Trusted publishing should be paired with source control governance.

Third-party actions and build dependencies remain powerful

A release workflow often runs code from:

  • GitHub Actions

  • Build plugins

  • Package managers

  • Compilers

  • Test tools

  • Release automation libraries

  • Shell scripts

Any of these may influence the package contents or steal temporary credentials during the short window when they exist.

Short-lived does not mean inaccessible.

Reduce risk by:

  • Pinning third-party actions to immutable commit SHAs

  • Reviewing action source and permissions

  • Keeping id-token: write limited to the publish job

  • Running untrusted tests in a separate job without publishing authority

  • Avoiding secret access in pull-request workflows from forks

  • Using lockfiles and deterministic dependency installation

  • Separating build and release roles where practical

The release job should be small and boring.

OIDC trust policy can be misconfigured

A trusted publisher policy that is too broad can authorize more workflows than intended.

Risky configurations include:

  • Trusting an entire organization without workflow restrictions

  • Allowing an unprotected branch

  • Omitting an environment condition where one is available

  • Trusting a reusable workflow that many unreviewed repositories can call

  • Allowing both direct and staged publishing when only staged publishing is needed

  • Keeping old trusted publisher policies after repository migration

Treat trust policy like an API authorization rule.

Review it regularly.

Temporary credentials are still credentials

PyPI warns that OIDC tokens and the short-lived API tokens exchanged from them are sensitive.

An attacker who intercepts one may use it before expiration.

Do not print tokens to logs. Do not pass them through unnecessary steps. Do not expose them to untrusted build scripts. Do not assume a fifteen-minute credential cannot cause damage.

The shorter lifetime reduces impact.

It does not remove the need for isolation.

Private dependencies may still require secrets

Trusted publishing solves authentication to the destination registry for publishing.

The build may still need credentials to download private dependencies, access a private artifact store, query a signing service, or read release metadata.

Those credentials need their own security model.

Use workload identity for those systems where possible. When tokens remain necessary, keep them short-lived, narrowly scoped, and isolated from untrusted steps.

Do not celebrate a tokenless publish while leaving organization-wide package-read tokens exposed to the same job.

Self-hosted runner support varies

npm's current trusted publishing documentation supports hosted environments from GitHub Actions, GitLab CI/CD, and CircleCI Cloud. It states that self-hosted runners are not currently supported.

This limitation matters for organizations with private networks, custom hardware, compliance requirements, or internal build farms.

Do not work around it by silently restoring a broad permanent token.

Consider:

  • Building on self-hosted infrastructure, then publishing from a small hosted release job

  • Using staged publishing so hosted CI can submit an already verified artifact

  • Keeping a narrowly scoped expiring token as a temporary exception

  • Using an internal registry that supports workload identity

  • Tracking provider support and revisiting the design later

Migration may need an interim architecture.

Trusted does not mean safe

The word trusted can be misleading.

A trusted publisher is an authorized workload identity. It is not a guarantee that the package is free from malware, vulnerabilities, backdoors, or unsafe behavior.

PyPI's documentation explicitly makes this distinction. GitHub says artifact attestations establish origin and integrity claims, not that the artifact is secure.

Consumers still need:

  • Dependency review

  • Vulnerability scanning

  • Malware analysis

  • Version pinning

  • Lockfiles

  • Update policy

  • Runtime controls

  • Incident response

Authorization is not endorsement.

A practical migration roadmap

Moving away from long-lived publishing tokens should be a controlled identity migration.

The goal is not only to delete a secret. The goal is to make the release path easier to understand, harder to impersonate, and more accountable.

Step one: inventory every publishing credential

Find all credentials that can upload or modify packages.

Search:

  • CI secret stores

  • Organization secrets

  • Repository secrets

  • Local .npmrc, .pypirc, and equivalent files

  • Password managers

  • Release scripts

  • Container images

  • Infrastructure configuration

  • Old automation systems

  • Maintainer documentation

For each credential, record:

Field Example
Registry npmjs.org
Package scope @acme/*
Permissions Publish and settings write
Owner Developer Platform team
Storage location GitHub organization secret
Expiration 90 days
Workflow users release.yml in 18 repositories
Replacement npm trusted publisher

You cannot remove credentials you do not know exist.

Step two: map package ownership and release identity

Decide which repository and workflow should be allowed to publish each package.

One package should have a clear release source.

Questions to answer:

  • Which repository owns this package?

  • Which workflow builds the release?

  • Which branch or tag starts publishing?

  • Is a deployment environment used?

  • Who can edit the workflow?

  • Who can create the release tag?

  • Who approves production releases?

  • Does the package need direct or staged publishing?

This is a governance exercise as much as a technical one.

Step three: make the workflow deterministic and reviewable

Before adding publishing authority, simplify the release job.

A good release workflow should:

  1. Check out a reviewed commit.

  2. Install dependencies from a lockfile.

  3. Run tests.

  4. Build the package.

  5. Inspect the package contents.

  6. Generate or attach provenance.

  7. Stage or publish the exact artifact.

For npm, include a package inspection step:

- name: Preview package contents
  run: npm pack --dry-run

This helps catch credentials, source maps, test fixtures, local files, and oversized output before release.

Step four: configure the trusted publisher

For npm, configure the relationship in the package settings or through the npm trust command.

Bind the policy to the exact CI identity:

  • Provider

  • Repository or project

  • Workflow file or pipeline definition

  • Environment where supported

  • Allowed action

Prefer stage-only access for sensitive or widely used packages.

Delete obsolete trust relationships after repository or workflow changes.

Step five: remove the permanent publish token from CI

Update the release workflow to request OIDC identity and publish without the registry token.

For GitHub Actions, keep permissions explicit:

permissions:
  contents: read
  id-token: write

Do not give broad repository permissions to the publishing job unless it genuinely needs them.

Remove:

env:
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

After a successful test release, revoke the old token rather than leaving it as an undocumented fallback.

A credential that remains active is still an attack path.

Step six: add staged publishing where the risk justifies it

Use staged publishing for:

  • Popular public packages

  • Security-sensitive libraries

  • Organization-wide SDKs

  • Packages used in production infrastructure

  • Releases with many downstream consumers

  • Maintainer teams that want proof of human presence

The workflow command becomes:

npm stage publish --access public

The maintainer then approves the package from npm after reviewing the staged contents and metadata.

This gives CI automation and human review separate roles.

Step seven: generate and verify provenance

Confirm that the published package includes provenance where the registry and provider support it.

Check that provenance points to:

  • Correct repository

  • Correct commit

  • Correct workflow

  • Correct package version

For internal deployment systems, define policy for consuming packages and containers.

Examples:

  • Only install packages with expected repository provenance.

  • Only deploy containers built by approved reusable workflows.

  • Reject artifacts without an attestation in production.

  • Record verified digests in release metadata.

Provenance becomes useful when automated systems check it.

Step eight: harden the release source

Once the package registry trusts a workflow, secure the path that controls that workflow.

Recommended controls:

  • Require pull requests for the default branch.

  • Require reviews from package owners.

  • Add .github/workflows/ or equivalent paths to CODEOWNERS.

  • Protect release tags.

  • Restrict who can create releases.

  • Use environment reviewers for production publishing.

  • Pin third-party actions.

  • Separate test jobs from the OIDC-enabled publish job.

  • Avoid running untrusted pull-request code with release authority.

  • Review reusable workflow callers.

The registry now trusts your CI identity.

Make that identity difficult to hijack.

Step nine: monitor publishing as a security event

Publishing should create a clear audit trail.

Track:

  • Package name and version

  • Artifact digest

  • Source commit

  • Workflow run

  • Publisher identity

  • Provenance status

  • Stage approver

  • Approval time

  • Release time

  • Failed publishing attempts

  • Trust policy changes

  • Credential creation and revocation

Alert on unusual events:

  • Release from an unexpected workflow

  • Publishing outside normal branches or tags

  • Package version created without provenance

  • Direct publish when stage-only is expected

  • Trusted publisher configuration changes

  • New owner or maintainer added

  • Repeated failed token exchanges

A release is a production change.

Observe it like one.

Step ten: scale the model across many packages

Large organizations need reusable release architecture.

Possible pattern:

A shared workflow can standardize:

  • Node and package manager versions

  • Test requirements

  • Package inspection

  • Provenance

  • Staged publishing

  • Release metadata

  • Notifications

  • Audit collection

Be careful with reusable workflows. They become high-value infrastructure. Protect their repository, review changes carefully, and version them safely.

The target architecture

A mature release path has several layers of trust.

No single control carries the whole security model.

  • Source review protects the code and workflow.

  • OIDC authenticates the publishing workload.

  • Short-lived credentials reduce replay value.

  • Provenance records origin and build context.

  • Staging adds human presence.

  • Verification lets consumers enforce policy.

This is the larger change behind trusted publishing.

Software release is moving away from a secret copied into CI.

It is becoming a chain of verifiable identities and decisions.

A long-lived token says:

Whoever holds me may publish.

A modern publishing pipeline says:

This approved workflow, from this repository, running in this protected environment, may submit this exact artifact, with this provenance, for this package, for a short period of time, under this release policy.

That is a much stronger statement.

And it is quickly becoming the new baseline for publishing software.

References