v2026.09.26.002: a value that is not set no longer stops a check - #7
Open
cdburgess75 wants to merge 1 commit into
Open
cdburgess75 wants to merge 1 commit into
cdburgess75 wants to merge 1 commit into
Conversation
A real run on RLG-JANE-PC (Windows 11 Pro 22621, 2026-09-26) logged eight
Invoke-SafeBlock skips, each dropping the rest of its block. Most checks read
(Get-ItemProperty $key -Name X -ErrorAction SilentlyContinue).X; where X is
not set (Windows' default for most policies) that is .X on nothing, which
throws under Set-StrictMode -Version 2. Since v1.002 the LLMNR, LAN Manager
auth, PS script block audit and credential exposure checks never ran to the
end on such a box, and the CIS block stopped after 1.1.1.
- New Get-RegistryValue returns the value or $null and never throws; every
read of that form uses it, the RDP/NLA check included. Not set means
Windows' documented default (LmCompatibilityLevel 3, LLMNR on, WDigest off,
script block logging off), otherwise unknown; neither is a finding or a
deduction (ADR 0009).
- Script block logging is opt-in: the audit's unconditional HKLM policy write
never ran where the policy was unset, and fixing the read would have turned
4104 logging on fleet-wide. New $SK_EnableScriptBlockLogging, default $false.
- Remove-FolderContents returns early on an empty folder ('Sum' of nothing
threw); the Windows Update block restarts wuauserv/bits/UsoSvc in a finally,
so an empty cache no longer leaves them stopped.
- Local admins: Get-LocalGroupMember by SID S-1-5-32-544, with an ADSI WinNT
fallback for error 1789 (an unresolvable member); neither is unknown.
- Defender exclusions: Get-MpPreference failing with Defender off (0x%1!x!)
is logged as not checked, no finding.
- Antivirus names each product once ('Datto AV, Datto AV').
- No scoring rule changes.
New tests/Test-MissingRegistryValues.ps1; tests/Test-EngineScope.ps1 adds
lm-not-set, lm-2 and av-duplicates. NOT yet run on real Windows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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.
What the real run showed
A real SYSTEM run on RLG-JANE-PC (Windows 11 Pro 22621, branch
fix/os-eol-by-edition= #4, 2026-09-26) logged eightInvoke-SafeBlockskips. Each one dropped the rest of its block:'EnableMulticast' cannot be found'LmCompatibilityLevel' cannot be found'LmCompatibilityLevel' cannot be found'EnableScriptBlockLogging' cannot be found'UseLogonCredential' cannot be foundThe property 'Sum' cannot be foundMeasure-Objectover no fileserror code = 1789Get-LocalGroupMembercould not resolve a memberOperation failed with the following error: 0x%1!x!Plus
antivirus: "Datto AV, Datto AV".The registry cases all come from one pattern:
(Get-ItemProperty $key -Name X -ErrorAction SilentlyContinue).X. Where X is not set, which is Windows' default for most policies,Get-ItemPropertyreturns nothing, and.Xon nothing throws underSet-StrictMode -Version 2. StrictMode has been on since v1.002. So on any box where these values are not set, these checks have never run to the end.What changes
Get-RegistryValuereturns the value, or$nullwhen the key or value is absent or unreadable, and never throws. Every read of the old form now uses it. That includes the RDP/NLA check, which did not fail on this box but reads its values the same way; its conversion is not from the logged list. A static AST test fails on any new instance.LmCompatibilityLevelnot set is level 3, Windows' default on 7 / 2008 R2 and later (Microsoft Policy CSP). The Hardening Engine logs it as OK, CIS 2.3 passes, and the -15 rule does not fire.$SK_SetLMAuthLevelstill raises only a level that is set below 3.EnableMulticastnot set: LLMNR is on, so it logs a warning. It writes only with$SK_DisableLLMNR.UseLogonCredentialnot set: WDigest is off, so there is no IOC.RunAsPPLandEnableVirtualizationBasedSecuritynot set: off, logged as before.NoDriveTypeAutoRunnot set: a CIS 2.8 issue in the log (not scored).fDenyTSConnectionsorUserAuthenticationnot found: RDP is logged as not checked. It does not raise "NLA not enforced" from a value it never read.Remove-FolderContentsreturns early on an empty folder. The WU block had stoppedwuauserv,bitsandUsoSvcbefore the throw and restarted them after it, so the throw left them stopped. The restart is now in afinally.Get-LocalGroupMember -SID S-1-5-32-544runs first, so a localized group name also works. If it fails, an ADSI WinNT fallback lists the members without resolving them, so an orphaned SID comes back as the SID. If neither answers, the result is unknown and raises no finding.Get-MpPreferencefails, the block logsnot checkedand raises no finding.$SK_EnableScriptBlockLogging = $false). The audit wrote theScriptBlockLoggingpolicy (EnableScriptBlockLogging = 1) whenever the value was not 1, with no config switch, even over an explicit GPO 0. The read in front of it threw wherever the policy was not set, so the write has never run on those boxes. Fixing the read alone would have turned 4104 logging on across the fleet on the first run. 4104 logs the text of every script block, which can include secrets. I followed the "all auto-remediation defaults to false" rule and the PR v2026.09.25.004: the Intel Engine loads threat intel; every intel match is report-only #5 precedent of not reviving dormant actions. If you want it on by default, flip one default.Local admin: ...(Medium, orphaned SIDs included) andDomain Usersas an admin (High). These are the findings any box that could list its admins already raised.Scoring: no rule changes, and no device's score changes. The LAN Manager rule is rewritten as "set and below 3". Its old
$null -eq $lmScbranch could never fire, because the read used-ErrorAction Stopand a catch.Verification status
AvoidUsingEmptyCatchBlock, in the new fallbacks).tests/Test-*.ps1pass under pwsh 7.5.tests/Test-MissingRegistryValues.ps1has 51 cases. The registry mock returns a key without the value asked for, no key, or an unreadable key. It runs the RDP, LLMNR, LAN Manager, local admin, Defender exclusion, WU cache (real temp folder), script block, credential and CIS blocks and the LAN Manager scoring rule verbatim. It asserts each block runs to its end, and checks every log line, registry write, finding, IOC count, score and service stop/start. Plus the static AST check.tests/Test-EngineScope.ps1: addslm-not-set(no deduction),lm-2(-15) andav-duplicates, and fails if CIS stops anywhere except 2.9 with Defender removed.Suggested real-Windows checks (RLG-JANE-PC is ideal)
... skippedlines above. The CIS block reachesCIS Benchmark Lite - N check(s) failed(or all passed).LAN Manager auth level: not set, Windows default 3 ... (OK)and[CIS 2.3] ... not set, Windows default 3 (OK)appear.security_scoredoes not drop from the LAN Manager rule.Get-Service wuauserv,bits,UsoSvcafter the run: each is back in its pre-run state or running, not left stopped.Local admin checklists members. With error 1789, it uses the ADSI fallback; check that the names and SIDs look right.Defender exclusions - not checkedwith Datto AV.antivirusreadsDatto AVonce.HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLoggingis not created (opt-in off).Not touched:
Intel Engine skipped - IntelEngine_PrimarySource, as decided.Stacked on #6 (base
fix/programdata-acl), the top of the open stack. #5 and #6 were opened after #4, so this sits on top of them rather than on #4 directly.🤖 Generated with Claude Code