Skip to content

fix: add SHA-256 checksum verification to release download (security)#285

Open
xiaolai wants to merge 1 commit into
nextlevelbuilder:mainfrom
xiaolai:fix/nlpm-download-checksum
Open

fix: add SHA-256 checksum verification to release download (security)#285
xiaolai wants to merge 1 commit into
nextlevelbuilder:mainfrom
xiaolai:fix/nlpm-download-checksum

Conversation

@xiaolai

@xiaolai xiaolai commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Automated audit: This PR was generated by NLPM, a natural language programming linter, running via claude-code-action. Please evaluate the diff on its merits.

Security Fix (Medium severity)

cli/src/utils/github.tsdownloadRelease() fetches a ZIP from GitHub releases and writes it to disk, then init.ts extracts and copies the contents into the user's project. No integrity check was performed, so a compromised or corrupted release asset would be silently installed.

Fix

cli/src/utils/github.ts

  • Added an optional expectedSha256 parameter to downloadRelease(). When provided, the downloaded buffer is hashed with Node's built-in node:crypto before writing to disk. A mismatch throws a GitHubDownloadError with both expected and actual hashes for easy diagnosis.
  • Added findChecksumAsset(release, assetName) — looks for a companion checksum file in the GitHub release assets (<assetName>.sha256, checksums.sha256, SHA256SUMS) and extracts the hex digest.

cli/src/commands/init.ts

  • Calls findChecksumAsset() before downloading.
  • Passes the result to downloadRelease().

Backwards compatibility: if the release does not include a checksum file, findChecksumAsset returns null and downloadRelease proceeds as before — no regression for existing releases.

downloadRelease() previously wrote the fetched ZIP to disk with no
integrity check. A compromised release asset would be silently installed.

Added an optional expectedSha256 parameter: when provided, the buffer is
hashed with node:crypto before writing, and a mismatch throws an error.

Added findChecksumAsset() to look for a companion checksum file in the
release assets (e.g. release.zip.sha256, checksums.sha256, SHA256SUMS)
and extract the hex digest. init.ts now calls findChecksumAsset() before
downloading and passes the result to downloadRelease() — if the release
includes a checksum file the download is verified; if not, the current
behaviour is preserved with no regression.

Co-Authored-By: Claude Code <noreply@anthropic.com>

@mrgoonie mrgoonie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary: Optional release checksum verification is a useful security direction, but this PR is not merge-ready because it duplicates another open checksum PR and fails open when checksum retrieval fails.

Risk level: Medium

Mandatory gates:

  • Duplicate/prior implementation: overlap found — PR #288 implements the same SHA-256 release download verification path in the same two files, and PR #315 includes broader release/download hardening.
  • Project standards: issue found — GitHub download/install failures should be explicit; checksum verification must not silently downgrade after selecting a checksum asset.
  • Strategic necessity: clear value — release-asset integrity verification reduces supply-chain risk for GitHub release installs.
  • CI/checks: missing/not reported for this PR.

Findings:

  • Important: This materially duplicates PR #288. Both PRs change cli/src/commands/init.ts and cli/src/utils/github.ts to add optional SHA-256 verification for release ZIP downloads. Please consolidate around one checksum design rather than keeping parallel implementations open.
  • Important: findChecksumAsset() returns null when a checksum asset exists but cannot be fetched or parsed (if (!response.ok) return null; and no parse-failure error). Because downloadRelease() only verifies when expectedSha256 is truthy, the install silently proceeds without verification after a selected checksum path fails. That is a dangerous fail-open security posture. If a checksum asset is selected, fetch/parse mismatch should fail closed with a clear GitHubDownloadError or equivalent.
  • Suggestion: add a small test for checksum success, checksum mismatch, and checksum asset fetch/parse failure so the fail-closed behavior stays locked.

Verdict: REQUEST_CHANGES

@mrgoonie mrgoonie added agent:github-maintain Processed by github-maintain automation pr:reviewed PR reviewed by maintain workflow pr:changes-requested Maintain review requested changes maintain:duplicate-candidate Potential duplicate under maintain review labels Jun 22, 2026
@ia-abatista

Copy link
Copy Markdown
Contributor

Recommend closing, @mrgoonie. Duplicate of #288 (same SHA-256 release-download verification); the release-checksum path also overlaps merged #375/#384.

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

Labels

agent:github-maintain Processed by github-maintain automation maintain:duplicate-candidate Potential duplicate under maintain review pr:changes-requested Maintain review requested changes pr:reviewed PR reviewed by maintain workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants