Software Supply Chain Security

Software supply chain security protects the path from someone else's source code to software running in your environment. Dependencies, package registries, build tools, CI workflows, and publishing identities all belong to that path. A secure application can still ship compromised code if its build or dependencies are compromised.

Coverage window: October 5, 2025–October 5, 2026. This guide uses npm's authentication changes and a documented package incident to explain practical controls. Foundational concepts below predate this window; dated developments are identified separately. The examples focus on JavaScript, but the separation of acquisition, build, and release applies across ecosystems.

TL;DR

Quick Example

Start with an offline inspection. Save this as audit-lockfile.mjs beside an npm lockfile using format 2 or 3, then run node audit-lockfile.mjs. It reads metadata without installing dependencies, accessing the network, or running package code.

The lockfile documentation defines these metadata fields. Workspaces, private registries, and native modules can produce legitimate findings. An empty report only means these checks found nothing; it does not establish that the dependency tree is safe.

Core Concepts

Integrity, identity, and intent

An integrity hash helps identify a particular artifact. A signature ties data to a signing identity. Neither answers whether the code does what your application needs or whether its behavior is acceptable. If a malicious release is the artifact you approved, faithfully retrieving its bytes preserves the problem.

Provenance

Provenance records how an artifact relates to source and its build. Consumers can examine that evidence when deciding whether to trust a release. npm explicitly states that provenance does not guarantee the absence of malicious code. Its provenance documentation also distinguishes this evidence from ordinary package metadata. npm provenance

Publishing authority

Trusted publishing uses OpenID Connect, or OIDC, to associate a CI workflow with registry publishing permission. Configure the intended repository and workflow precisely. For GitHub Actions, npm also supports an environment constraint. This reduces reliance on stored publishing secrets, while making protection of the authorized workflow particularly important. Trusted publishing documentation

Inventory

A software bill of materials, or SBOM, lists components. npm can produce CycloneDX or SPDX output with npm sbom; its lockfile-only mode reads the recorded dependency tree. That inventory helps locate affected releases, but it does not prove what a running deployment contains. Associate it with the actual build artifact. npm SBOM documentation

What Changed During the Last Year

November 2025: a concrete dependency incident

On November 24, 2025, Postman disclosed that public packages in its npm organization had been infected during the Shai-Hulud 2.0 campaign. Its notice identifies affected package versions and distinguishes those packages from its application and production cloud services, which it reported were not compromised. Use the version list and updated timeline when investigating historical exposure. Postman incident notice

The practical lesson is to investigate where a package was installed and executed, rather than assuming the scope of a familiar vendor's incident from its name alone.

December 2025: classic npm tokens stopped working

On December 9, 2025, npm permanently revoked classic tokens and introduced two-hour sessions for npm login. The announcement also documented a maximum 90-day lifetime for granular write tokens. December 9 is the completed revocation date; earlier migration announcements had proposed an earlier deadline. npm authentication changes

Audit release jobs for assumptions about permanent credentials. A pipeline that still expects an obsolete authentication method needs a publishing migration, not repeated retries.

September 2026: staging and promotion gained narrower controls

On September 18, 2026, npm introduced opt-in stage-only granular tokens. They can submit a version with npm stage publish, followed by maintainer approval using 2FA, but cannot directly publish a new version. They still retain other write capabilities, including changing dist-tags and deprecating versions. The announcement describes January 2027 removal of direct publishing through bypass-2FA tokens as a target, not a completed change within this guide's window. Stage-only token announcement

On September 30, npm added an independent, opt-in permission for trusted publishers to manage dist-tags using OIDC. This lets teams evaluate removing a stored token previously retained solely for promotion or rollback. The permission defaults to off. Dist-tag permission announcement

Build a Dependency-to-Release Workflow

Start dependency updates in a review branch. Inspect the manifest and lockfile diff together: a small direct upgrade can replace many transitive packages. Check unexpected registry origins, newly introduced installation scripts, and unexplained changes to the upstream release process.

Install in a disposable build environment with only the access needed for that job. npm ci --ignore-scripts suppresses package scripts during installation, but a later explicit npm test or npm run still executes the requested script. Some dependencies require reviewed build steps before they function correctly. npm ci behavior

Use separate checks for separate questions. npm audit asks the configured registry about known vulnerabilities; npm audit signatures verifies supported registry signatures and provenance attestations for downloaded packages. Neither result substitutes for reviewing code or release authority. npm audit documentation

Finally, promote an identified artifact through a controlled release job. Record its digest, source revision, dependency inventory, and approval. This gives responders something concrete to compare with deployed software.

Best Practices

Minimize credentials during builds

Give dependency-fetching jobs read-only registry access when required. Keep publishing authority out of pull-request tests. For example, a failed unit test should never have had permission to release a package in the first place.

Review the release boundary

Protect workflow changes and require appropriate review before release. A reviewer should inspect the artifact being approved, including generated files; approving only a source diff misses what packaging added or omitted.

Prepare incident evidence

Keep lockfiles and build records with release identifiers. During a suspected compromise, pause affected releases, identify executions, preserve evidence, and revoke exposed credentials from a clean environment. GitHub's December 2025 guidance describes compromised credentials and malicious installation scripts as recurring campaign mechanisms. GitHub supply-chain guidance

Comparison

Common Mistakes

Assuming a signature approves behavior

Bad: Accept every signed dependency automatically.

Correct: Verify expected identities and review changes according to the dependency's role and exposure.

Restoring a compromised build with the same secrets

Bad: Remove the affected dependency and immediately rerun the release job.

Correct: Investigate execution and credential exposure, rebuild in a clean environment, and replace affected credentials before restoring releases.

Treating development dependencies as harmless

Bad: Review only packages that ship inside the production bundle.

Correct: Include test tools, transpilers, and release utilities. Their execution can affect the resulting artifact or the machine building it.

FAQ

Does trusted publishing prevent every supply chain attack?

No. It reduces reliance on reusable publishing tokens. A compromised authorized workflow can still perform authorized actions, so source review and release controls remain necessary.

Is disabling installation scripts enough?

No. It reduces one execution opportunity. Dependency code can also execute when imported, tested, built, or run as a tool; isolation must cover those stages too.

Should every vulnerability alert block a release?

Set an explicit policy based on severity, reachability, available fixes, and the deployment context. Record exceptions with an owner and review date so a temporary decision does not become permanent neglect.

Can an SBOM replace a lockfile?

They serve different jobs. A lockfile guides dependency resolution; an SBOM communicates component inventory. Keep both associated with the build they describe.

Related Topics

References