From 0286bce4e11e15c7c75ecb472e91fbdedf110072 Mon Sep 17 00:00:00 2001 From: Jamie Chapman <104535858+bilbospocketses@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:35:09 -0400 Subject: [PATCH 1/4] fix(update): pin the Velopack update channel to "stable" (audit #14) VelopackUpdateService created the UpdateManager with no explicit channel, so it fell back to Velopack's RID-derived default rather than the "stable" channel release.yml publishes non-prerelease tags to (vpk pack --channel stable; -beta/-alpha go to beta). It now sets UpdateOptions.ExplicitChannel = "stable", so the updater reliably matches the published stable releases and can't drift onto another channel. Pinning the update package's publisher/signature is deferred to the Velopack Phase-2 signing initiative. --- src/ControlMenu/Services/Update/VelopackUpdateService.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ControlMenu/Services/Update/VelopackUpdateService.cs b/src/ControlMenu/Services/Update/VelopackUpdateService.cs index 7803c7e..74de277 100644 --- a/src/ControlMenu/Services/Update/VelopackUpdateService.cs +++ b/src/ControlMenu/Services/Update/VelopackUpdateService.cs @@ -43,7 +43,14 @@ public VelopackUpdateService(IHostApplicationLifetime lifetime, ILogger CheckForUpdatesAsync(CancellationToken ct = default) From 430b49c0aa34ed11c45ebb621e4285d600dba986 Mon Sep 17 00:00:00 2001 From: Jamie Chapman <104535858+bilbospocketses@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:35:25 -0400 Subject: [PATCH 2/4] build(deps): source- and signature-pin NuGet restores + the vpk install (audit #15) vpk was installed (dotnet tool install -g vpk --version 1.2.0) with no source or signature pin, so a stray/typosquatting feed could substitute a malicious build. A repo nuget.config now clears package sources to nuget.org only and sets signatureValidationMode=require with the nuget.org repository signer trusted (populated authoritatively via `dotnet nuget trust source`), so every restored package must carry a valid nuget.org signature. The vpk install in release.yml and local-pack.ps1 passes --configfile to pin the global-tool install the same way. Verified locally: a fresh full solution restore and a clean vpk install both pass under require-mode. --- .github/workflows/release.yml | 4 +++- nuget.config | 29 +++++++++++++++++++++++++++++ scripts/local-pack.ps1 | 4 +++- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 nuget.config diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d188c5..d5115b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,7 +59,9 @@ jobs: # package (#44); `--msi` / `--instLocation PerMachine` are solidly # supported on the 1.2.0 line (bundled WiX 5). Mirrors ws-scrcpy-web's pin. - name: Install vpk CLI - run: dotnet tool install -g vpk --version 1.2.0 + # Source-pinned to nuget.org + signature-validated via the repo nuget.config + # (audit #15: nuget.org-only source + signatureValidationMode=require). + run: dotnet tool install -g vpk --version 1.2.0 --configfile nuget.config # Restore + build per project directly (not via ControlMenu.sln) to # mirror the local-pack.ps1 approach (3x dotnet publish below). diff --git a/nuget.config b/nuget.config new file mode 100644 index 0000000..ea79f33 --- /dev/null +++ b/nuget.config @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/scripts/local-pack.ps1 b/scripts/local-pack.ps1 index 5a633d8..d142f9c 100644 --- a/scripts/local-pack.ps1 +++ b/scripts/local-pack.ps1 @@ -75,7 +75,9 @@ function Resolve-Vpk { Write-Host "Installing vpk $vpkVersion globally (matches the Velopack NuGet pin)..." # Uninstall any older vpk first to avoid version conflict dotnet tool uninstall -g vpk 2>$null | Out-Null - dotnet tool install -g vpk --version $vpkVersion + # Source-pinned to nuget.org + signature-validated via the repo nuget.config + # (audit #15: nuget.org-only source + signatureValidationMode=require). + dotnet tool install -g vpk --version $vpkVersion --configfile (Join-Path $PSScriptRoot '..\nuget.config') if ($LASTEXITCODE -ne 0) { throw "vpk install failed (exit $LASTEXITCODE)" } Write-Host "vpk $vpkVersion installed." } From bc78e1b16d03ae5b521b6ce3be2f73371aa32cb1 Mon Sep 17 00:00:00 2001 From: Jamie Chapman <104535858+bilbospocketses@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:35:48 -0400 Subject: [PATCH 3/4] build(deps): vendor a SHA-pinned 7zr.exe for .7z extraction, not PATH 7z (audit #17) _Fetcher.ps1's Expand-Cm7z shelled out to whatever 7z was on the runner's PATH to extract ImageMagick's portable .7z - a Local-Dependencies-Only violation (a build tool assumed present on the runner). A new Get-Cm7zr fetches a SHA-256-pinned 7zr.exe (the official 7-Zip standalone extractor) into the build cache, and Expand-Cm7z uses it. 7-Zip publishes no signature/checksum for the standalone extractor, so the hash is recorded from the official download (TOFU) and fails closed on any change. Verified: the vendored 7zr extracts the real ImageMagick 7.1.2-25 portable .7z. Carries the CHANGELOG entries for #14/#15/#17. --- CHANGELOG.md | 3 +++ scripts/dependencies/_Fetcher.ps1 | 38 +++++++++++++++++++------------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 004b83a..92868c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Traced SVGs are no longer served as navigable same-origin content.** The Tracing tool wrote its generated SVG under `wwwroot/temp` and pointed both the preview `` and the Download Copy link at that `/temp/.svg` URL. An SVG fetched from a same-origin URL is active content — an embedded `