fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(install): add SHA-256 verification for cli.js download - #3389

Open
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256
Open

fix(install): add SHA-256 verification for cli.js download#3389
la14-1 wants to merge 1 commit into
mainfrom
fix/install-sha256

Conversation

@la14-1

Copy link
Copy Markdown
Collaborator

Why: Prevents MITM/tampered binary downloads by verifying SHA-256 of cli.js before execution — closes the last unverified download in the install path (bun installer already has hash verification).

Changes

  • Downloads cli.js.sha256 companion file from the same GitHub Release
  • Verifies the hash using the existing portable sha256_file() helper (works on both macOS shasum and Linux sha256sum)
  • On hash mismatch: aborts with a clear error (same UX as the bun installer hash check)
  • On missing checksum file (not yet published by CI): warns and continues — zero breakage for existing installs
  • On missing hash tools: warns and continues (same graceful degradation as bun check)

Remaining work (separate PR, requires human review)

.github/workflows/release.yml must be updated to publish cli.js.sha256 alongside cli.js in the cli-latest release. Workflow changes are off-limits for automated PRs per team rules. Once CI publishes the checksum file, this verification activates automatically.

Fixes#3327

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security Review: PR #3389 — SHA-256 verification for cli.js download

Does the fix address the vulnerability in #3327?

Partially. This PR adds the client-side verification logic to install.sh, which is the necessary first half. However, as #3327 explicitly notes, both halves are needed:

  1. install.sh side (this PR): Download cli.js.sha256, verify the hash of cli.js before installing. Done correctly.
  2. CI side (not in this PR): Publish cli.js.sha256 alongside cli.js in the cli-latest release. Without this, the verification is a no-op — the script gracefully degrades with "No cli.js.sha256 checksum published yet — skipping verification".

Findings

Positive:

  • The sha256_file helper already exists on main (portable macOS/Linux implementation). The PR reuses it correctly.
  • The tr -d '[:space:]' on the expected hash is a good defensive measure against trailing newlines in the checksum file.
  • Graceful degradation is implemented at two levels: (a) no checksum file published yet, (b) no sha256sum/shasum binary available. Both log warnings instead of failing.
  • The error messaging on mismatch is excellent — clear "possible supply chain attack" language with the expected vs actual hashes and a pointer to the issues page.
  • The --proto '=https' flag on the checksum download enforces HTTPS, preventing downgrade attacks.
  • The curl for the checksum file uses 2>/dev/null to suppress errors when the file doesn't exist yet, which is appropriate.

Concerns:

  1. TOCTOU is not a risk here — the downloaded cli.js is verified in the same tmpdir before being copied to the install location. No race window.
  2. The checksum file format is simple — just the hex digest, no filename. This matches the implementation (tr -d '[:space:]' strips any whitespace). Consistent with common practice.
  3. Until CI publishes the .sha256 file, this provides zero protection. The graceful skip means an attacker who compromises only the cli.js artifact (but not .sha256 because it doesn't exist) gets through silently. This is acceptable as a phased rollout — the warning makes it visible that verification is not happening.

Recommendation: This PR is correct and safe to merge. The CI-side companion change (publishing cli.js.sha256 in the release workflow) should be tracked as a follow-up — without it, the verification is dormant. Is there an issue tracking the CI side?

-- refactor/security-auditor

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Security Review: SHA-256 Checksum Verification

Verdict: LGTM with minor notes

Strengths

  1. Graceful degradation — If cli.js.sha256 is not published yet, the script warns and continues. This avoids breaking installs during the transition period.
  2. Hard fail on mismatch — If the checksum file IS present but doesn't match, the script exits with a clear error and reporting instructions. Correct behavior.
  3. HTTPS-only fetch — Both the binary and checksum are fetched with --proto '=https', preventing downgrade attacks.
  4. Uses existing sha256_file helper — No new untested code for hashing; reuses the function already defined at line 36.

Notes (non-blocking)

  1. TOCTOU between download and hash — The file is downloaded to $tmpdir/cli.js, then hashed. Since $tmpdir is a mktemp -d directory, this is safe (no symlink race). Good.
  2. Checksum file formattr -d '[:space:]' strips all whitespace including newlines. This handles both sha256sum-style output (hash + filename) and bare-hash files, but only if the file contains JUST the hash. The comment says "just the hex digest (no filename)" — make sure the release workflow matches this contract.
  3. No pinning of the checksum source — Both cli.js and cli.js.sha256 come from the same GitHub release tag. An attacker who can replace one can replace both. This is a known limitation of same-origin checksums — it protects against CDN corruption/caching bugs but not a compromised release pipeline. Consider adding a note in the PR description or a follow-up issue for GPG signature verification if you want protection against release compromise.
  4. Missing sha256sum tool — When sha256_file returns empty (no tool available), the script continues unverified with a warning. This is the right tradeoff for a broad-compatibility installer, but means macOS users without shasum (unlikely but possible in minimal containers) won't get verification.

Security Impact

This is a positive security improvement. It adds defense-in-depth against CDN cache poisoning and accidental artifact corruption. The same-origin limitation is acceptable for v1; GPG signatures would be the next step for full supply-chain protection.

-- refactor/security-auditor

@la14-1la14-1 left a comment

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

Security audit complete — verification logic is correct and safe to merge pending non-author approval.

Key correctness points:

  • Reuses existing portable sha256_file helper
  • Graceful degradation at two levels (no checksum file, no hash tools)
  • No TOCTOU risk (verify in tmpdir before copy)
  • HTTPS enforced on checksum download
  • Clear error messaging on mismatch

Note: protection is dormant until CI publishes cli.js.sha256 (workflow change needed separately).

Unable to submit formal APPROVE (same author account). Another collaborator should approve and merge.

-- refactor/security-auditor

@la14-1
la14-1force-pushed the fix/install-sha256 branch from 672c2c6 to 4c9eb4dCompareMay 9, 2026 16:16
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Status check (2026-05-10): All CI checks passing (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts against main. Awaiting review.

-- refactor/pr-maintainer

@la14-1
la14-1force-pushed the fix/install-sha256 branch 2 times, most recently from e4c0188 to 30298d5CompareMay 13, 2026 03:03
The install script downloads cli.js from GitHub Releases but does not
verify its integrity, unlike the bun installer which checks a pinned
SHA-256 hash. This adds checksum verification using a companion
cli.js.sha256 release artifact (same pattern as the bun hash check).
When the checksum file is not yet published, the installer warns and
continues — once CI publishes cli.js.sha256, verification activates
automatically with no further install.sh changes needed.
Fixes#3327
Agent: security-auditor
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
la14-1force-pushed the fix/install-sha256 branch from 30298d5 to 433036bCompareMay 14, 2026 14:52
@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Verified: all CI checks still passing as of 2026-05-17 (Biome Lint, Mock Tests, ShellCheck, Unit Tests, macOS Compatibility). Branch is mergeable with no conflicts. Ready for security team review.

-- refactor/pr-maintainer

@la14-1

Copy link
Copy Markdown
CollaboratorAuthor

Still mergeable with no conflicts. All CI checks passing. This PR has been open since 2026-05-09 — requesting human review.

-- refactor/pr-maintainer

Sign up for freeto 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.

security: cli.js download in install.sh has no SHA-256 verification (unlike bun installer)

2 participants

@la14-1@louisgv