WDAC and Code Integrity events: 3076 and 3077
Reading the CodeIntegrity Operational log for application-control and driver-blocking evidence — audit blocks (3076) vs enforced blocks (3077), what they reveal about unsigned and untrusted code, and how they fit alongside AppLocker.
Windows Defender Application Control (WDAC) and the underlying Code Integrity subsystem decide whether a binary or driver is allowed to load at all based on signing and policy. Its log is narrower than AppLocker's but deeper: it speaks to kernel-level trust, which makes it especially useful for catching unsigned drivers and BYOVD ("bring your own vulnerable driver") activity. This rounds out the endpoint-controls coverage.
Where it lives
The channel is Microsoft-Windows-CodeIntegrity/Operational. It logs regardless of whether a formal WDAC policy is deployed — base Code Integrity (and rules like the Microsoft vulnerable-driver blocklist) still record load decisions here.
The event IDs
| ID | Meaning |
|---|---|
| 3076 | Code Integrity audit block — the file would have been blocked |
| 3077 | Code Integrity enforced block — the file was blocked from loading |
| 3033 | A file did not meet integrity requirements (load failed) |
| 3089 | Signing information for a blocked/audited file |
As with AppLocker, 3076 (audit) vs 3077 (enforce) mirrors "would block" vs "did block." The 3089 events carry the signature details for the file referenced by a 3076/3077 — so a block plus its 3089 tells you the file path, hash, and why trust failed (unsigned, revoked, not in policy).
Why it matters for DFIR
- Unsigned / untrusted drivers. Code Integrity gates kernel drivers. A 3077 (or 3076 in audit) on a driver is high-signal — attackers load vulnerable or malicious drivers to disable EDR or gain kernel execution (BYOVD). A driver being blocked, or audited-but-allowed, tells you someone tried.
- Unsigned user-mode code under WDAC. Where WDAC enforces user-mode rules, 3077 records blocked executables/DLLs that AppLocker policy might not cover.
- Audit-mode reconnaissance value. Like AppLocker, WDAC is frequently deployed in audit mode first. In that mode 3076 logs everything that violates policy without stopping it — a ready list of untrusted code that ran.
What to hunt
- 3076/3077 on drivers (
.sys, paths under\Windows\System32\drivers\or user-writable locations) — the BYOVD signal. - 3077 enforced blocks during the incident window — read the file path/hash via the paired 3089.
- Repeated blocks of the same file — an attacker retrying a load.
- Unsigned/revoked signature status in 3089 for files from user-writable paths.
- A 3076 (audited, allowed) for a known-vulnerable driver — it loaded because enforcement was off; treat as a hit, not a non-event.
The interplay with AppLocker and Defender
These controls overlap but aren't redundant:
- WDAC/Code Integrity = signing/kernel trust (drivers + code integrity).
- AppLocker = path/publisher/hash rules for user-mode apps and scripts.
- Defender = malware detection + ASR.
A capable intruder may evade one and trip another — so read all three logs together. A driver that sails past AppLocker can still light up CodeIntegrity 3077.
Correlate
4624 (+4672) privileged logon
Sysmon 11 a .sys driver dropped to disk
3076 / 3077 CodeIntegrity audits/blocks the unsigned driver load (BYOVD)
Sysmon 10 (if it loaded) a process opens lsass / EDR is blinded
The Code Integrity event is the moment the kernel-trust boundary was tested. Place it on a timeline with the drop and any follow-on injection.
Hunt checklist
- Pull
…CodeIntegrity%4Operational.evtx. - Filter to 3076 / 3077 (and 3033); read the paired 3089 for path/hash/signature.
- Prioritise driver (.sys) blocks and unsigned/revoked files from user-writable paths.
- Treat audited-but-allowed vulnerable drivers (3076 in audit mode) as hits.
- Cross-read with AppLocker and Defender.
Open the CodeIntegrity log in the browser parser; full ID set in the cheat sheet.