the assumption that breaks policies
The standard WDAC workflow looks reasonable. Run the policy in audit mode, collect the events, and let the signature information in each event decide whether a file gets a publisher rule or a hash rule. Signed files get publisher rules, unsigned files get hash rules.
The problem is that the second half is not reliable. A properly signed file can show up in audit events with no signature information attached. The file is signed, the certificate is valid, the publisher rule that should cover it would work perfectly. But the event carries no issuer, no publisher, and no TBS hash, so anything generating a policy from that event falls back to a hash rule.
This is the Event 3089 trap, and it is one of the most common reasons a generated policy is quietly wrong from day one.
what Event 3089 actually tells you
Event 3089 is the signature information event. It accompanies an audit or block event and is meant to describe the signatures on the file that triggered it. Policy generation reads its issuer, publisher, and certificate hashes and produces a publisher rule.
The trap is that the 3089 is not guaranteed to contain what you expect. Depending on the context in which the file was evaluated, the signature fields can be empty or report the file as unsigned even when it carries a valid Authenticode signature. The event records what code integrity saw at evaluation time, and that is not always the full signing state of the file on disk.
The common causes are all about load context rather than the file itself. Files loaded early in boot, before full signature verification is available, get evaluated against a reduced view of their signing state. Catalog-signed files whose catalog is not correctly registered evaluate as unsigned. Files served through caching or virtualisation layers can be detached from their signature. In every case the binary on disk is signed, but the event WDAC logged did not capture it, and the event is what survives into your audit data.
what this does to a generated policy
The consequence is mechanical. Policy generation sees an event with no signature information and writes a hash rule. The file is now allowed by its SHA256 hash rather than by its publisher.
A hash rule allows exactly one version of one file. The moment that application updates, the hash changes, the rule stops matching, and the file is blocked. A publisher rule would have survived the update because it trusts the signer rather than the bytes. So a policy that should have been resilient is instead brittle, and it breaks on the next patch cycle for reasons that look unrelated to the update.
The defect is invisible at review time. The rule is there, the file was allowed in audit mode, and nothing in the generated XML signals that this should have been a publisher rule and silently became a hash rule. You find out weeks later when a trusted vendor binary is suddenly blocked. This is why policies built purely from audit events are wrong by design: the audit log records evaluation outcomes, not reliable file signing state.
the version without a tidy explanation
There is a harder edge worth being honest about, because practitioners hit it and find nothing written down.
Sometimes a machine starts reporting signed files as unsigned with no change anyone made. The policy is unchanged, the application is unchanged, the certificates are valid. Yet that specific workstation logs empty signature information for binaries that evaluate perfectly everywhere else. It appears out of the blue, persists through reboots, and resists the usual remediation — catalog re-registration, rebuilding the native image cache, command-line signature verification all change nothing. The code integrity subsystem on that endpoint has reached a state where it no longer evaluates these signatures the way every other machine does.
In these cases the only reliable fix is to rebuild the workstation. A fresh Windows 11 install, and the problem disappears. Same files, same policy, same certificates, and the new build evaluates them correctly while the old one did not. It is not satisfying, but it is honest, and it saves hours of diagnosis on an endpoint that is not going to recover. The implication for policy work matters: a single corrupted endpoint can manufacture a stream of false unsigned events that look exactly like legitimate ones, and any policy generated from a population that includes it inherits that noise as hash rules.
what to do instead
The fix is not to abandon audit mode — it is still how you discover what runs in an environment. The fix is to stop treating the signature fields in an audit event as authoritative.
When an event reports a file as unsigned, that is a prompt to verify, not a fact to encode. Before a hash rule is written, the file itself should be inspected for an embedded or catalog signature. If a valid signature is present, the correct rule is a publisher rule built from the actual certificate on the file, regardless of what the event claimed. The event tells you the file ran. The file tells you how it should be trusted.
That verification step is exactly what gets skipped when policy generation is treated as a mechanical pipeline from events to XML. It is also the difference between a policy that survives the next round of vendor updates and one that starts generating blocks the moment anything patches. WDACManager performs this verification as part of policy generation rather than trusting the event — which is the difference between a policy that ages well and one that breaks on the next patch Tuesday.