Skip to content

fix(knife): GPG-verify Node.js SHASUMS256.txt.asc before committing checksums - #2147

Open
rishuranjanofficial wants to merge 1 commit into
GoogleContainerTools:mainfrom
rishuranjanofficial:fix/gpg-verify-node-shasums
Open

fix(knife): GPG-verify Node.js SHASUMS256.txt.asc before committing checksums#2147
rishuranjanofficial wants to merge 1 commit into
GoogleContainerTools:mainfrom
rishuranjanofficial:fix/gpg-verify-node-shasums

Conversation

@rishuranjanofficial

Copy link
Copy Markdown

Problem

knife.d/update_node_archives.js computes SHA-256 checksums by downloading
each Node.js tarball directly and hashing it locally. The resulting hashes are
committed to private/extensions/node.bzl and later used by Bazel to verify
downloads.

If the nodejs.org CDN, a reverse proxy, or DNS resolution is compromised at the
time the nightly update-node-archives workflow runs, an attacker can serve a
malicious tarball. The script will compute and commit the correct SHA-256 of the
malicious file — Bazel will then accept it on every subsequent build, silently
backdooring all gcr.io/distroless/nodejs* images.

Solution

Node.js publishes a GPG-signed SHASUMS256.txt.asc alongside every release,
signed by the Node.js release team's keys (documented at
https://github.com/nodejs/node#release-keys). Verifying this signature before
trusting any checksum establishes a chain of custody back to the Node.js release
team and eliminates the attack vector above.

This PR:

  1. Imports the 10 current Node.js release GPG keys into an isolated temporary
    keyring at startup (with fallback to a secondary keyserver).
  2. Downloads SHASUMS256.txt and SHASUMS256.txt.asc for each Node.js version.
  3. Runs gpg --verify — the script hard-fails if the signature does not
    validate, preventing any bad hashes from being committed.
  4. Parses the verified SHASUMS256.txt to extract per-architecture SHA-256
    values, replacing the previous approach of hashing downloaded tarballs.
  5. Cleans up all temporary files in a finally block.

The nightly workflow already runs on ubuntu-latest, which has gpg
pre-installed. No runner or workflow changes are required.

Security impact

Scenario Before this fix After this fix
CDN/BGP/DNS MITM during nightly cron Malicious SHA-256 committed GPG verification fails; workflow aborts
nodejs.org serving wrong tarball Bad hash committed GPG verification fails; workflow aborts
SHASUMS256.txt tampered without valid key Not checked GPG verification fails; workflow aborts

Testing

Verified locally that:

  • GPG signature validation passes for Node.js 22 current release SHASUMS.
  • The SHA-256 values parsed from the verified SHASUMS file match those produced
    by the previous tarball-hash approach.
  • A tampered SHASUMS file causes the script to exit non-zero, preventing PR
    creation.

…checksums

Signed-off-by: rishuranjan <rishuranjan6@gmail.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@rishuranjanofficial

Copy link
Copy Markdown
Author

@loosebazooka

I've submitted this pull request and would appreciate a review when you have some bandwidth. Please let me know if any changes or additional context are needed.

Thank you for your time and consideration.

@rishuranjanofficial

rishuranjanofficial commented Aug 10, 2026

Copy link
Copy Markdown
Author

Hi @loosebazooka @nlopezgi @bobcallaway

Gentle ping on #2147. The PR adds GPG verification of SHASUMS256.txt.asc before committing Node.js checksums, closing a supply chain attack vector in the nightly update-node-archives workflow. Happy to address any feedback. Thanks!

@lathama

lathama commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

I am not a node person but did a quick check. I feel the execSync to connect to keyserver.ubuntu.com will fail on some build environments that limit outbound network connections. I think you are trying to fix a real issue but I doubt the shell execution is the best option.

@rishuranjanofficial

Copy link
Copy Markdown
Author

Hi @lathama

Thanks for the review!

You're right - fetching from a keyserver at runtime breaks in restricted network environments, and using execSync for shell commands is fragile.

Better approach: bundle the Node.js release team's public keys directly in the repo as a committed file (sourced from https://github.com/nodejs/node#release-keys) and replace the gpg shell call with the openpgp npm package for pure Node.js verification - no system dependencies, no network calls at build time.

These are public keys, not secrets - they're already published openly by the Node.js team and are safe to commit. Think of them like a list of trusted signatures you keep on file to check documents against.

The only maintenance consideration is that Node.js occasionally adds new release signers. When that happens the keys file needs a one-line update via PR, which is better than fetching keys silently at runtime - changes go through review and are tracked in git history.

Does this direction sound good to you, or do you have a different approach in mind?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants