Skip to content

fix(detection): tri-state certutil-backed CA properties so query failure is not a finding - #103

Merged
jakehildreth merged 1 commit into
mainfrom
fix/auditfilter-query-failure-fp
Sep 6, 2026
Merged

fix(detection): tri-state certutil-backed CA properties so query failure is not a finding#103
jakehildreth merged 1 commit into
mainfrom
fix/auditfilter-query-failure-fp

Conversation

@jakehildreth

Copy link
Copy Markdown
Owner

fix(detection): tri-state certutil-backed CA properties so query failure is not a finding

Closes #92, together with jakehildreth/PSCertutil#2.

Root cause (two layers)

  1. PSCertutil (the actual trigger): parseAuditFilter ran [int]$AuditFilter = $null on certutil failure, coercing $null to 0, then always emitted @{ AuditFilter = 0 }. A failed -getreg CA\AuditFilter returned a real 0, so Locksmith2 computed AuditingIncomplete = (0 -ne 127) = $true → "auditing not enabled" on a query failure. Fixed in fix(parse): emit nothing on certutil failure instead of fabricated 0 PSCertutil#2 (parser now emits nothing on parse failure).

  2. Locksmith2 (the design gap, this PR): the four certutil-backed detection properties had no "unknown" state. AuditingIncomplete was a non-nullable [bool], so a failed/absent query was indistinguishable from "queried, clean." Defense-in-depth even with a fixed parser.

What changed

  • Classes/LS2AdcsObject.ps1: AuditingIncomplete[Nullable[bool]]; $null = unknown/never queried.
  • All four Set-CA* cmdlets (AuditFilter, EditFlags, InterfaceFlags, DisableExtensionList): set their detection properties to $null on both throw and empty-result paths, so failure is never clean and a stale rescan value cannot survive.
  • Fixed Set-CADisableExtensionList catch block: it set properties on $_ (the ErrorRecord inside catch), so the failure path had never worked.
  • Tests: failure-path contexts (throw + null-result) in all four Set-CA* suites, PSCertutil stub for Set-CADisableExtensionList, Find-level regression proving a CA with AuditingIncomplete = $null emits no Auditing issue.

Verification

  • 56/56 targeted tests pass in pwsh 7.6.5.
  • Full suite: 238 pre-existing macOS platform failures, identical on unmodified main (no Windows Principal/System.DirectoryServices APIs); zero new failures.
  • PS 5.1 leg pending — must run on Windows (powershell.exe) before merge.

Not in this change

…ure is not a finding

- make LS2AdcsObject.AuditingIncomplete [Nullable[bool]]; failure leaves $null, not $false (GH #92)
- set $null on throw/empty-result paths in Set-CAAuditFilter, Set-CAEditFlags, Set-CAInterfaceFlags, Set-CADisableExtensionList
- fix Set-CADisableExtensionList catch block setting properties on the ErrorRecord ($_) instead of the CA object
- add failure-path tests for all four cmdlets and a Find-LS2VulnerableCA regression test (null AuditingIncomplete emits no Auditing issue)
- generic condition evaluator already treats $null as non-match; ESCDefinitions unchanged
@jakehildreth
jakehildreth merged commit b8ed22e into main Sep 6, 2026
1 check passed
@jakehildreth
jakehildreth deleted the fix/auditfilter-query-failure-fp branch September 6, 2026 02:43
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.

AuditFilter detection Possible Bug

1 participant