Integrity + defence-in-depth for the in-app updater:
- Require and verify a SHA-256 checksum before running an installer. Each
release must attach `<installer>.sha256`; downloadAppUpdate fetches it from
the host-pinned origin (deriving the URL itself, not trusting the renderer),
hashes the stream as it writes, and refuses to run on mismatch/missing/
unparseable. Fails closed. NB: same-host hash is integrity, not protection
against a fully compromised host — only Authenticode signing covers that.
- fetchTrustedText helper GETs the checksum with the same per-hop host
re-validation as the installer download, plus a size cap and timeout.
- finish() is now the single teardown point and aborts the request on failure,
so a write error can't leave Electron pulling bytes into a dead stream;
removed three now-redundant explicit abort() calls.
- Clear the idle/stall timer once the body is fully received.
- Export isTrustedDownloadUrl/compareVersions, extract extractSha256, and add
14 unit tests (host pin incl. userinfo spoof + wrong port, checksum parsing
incl. sha512 non-slice, prerelease never outranking its release).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Seven-tier security audit of the main process, each finding fixed with a
regression test. Typecheck (node + web) clean; unit tests 106 -> 140.
- Tier 1 (command exec/argv): allowlist the yt-dlp --update-to channel
(blocks arbitrary-binary-install RCE); gate per-download extraArgs behind
the customCommandEnabled consent flag in main (blocks --exec RCE); resolve
taskkill/schtasks by absolute System32 path; validate per-download
outputDir; normalize the URL in assertHttpUrl and use it at every spawn.
- Tier 2 (input validation): fix isSafeFilenameTemplate drive-relative
('C:foo') and Windows dotted-'..' traversal bypasses; percent-encode the
untrusted id in entryUrl; catch reserved device names with extensions in
sanitizeDirSegment.
- Tier 3 (fs/backup): drop malformed template rows in importBackup;
normalize deep-link URLs via assertHttpUrl.
- Tier 4 (cookies): confine the sign-in window's navigations/popups to web
URLs (recursively) and deny all web permissions on its session.
- Tier 5 (deep-link/argv): bound the .url file read to 64 KB; match the
aerofetch:// scheme case-insensitively.
- Tier 6 (Electron window): deny camera/mic/geolocation/USB/HID/serial/
Bluetooth permissions on the app window.
- Tier 7 (network/persistence): restrict the watched-source RSS fetch to
youtube.com feed URLs (SSRF guard); complete isValidSource validation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>