Integrating npm's Staged Publishing: Workflow considerations?
Just saw the update regarding GitHub's rollout of "staged publishing" for npm. This seems like a solid move to mitigate supply chain risks by enforcing a 2FA challenge before a package goes live.
We've been looking to harden our release pipeline after seeing recent incidents where compromised maintainer credentials led to malicious package uploads. The idea that an automated script can publish to a staging area, but requires a human with a hardware key (YubiKey ideally) to sign off, creates a nice air gap.
I'm trying to figure out the best way to audit the staged package before approval. Ideally, we'd want a script to automatically scan the tarball in that intermediate state.
Here is how you enable 2FA on an account level:
npm profile enable-2fa auth-and-writes
But for the staged workflow, are there API endpoints to query the pending release? We're thinking of using a script like this to pull the tarball for static analysis:
npm pack --dry-run
Does anyone know if there's a specific flag or API to interact with the "staged" version specifically, or do we have to wait for the public link to become active after approval?
How are you handling the gap between automation and this new manual 2FA gate?
This is a welcome change. We've been experimenting with it in beta. regarding the workflow, we treat the 'staged' event as a trigger. We have a GitHub Action that pauses on needs: approval.
You can use the npm access commands to check permissions, but for the tarball itself, we utilize a custom script that pulls from the registry's internal API if available, or we just verify the diff of the source code before the human hits the 2FA button. It adds about 15 minutes to deployment, but the security ROI is worth it.
Don't forget to look at package provenance (Sigstore). Even with 2FA, if the maintainer's machine is compromised, the attacker could wait for the 2FA prompt and the user might inadvertently approve a malicious build if they aren't checking hashes.
You can verify provenance locally using:
npm audit signatures
Combining staged publishing with strong signature verification is the only way to be truly sure.
From a pentester perspective, this is annoying but effective. I've seen too many CI/CD pipelines with saved tokens that allow silent package updates. This forces a human in the loop.
My advice: ensure your 2FA method isn't SMS. Use a hardware key or TOTP. If you rely on SMS, a SIM swap attack bypasses this new control entirely.
To build on Ivan's workflow point, ensure your CI job explicitly generates the provenance signature before the approval pause. This ensures the metadata is ready to go when the human signs off.
You can enforce this in your workflow command:
npm publish --provenance
We found this prevents the 'approval' step from failing later due to missing signing keys, keeping the human loop efficient.
To ensure the CI build process didn't inject unexpected changes (like a malicious dependency upgrade) before the approval, consider diffing the generated tarball against your source code.
You can pipe the contents directly from the tarball to compare metadata without fully extracting it:
diff <(cat package.) <(tar -xOf *.tgz package/package.)
If this step fails, halt the pipeline. This forces the human to only approve artifacts that strictly match the repository state, closing the loop on build-time integrity.
To add another layer of defense, consider running npm audit specifically against the tarball generated in the staged phase. This catches transitive vulnerabilities that might have slipped in after your initial lockfile generation.
You can unpack and audit the staged artifact locally before hitting approve:
tar -xzf package.tgz
cd package
npm audit --audit-level=moderate
It gives the approver a final sanity check on the dependency tree.
Verified Access Required
To maintain the integrity of our intelligence feeds, only verified partners and security professionals can post replies.
Request Access