Skip to content

feat(npm): verify SHA-256 of downloaded binary against checksums.txt - #63

Open
saurabhhhcodes wants to merge 1 commit into
optiqor:mainfrom
saurabhhhcodes:feat/npm-sha256-verification
Open

feat(npm): verify SHA-256 of downloaded binary against checksums.txt#63
saurabhhhcodes wants to merge 1 commit into
optiqor:mainfrom
saurabhhhcodes:feat/npm-sha256-verification

Conversation

@saurabhhhcodes

Copy link
Copy Markdown

Closes #28

Problem

npm/postinstall.js downloaded the release tarball and piped it straight into tar -xzf without validating its digest, so a MITM'd, hijacked, or compromised release asset would run arbitrary code on any npm install -g @optiqor/cli host. GoReleaser ships checksums.txt with every release; the install path never used it.

Changes (npm/postinstall.js)

  1. Fetches checksums.txt from the same release tag.
  2. Hashes the downloaded tarball with crypto.createHash('sha256') before extraction.
  3. Compares against the entry matching the archive filename (optiqor_${VERSION}_${target}.tar.gz). A missing entry or a malformed digest is treated as a failure.
  4. On mismatch: deletes the tarball and exits 1 (refusing to install a tampered binary) instead of proceeding.

Other network errors keep the existing non-fatal exit-0 path, so an offline npm install still surfaces the source-build hint instead of aborting the whole install.

Verification

Logic exercised standalone: entry match, missing entry → null, malformed digest → null, uppercase digest normalization, file-hash comparison — all pass.

Example failure output:

optiqor: checksum mismatch for optiqor_0.1.0_darwin_arm64.tar.gz
optiqor:   expected <sha256 from checksums.txt>
optiqor:   actual   <computed sha256>
optiqor: refusing to install a tampered binary.

Cosign verification of checksums.txt itself is left as follow-up (bonus item in the issue).

Closes optiqor#28

postinstall.js streamed the release tarball straight into tar without
validating its digest, so a MITM'd or hijacked release asset could run
arbitrary code on any npm install -g @optiqor/cli host.

- Fetch checksums.txt from the same release tag.
- Hash the downloaded tarball with crypto sha256 before extracting.
- Compare against the entry matching the archive filename; a missing
  or malformed entry is treated as failure.
- On mismatch: delete the tarball and exit 1 instead of proceeding.
- Other network errors keep the existing non-fatal exit-0 path so an
  offline npm install still falls back to the source-build hint.

Signed-off-by: Saurabh Kumar Bajpai <saurabhkumarbajpaiai@gmail.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

First PR — welcome aboard!

A few things to expect:

  1. CI: every PR runs build + race tests + lint on Ubuntu and macOS. If something fails, the log will tell you exactly which gate.
  2. DCO: every commit needs Signed-off-by:. git commit -s adds it automatically.
  3. Conventional Commits: PR titles like feat(analyze): new rule or fix(cli): handle X. We squash-merge by default.
  4. Review: a maintainer will review within 72 hours. Suggestions are conversations, not orders — push back if something doesn't fit your context.

If you get stuck, reply here or jump to Discussions. We want this PR to land.

@github-actions github-actions Bot added area/npm npm distribution and wrapper size/S 11–50 lines labels Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/npm npm distribution and wrapper size/S 11–50 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(npm): verify SHA-256 of downloaded binary against checksums.txt

1 participant