P1 / High findings
H-01 — Windows elevates a mutable install-tree batch file
pkg/installer/windows.go:160-212; pkg/installer/common_handler.go:165-184; pkg/tui/models_messages.go:419-423
The uninstall flow copies an install-tree mpv-unregister.bat and runs it with Start-Process -Verb RunAs, without digest, signature, ownership, ACL, or reparse-point validation at elevation time. An unprivileged process can replace it and gain administrator execution when the expected UAC prompt is approved.
Fix: use fixed native cleanup or an embedded authenticated helper in an ACL-protected location; verify immediately before elevation and prohibit manager uninstall for unmanaged records.
H-02 — Windows uninstall deletes an entire directory without ownership proof
pkg/installer/windows.go:121-142; pkg/installer/windows_detection.go:30-53; pkg/web/api_adopt.go:447-476
Uninstall recursively removes every direct child except a small preserve list, while detection/adoption accepts shared custom, PATH, Scoop, and Chocolatey locations. An adopted MPV in C:\Tools can cause unrelated siblings to be removed.
Fix: require a manager ownership marker and per-install manifest; delete only owned paths and use upstream uninstall for adopted/package-managed installs.
H-03 — TUI update/uninstall can target another installation
pkg/version/updates.go:24-33; pkg/tui/models_types.go:141-148; pkg/tui/models_update.go:438-446; pkg/tui/models_messages.go:40-64
The TUI drops AppID and InstallPath from update items and dispatches through a global installer. With multiple/custom/adopted Windows installs, choosing B can update or delete A.
Fix: carry stable identity/path through every message and build an immutable per-operation installer for the exact selected record.
H-04 — Custom Windows installs and settings resolve different config trees
pkg/web/api_settings.go:479-518; pkg/installer/windows.go:410-423; pkg/constants/paths.go:47-79,306-319; config/hotkeys/scriptopts/uiconfig resolvers
Install writes <custom>\portable_config, but later settings, hotkeys, ModernZ/uOSC, migration, backup, and restore resolve AppData/legacy paths. Successful changes may affect a tree MPV never reads.
Fix: use one installed-app-aware resolver across every configuration surface.
H-05 — Cancellation archives “cancelled” before workers finish commits
pkg/web/jobs.go:482-543; install/uninstall/adopt/UI workers
CancelJob immediately marks, persists, removes, and broadcasts a terminal job. A worker can pass its last cancellation check and still commit physical/config side effects; later completion updates miss the archived job.
Fix: cancellation only requests cancellation; the worker owns one compare-and-set terminal transition at a defined commit boundary.
H-06 — Job conflicts are method-based, not resource-based
pkg/web/jobs.go:256-279; Linux installers; component jobs; pkg/web/api_config.go:563-615
Different method IDs and direct reset/restore/migration endpoints mutate shared config/UI/install resources concurrently. One rollback can undo another successful operation.
Fix: add deterministic resource-keyed leases for config trees, targets, package managers, and app identities.
H-07 — Physical success is reported despite tracking persistence failure
pkg/web/api_install.go:382-394,507-540; pkg/web/api_adopt.go:228-249,460-477; pkg/tui/models_update.go:524-618,960-990,1024-1038
Web and TUI flows warn or log when installed-app metadata cannot be saved, then report success. Tasks/history can contradict the physical system.
Fix: include persistence in terminal outcome; expose structured partial success and reconciliation when physical rollback is impossible.
H-08 — Failed manager-config writes leak into memory
pkg/config/config.go:325-345,459-515,672-825,921-930,985-993,1059-1092
Many setters mutate globalConfig before saving and do not restore it on failure. A failed mutation is immediately observable and can be persisted by a later unrelated save.
Fix: mutate clones and publish after successful persistence, or route all setters through the rollback-capable update primitive.
H-09 — Config read errors are treated as a missing file
pkg/config/config.go:85-149,258-263
Permission, I/O, and unavailable-mount errors fall through to defaults and a nil return. Later writes can replace valid state. A shadowed decode error also logs <nil> before quarantine.
Fix: default only on IsNotExist; retain last known-good state and return other errors.
H-10 — Config restore has duplicate rename steps and no rollback
pkg/installer/installer.go:1165-1195; pkg/installer/common.go:161-194; date-only backup names
The live file is renamed before a second helper tries to back it up again. Copy failure can leave mpv.conf absent, and repeated same-day restores collide.
Fix: stage/fsync/swap once, restore the original on failure, and use unique names.
H-11 — Package-version timeout does not terminate its loop
pkg/web/server_version_cache.go:249-364; unbounded commands in pkg/web/package_version.go; synchronous startup
An unlabelled break exits the select, not the collector loop. The one-shot timer is then drained and an unbounded package probe can prevent Web startup or freeze refresh indefinitely. Staticcheck reports SA4011.
Fix: context-bound probes, shared cancellation, a real return/labelled break, and probing outside the cache lock.
H-12 — IINA install trusts a hard-coded global DMG mount
pkg/installer/macos.go:199-216,438-475
The code discards hdiutil output, assumes /Volumes/IINA, and validates only structure. A name collision/alternate mount can copy an unrelated app and detach the wrong volume.
Fix: parse hdiutil attach -plist, use an owned random mount, validate bundle ID/architecture/code signature/Team ID, and detach by returned device.
H-13 — Tagged generator code receives the release private key
.gitlab-ci.yml:284-317,477-506; cmd/generate-info/main.go:517-527
The signing job executes a generator built from the tag with the long-lived key in its environment. Compromised tagged code can exfiltrate the key and forge future releases.
Fix: isolate signing behind a pinned minimal signer and non-exportable KMS/HSM key; tagged application code must never receive key material.
H-14 — Upstream “latest” bytes become first-party signed assets without provenance verification
cmd/generate-info/main.go:358-448,546-634,948-977,1174-1232,1260-1269
The generator discovers upstream latest releases, downloads bytes, hashes them, and immediately signs/publishes those hashes without upstream signature/checksum/native-signature verification or a reviewed digest allowlist.
Fix: pin reviewed versions/digests, verify upstream and platform-native signatures, and require approval before isolated signing.
H-15 — Post-update TUI relaunch inherits the helper log instead of the terminal
pkg/version/transaction.go:349-358,466-485; cmd/mpv-manager/main.go:101-180,273-275
The helper is launched with stdout/stderr redirected to helper.log, then launches the new TUI using its inherited stdout/stderr while stdin remains the terminal. The new TUI can render invisibly into the log. Health is acknowledged before Bubble Tea initialization or first render, so this can still commit as healthy.
Fix: hand the child real controlling-terminal descriptors and acknowledge only after a visible first render; qualify in a native PTY.
H-16 — FFmpeg replacement failure deletes the only known-good backup
pkg/installer/installer.go:593-608
The updater renames ffmpeg.exe to .bak, defers deletion of that backup, and then copies the replacement. If copy fails, deferred cleanup removes the backup and leaves no executable.
Fix: stage/verify before touching live state, atomically swap, roll back on every failure, and delete backup only after verification.
H-17 — TUI language apply replaces the full live config from defaults
pkg/tui/language_preferences.go:823-859; pkg/config/editor.go:135-177
The TUI renames mpv.conf to a date-only backup before setting one language field. Seeing no live file, the shared editor loads the embedded default and writes it, dropping every other user setting from the active config.
Fix: remove the rename path and update the existing file through the shared atomic backup/edit transaction.