Skip to content

Harden the update watchdog and broaden what it re-asserts - #47

Merged
BiosSystem merged 1 commit into
masterfrom
feature/hardened-update-watchdog
Sep 17, 2026
Merged

BiosSystem merged 1 commit into
masterfrom
feature/hardened-update-watchdog

Conversation

@BiosSystem

Copy link
Copy Markdown
Owner

What

The -EnableUpdateWatchdog task runs its payload as SYSTEM, but the payload lived in %ProgramData%\Winnow under the default inherited ACL, which a standard user can influence. A SYSTEM task executing a script from a directory non-admins can write to is a local privilege-escalation path.

This reworks the watchdog into a tamper-evident, broader-coverage self-healing enforcer:

  • Directory lockdown. %ProgramData%\Winnow gets a protected ACL (SYSTEM + Administrators Full Control, standard users read/execute, inheritance off), re-applied on every run.
  • Self-integrity check. The payload's SHA256 is recorded under an admin-only HKLM\SOFTWARE\Winnow\Watchdog key at install and re-checked before enforcing. A payload that does not match refuses to run and logs a warning; missing/unreadable state fails closed.
  • Broader floor. Instead of only AllowTelemetry + DiagTrack, it now re-asserts the machine-wide (HKLM) privacy policy floor Windows Update most often resets: Copilot, Recall, Windows AI, generative fill, cross-device clipboard, ink workspace, and OneDrive sync policies, dmwappushservice, and the CEIP telemetry tasks. Touches only what has drifted. Kept to HKLM because a SYSTEM task has no user hive.
  • Testable payload. Moved out of the installer here-string into Scripts/Watchdog/WatchdogPayload.ps1 so it is parsed by static validation and unit-tested.

Validation

Run locally on Windows PowerShell 5.1:

  • Tests\Invoke-StaticValidation.ps1 -RequirePSScriptAnalyzer — parse, duplicate-function, JSON, and PSScriptAnalyzer at Error severity: clean (120 files).
  • Tests/Unit/Test-UpdateWatchdog.ps1 (Pester 5.7.1): 11/11 pass (ACL protection, integrity pass/tamper/missing/absent, desired-state shape, drift-only enforcement for registry/service/task).
  • Related suites (Test-DesiredStateVerification, Test-CustomFeatureContracts, Test-SafetyGuards): 35/35 pass, no regressions.
  • build.ps1 standalone builds and parses clean with the new Scripts/Watchdog folder embedded.

Not verified here (needs a live environment, unchanged from prior watchdog work): the end-to-end path against a real Windows update installing and the watchdog firing on the event trigger as SYSTEM. Documented as a known limitation in the CHANGELOG entry.

New CI step added to run the watchdog tests.

The watchdog task runs its payload as SYSTEM, but the payload lived in
%ProgramData%\Winnow with the default inherited ACL, which lets a standard
user influence a script SYSTEM later executes. Lock that directory down
(SYSTEM and Administrators full, users read and execute, inheritance off)
and re-apply the ACL on every run. Record the payload's SHA256 under an
admin-only HKLM key at install and re-check it before enforcing, so a
swapped payload refuses to run instead of applying whatever it now contains;
missing or unreadable state fails closed.

The old payload only re-asserted AllowTelemetry and DiagTrack. It now
re-asserts the machine-wide privacy floor Windows Update most often resets:
the Copilot, Recall, Windows AI, generative fill, cross-device clipboard,
ink workspace, and OneDrive sync policies, dmwappushservice, and the CEIP
telemetry tasks, correcting only what has drifted. Kept to HKLM because a
SYSTEM task has no user hive.

Moved the payload out of the here-string into Scripts/Watchdog/WatchdogPayload.ps1
so it can be parsed and unit-tested. Added Tests/Unit/Test-UpdateWatchdog.ps1
covering the ACL, the integrity check, and the drift-only enforcement, and
wired it into the CI workflow.
@BiosSystem
BiosSystem merged commit 373102f into master Sep 17, 2026
1 check passed
@BiosSystem
BiosSystem deleted the feature/hardened-update-watchdog branch September 17, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant