Repository navigation
Conversation
Reject an update whose archive is oversized, contains entries that would escape the unpack directory, or unpacks to anything but a plain app bundle of bounded size. Require the published checksum instead of silently skipping it when an asset has no digest.
Owner
|
Thanks for looking at the updater so closely, and for the clear write-up. I tested each case, and I'm going to close this one:
If you find a way past the signature check, I'd like to hear about it. Thanks again! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this PR
The update path already gets the hard parts right: a download has to match its published SHA-256 and pass a strict code-signature check (same team, same bundle ID, Developer ID, notarized) before anything runs. This PR closes the gaps in what happens before those checks — the unpacking itself — and turns one silently skippable check into a hard requirement. Everything here is defense-in-depth; none of it is reachable without the release signing identity.
Changes
The archive is validated before anything touches it
Updater.preparepreviously passed whatever GitHub served straight toditto -x -k, with no limit on size, no check that entries stayed inside the unpack directory, and only a narrow check afterwards (thatMeowse.appis a directory and not a symlink). Three checks now run in order:unzip -Z1) is inspected first. Any entry that is absolute or contains a..component is rejected beforedittoruns, so nothing can write outside the private unpack directory.Meowse.app— a link inside the bundle could point somewhere that changes after verification), and the total uncompressed size is capped at 300 MB.Every rejection uses the existing "invalid archive" error, so failures surface exactly like any other bad download.
A missing checksum now fails closed
The SHA-256 check only ran when the release asset carried a
digest; a missing one silently skipped the check. It now refuses to install (checksumMissing). Every asset in this repo's release history has a digest — GitHub computes them — so published releases are unaffected, but an asset that ever ships without one now produces a clear error instead of falling back to signature verification alone.Notes for review
scripts/build.shguarantees today. If a future release legitimately needs symlinks (e.g. framework version directories), relax that check to allow links whose targets resolve inside the bundle.digest), but haven't run an end-to-end update against a signed build. The updater isn't unit-tested, so CI won't exercise these paths; the easy manual check is to pointMeowseUpdateRepositoryat a throwaway repo whose release asset is a zip containing../escape.txtor a symlink, and confirm the update fails with "isn't a valid Meowse release".