Skip to content

[BUG] Trusted publishing auto-provenance silently discards the --provenance-file bundle #9879

Closed

Description

@yunseo-kim

Is there an existing issue for this?

  • I have searched the existing issues

This issue exists in the latest npm version

  • I am using the latest npm

This is not just a request to bump a dependency for a CVE

  • This is not solely a request to bump a dependency for a CVE

Current Behavior

When publishing with an externally generated provenance bundle under OIDC trusted
publishing (npm publish <tarball> --provenance-file=<bundle> from GitHub Actions,
public repository, public package), npm silently discards the supplied bundle and
publishes its own auto-generated provenance instead.

Mechanism (npm 12.0.2, commit b888cc9):

  1. lib/commands/publish.js calls oidc() unconditionally before reading credentials
    (L145-L155). The OIDC flow auto-enables provenance when the config is at its default
    (lib/utils/oidc.js L144-L168: config.isDefault('provenance') →
    opts.provenance = true).
  2. In libnpmpublish/lib/publish.js buildMetadata() (L145-L179), the inner
    if (provenance === true) branch runs generateProvenance(), so the inner else
    (verifyProvenance(subject, provenanceFile), the only code path that reads the
    supplied file) never executes.
  3. The registry therefore receives npm's generated statement (builder.id =
    https://github.com/actions/runner/github-hosted, internalParameters.github,
    sha512-only subject) in place of the supplied one. No warning or error is emitted;
    the publish "succeeds".

The same structure exists in v11.5.1 (commit da1d4d2), so the whole trusted-publishing
release line is affected.

Additionally, every documented way to disable automatic provenance is unusable in
combination with --provenance-file:

  • NPM_CONFIG_PROVENANCE=false: on 12.0.2 the env value is silently skipped when
    --provenance-file is set via CLI (the where === 'env' carve-out in
    @npmcli/config #loadObject); on 11.5.1 the same combination throws
    --provenance can not be provided when using --provenance-file.
  • provenance=false in user/global npmrc: throws the same exclusive-config error.
  • publishConfig.provenance=false: the manifest flatten happens after oidc()
    runs (commands/publish.js L248-L280 vs L145-L155), so it cannot prevent the
    auto-enable.

Expected Behavior

The --provenance-file documentation states: "When publishing, the provenance bundle
at the given path will be used."

Expected: an explicitly supplied --provenance-file takes precedence over the implicit
OIDC auto-provenance (the supplied bundle is verified via verifyProvenance() and
published), or, if the combination is considered invalid, npm rejects it explicitly
with a clear error. npm must not silently discard a caller-supplied, cryptographically
meaningful artifact. The trusted-publishing documentation should also state how
automatic generation interacts with --provenance-file.

Steps To Reproduce

  1. Environment: GitHub Actions workflow on a public repository, with
    permissions: id-token: write, and an npm trusted publisher configured for the
    repository + workflow filename. Target package is public.
  2. Config: no provenance settings anywhere (defaults); generate or obtain a valid
    Sigstore provenance bundle for the tarball by external means (the documented purpose
    of --provenance-file, e.g. PR feat: add --provenance-file flag for publish command #6490).
  3. Run: npm publish <pkg>.tgz --provenance-file=<bundle>.json --registry=https://registry.npmjs.org
    (npm 11.5.1+; verified through 12.0.2).
  4. After publish, fetch
    https://registry.npmjs.org/-/npm/v1/attestations/<url-encoded-pkg>@<version>,
    select the https://slsa.dev/provenance/v1 entry, and base64-decode
    .bundle.dsseEnvelope.payload.
  5. Observe: the statement is npm's generated shape
    (externalParameters.workflow, internalParameters.github,
    builder.id = https://github.com/actions/runner/github-hosted, sha512-only subject),
    not the supplied statement. The supplied bundle was never read.

Note: npm publish --dry-run does not invoke libnpmpublish's provenance path, so this
is only observable on a real publish — a disposable scoped test package is recommended.

Real-world evidence: observed during a live publish of @windlass/vers-js@0.1.2
(workflow run: https://github.com/windlasstech/vers-js/actions/runs/31840088262); the
registry's SLSA provenance payload differs byte-for-byte from the bundle that was
passed via --provenance-file (preserved build artifact available on request).

Environment

  • npm: 11.17.0 (observed live); code path verified identical in 11.5.1 and 12.0.2 sources
  • Node.js: v24.19.0
  • OS Name: Ubuntu 24.04.4 LTS (GitHub-hosted runner)
  • System Model Name: GitHub Actions ubuntu-24.04
  • npm config:
    ; node bin location = /opt/hostedtoolcache/node/24.19.0/x64/bin/node
    ; node version = v24.19.0
    ; npm local prefix = /home/runner/work/vers-js/vers-js
    ; npm version = 11.17.0
    ; cwd = /home/runner/work/vers-js/vers-js
    ; HOME = /home/runner
    ; Run `npm config ls -l` to show all defaults.
    Note: the original failure occurred inside a reusable workflow that invokes npm
    with stronger isolation (stripped NPM_CONFIG_* env, empty user/global
    config files, isolated temp cwd) — so ambient configuration cannot explain the
    substitution. The reusable-workflow indirection does not affect the bug: npm still
    runs on a GitHub-hosted runner with GITHUB_ACTIONS=true and OIDC request variables
    present, which is all the auto-enable path requires.

Full downstream root-cause analysis, including a byte-level comparison of the
supplied bundle versus the statement actually published by the registry:
windlasstech/slsa-builder#97

Activity

  1. added
    Priority 2secondary priority issue
    cmd:publishrelated to `npm publish`
    and removed
    Needs Triageneeds review for next steps
    on Aug 18, 2026
  2. self-assigned this
    on Aug 25, 2026
  3. added a commit that references this issue on Sep 3, 2026
    c9876d7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Bugthing that needs fixingPriority 2secondary priority issuecmd:publishrelated to `npm publish`ws:libnpmpublishRelated to the libnpmpublish workspace.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions