Make UpdateSelf refuse an update it cannot verify - #94
Merged
Conversation
v1.122.1 fixed the interactive updater in 35-Utilities, but the UpdateSelf CLI action in 50-EntryPoint is a separate implementation and kept the same fail-open shape: when no SHA-256 for RackStack.exe appeared in the release body it warned and replaced the running executable anyway. It now refuses and exits, matching the policy Install-RackStack.ps1 already applies to the bootstrap download. In practice the hash has always been present, so this closes a latent gap rather than a live exposure - but v1.122.1's notes described the fix more broadly than what shipped, and this makes that description accurate. Found by verifying the shipped v1.122.2 monolithic rather than the module that was edited. The section 204 assertion was scoped to 35-Utilities, so it passed while this second path survived. That assertion is now repo-wide across every module, and verified by reintroducing the fail-open string in 50-EntryPoint and confirming the suite goes red. Also audited the remaining download-then-execute sites: Install-RackStack.ps1 fails closed with an explicit -AllowUnverified opt-out, and 77-WindowsAdminCenter re-verifies its MSI signature at apply time. UpdateSelf was the only outstanding one. Separately, the Scoop manifest described the EXE as code-signed. It is not Authenticode-signed - that is the reason antivirus engines flag it - so the description now states what is true: Sigstore cosign signatures and SLSA Level 3 build provenance.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
The second fail-open path
v1.122.1 fixed the interactive updater (
Install-ScriptUpdatein35-Utilities). TheUpdateSelfCLI action in50-EntryPointis a separate implementation and kept the same shape:It then renames the running EXE aside and copies the downloaded one into place. An update whose integrity could not be established was installed with a warning.
It now refuses and exits, matching the policy
Install-RackStack.ps1already applies to the bootstrap download.Severity is low and I want to be accurate about it. The
RackStack.exemanifest line has always been present in release bodies, so this closed a latent gap, not a live exposure. Someone able to omit the hash from a release body already controls the release. But v1.122.1's changelog said "an update whose hash cannot be found is refused rather than installed with a warning" — true of the interactive updater, false ofUpdateSelf. The claim was broader than what shipped; this makes it true.How it was found, and the test lesson
Not by review — by verifying the shipped v1.122.2 monolithic instead of the module that was edited. Section 204 asserted the fail-open string was absent from
35-Utilities, which passed while an identical path survived in50-EntryPoint.A test scoped to the file you just changed only proves you changed that file. The assertion is now repo-wide:
Verified by reintroducing the string in
50-EntryPointand confirming the suite goes red, rather than trusting that it passes for the right reason.Audit of the remaining sites
Every download-then-execute path was checked, not just the one that failed:
Install-RackStack.ps1bootstrap-AllowUnverifiedopt-out77-WindowsAdminCenterMSI install35-UtilitiesInstall-ScriptUpdate50-EntryPointUpdateSelfPackaging correction
dist/scoop/rackstack.jsondescribed RackStack as shipping "a code-signed EXE". It is not Authenticode-signed — that is precisely why ML antivirus engines flag it, as the new antivirus guide explains. Cosign signing is supply-chain attestation, not code signing, and readers will not draw that distinction. The description now states what is true: Sigstore cosign signatures and SLSA Level 3 build provenance.This was the only tracked file carrying the claim; README, SECURITY.md, and the antivirus guide all state the opposite correctly.
Verification
50-EntryPoint,35-Utilities,Run-TestsRackStack.psd1 ModuleVersion matches (1.122.3)The two remaining
Validate-Releasefailures are the pre-existing stale changelog-convention checks, unchanged from v1.122.0.