<?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: credential-guard</title><description>Posts tagged credential-guard.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:08 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/credential-guard/rss.xml" rel="self" type="application/rss+xml"/><item><title>Pass-the-Hash to Pass-the-PRT: Twenty-Nine Years of Windows Credential Replay in One Family Tree</title><link>https://paragmali.com/blog/pass-the-hash-to-pass-the-prt-twenty-nine-years-of-windows-c/</link><guid isPermaLink="true">https://paragmali.com/blog/pass-the-hash-to-pass-the-prt-twenty-nine-years-of-windows-c/</guid><description>Pass-the-Hash, Pass-the-Ticket, Overpass-the-Hash, Pass-the-Certificate, and Pass-the-PRT are one architectural lineage. Each defense bought years; none closed the family.</description><pubDate>Thu, 28 May 2026 00:00:00 GMT</pubDate><content:encoded>
Twenty-nine years of Windows credential-replay attacks -- Pass-the-Hash, Pass-the-Ticket, Overpass-the-Hash, Pass-the-Certificate, Pass-the-PRT -- are a single lineage, not five techniques. Each generation finds the next long-term authentication artefact that lives outside the latest Microsoft isolation boundary, then commoditises extraction in tooling that runs anywhere with local administrator. Credential Guard (2015) and KB5014754 (2022) bought years but not closure; Pass-the-PRT (Mollema + Delpy, 2020) already defeats both because the Primary Refresh Token lives in the CloudAP plug-in, which is not inside any current isolation scope. The next decade of Windows credential theft turns on whether Microsoft extends hypervisor-based isolation to CloudAP before commodity offensive tooling makes the attack universal.
&lt;h2&gt;1. Two Afternoons, Twenty-Nine Years Apart&lt;/h2&gt;
&lt;p&gt;On the afternoon of Tuesday, April 8, 1997, between 5:27 p.m. and 8:57 p.m. -- a window we can narrow to about three and a half hours from the file timestamps preserved in the patch he posted -- a researcher named Paul Ashton sat down with the Samba source tree and made the smallest possible change to &lt;code&gt;smbclient&lt;/code&gt;.The bracketing mtimes &lt;code&gt;Tue Apr  8 17:27:29 1997&lt;/code&gt; and &lt;code&gt;Tue Apr  8 20:57:43 1997&lt;/code&gt; are preserved verbatim in the unified diff&apos;s &lt;code&gt;***&lt;/code&gt; and &lt;code&gt;---&lt;/code&gt; header lines on Exploit-DB advisory 19197 [@ashton-exploitdb-19197]. You can still download the diff today and confirm the timestamps yourself. Where the unpatched client computed a network response from a typed-in password, his version read the password&apos;s LM hash from &lt;code&gt;smbpasswd&lt;/code&gt; on disk and fed it straight to the same encryption primitive, skipping the password entirely.&lt;/p&gt;
&lt;p&gt;He posted the diff to NTBugtraq the same evening with a five-line advisory: &quot;A modified SMB client can mount shares on an SMB host by passing the username and corresponding LanMan hash of an account that is authorized to access the host and share. The modified SMB client removes the need for the user to &apos;decrypt&apos; the password hash into its clear-text equivalent.&quot; [@ashton-exploitdb-19197]&lt;/p&gt;
&lt;p&gt;Twenty-nine years later, every Windows credential-replay attack in commodity offensive tooling is a direct descendant of that afternoon.&lt;/p&gt;
&lt;p&gt;Fast-forward to 2026. A Windows 11 23H2 laptop, hardened to Microsoft&apos;s published baseline. &lt;a href=&quot;https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/&quot; rel=&quot;noopener&quot;&gt;Credential Guard&lt;/a&gt; on. KB5014754 strong certificate mapping in full enforcement. Conditional Access enabled, with Token Protection where supported. An attacker has local admin -- the same starting position the 1997 attack assumed.&lt;/p&gt;
&lt;p&gt;Two commands run on that machine, in the same paragraph. Mimikatz &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; returns empty NT hash and TGT buffers; Credential Guard has done its job. Then Mimikatz &lt;code&gt;dpapi::cloudapkd /unprotect&lt;/code&gt; returns a valid Primary Refresh Token session key and proof-of-possession material [@mollema-prt-digging]. On a &lt;em&gt;different&lt;/em&gt; machine across the internet, the attacker pastes that material into Dirk-jan Mollema&apos;s &lt;code&gt;roadtx prt&lt;/code&gt;, mints an &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; cookie, and authenticates to Entra ID as the laptop&apos;s user [@mollema-prt-abusing] [@roadtools-github]. Every Microsoft defense shipped in 2015, 2022, and 2024 is running. The attack still wins.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The empty buffer from &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; is the artefact of twenty-nine years of architectural lessons. The PRT extraction from &lt;code&gt;dpapi::cloudapkd&lt;/code&gt; is the architecture of the &lt;em&gt;next&lt;/em&gt; five-to-ten years. Both scenes are the same attack class. The credential changed; the protocol that consumes it changed; the long-term storage location changed; the lineage did not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You will meet seven people in this article. Paul Ashton (1997, the patch). Hernan Ochoa (2008, the toolkit that put the technique inside Windows itself). Benjamin Delpy (2011, Mimikatz; and the Kerberos generations that followed). Sean Metcalf (2014, who named Overpass-the-Hash and wrote the practitioner reference that taught a generation of red and blue teams).&lt;/p&gt;
&lt;p&gt;Will Schroeder and Lee Christensen (2021, &quot;Certified Pre-Owned,&quot; the AD CS catalog that became Pass-the-Certificate). Oliver Lyak (2022, Certifried, the CVE that forced Microsoft to ship KB5014754). And Dirk-jan Mollema (2020, the Primary Refresh Token research this article argues is the most consequential credential-theft work since 2008). The cast is small. The lineage they built is the load-bearing structure of every Windows penetration test in 2026.&lt;/p&gt;
&lt;p&gt;How is it possible that the same attack works in 1997 and 2026? The answer is structural, not coincidental -- and once you see it, you cannot unsee it.&lt;/p&gt;
&lt;h2&gt;2. The Architectural Property the Family Shares&lt;/h2&gt;
&lt;p&gt;NTLM authentication never asks for the password as a string. It asks for a function of the hash. The hash &lt;em&gt;is&lt;/em&gt; the password.&lt;/p&gt;
&lt;p&gt;That sentence is the article&apos;s load-bearing claim, and the rest of this section is its proof.&lt;/p&gt;
&lt;p&gt;The Microsoft specification for the NTLM protocol -- &lt;code&gt;[MS-NLMP]&lt;/code&gt;, sections 3.3.1 and 3.3.2 -- writes the response computation in pseudocode. For NTLMv1, the server sends an 8-byte challenge; the client computes &lt;code&gt;NtChallengeResponse = DESL(ResponseKeyNT, challenge)&lt;/code&gt;, where &lt;code&gt;ResponseKeyNT = NTOWFv1(password) = MD4(UNICODE(password))&lt;/code&gt; [@ms-nlmp-3-3-1]. &lt;code&gt;DESL&lt;/code&gt; is a variant of DES that pads the 16-byte NT hash to 21 bytes with five zero bytes, splits the result into three 7-byte sub-keys, runs DES on the 8-byte challenge under each sub-key, and concatenates the three 8-byte ciphertexts to form a 24-byte response.&lt;/p&gt;
&lt;p&gt;NTLMv2 is more elaborate -- the response key is &lt;code&gt;NTOWFv2 = HMAC_MD5(MD4(UNICODE(password)), UNICODE(Uppercase(User) + UserDom))&lt;/code&gt;, and the proof string is &lt;code&gt;HMAC_MD5&lt;/code&gt; of the challenge concatenated with a target-info structure -- but the structural property is identical: the cleartext password appears in exactly one place in the entire protocol, the input to the hash function on the client. The verifier performs the same computation against the stored NT hash from the SAM or NTDS.dit, and compares. Neither side ever transmits the password [@ms-nlmp-3-3-2].&lt;/p&gt;
&lt;p&gt;This is what Microsoft means when its institutional documentation says Pass-the-Hash &quot;cannot be patched at the protocol level.&quot; There is nothing to patch.The same property holds for any challenge-response protocol whose verifier stores a determinable function of the password rather than the password itself: Kerberos with stored long-term keys, CHAP with shared secrets, OAuth client_credentials with shared secrets, every HMAC-based proof-of-possession scheme.&lt;/p&gt;
&lt;p&gt;The protocol takes a stored hash and produces a response. Swap the user&apos;s hash for the attacker&apos;s hash, and the protocol still produces a valid response, signed by the substituted key. The bug is not a bug; it is a documented property.&lt;/p&gt;

A family of Windows authentication protocols (NTLMv1 and NTLMv2) in which a server sends a random challenge and the client returns a response computed by applying a keyed cryptographic primitive (DES or HMAC-MD5) to that challenge under a key derived from the user&apos;s password. The verifier holds the same key and recomputes the response to confirm. The cleartext password is never transmitted [@ms-nlmp-3-3-1] [@ms-nlmp-3-3-2].

The 16-byte MD4 of the user&apos;s password as UTF-16 little-endian (`MD4(UNICODE(Passwd))` in the NLMP pseudocode). Unsalted by design, because NT was originally specified for an offline domain controller that has to verify against a fixed reference value. The NT hash is the long-term symmetric Windows authentication secret for every account, stored locally in the SAM and centrally in the NTDS.dit Active Directory database [@ms-nlmp-3-3-1].

The technique of authenticating to a service that uses NTLM (or any protocol descended from the same family) by feeding a stolen NT hash directly to the response-construction function, instead of typing a password the function would then hash. The terminology and the first working demonstration are due to Paul Ashton, NTBugtraq, April 1997 [@ashton-exploitdb-19197].

sequenceDiagram
    participant Client
    participant Server
    participant Verifier as SAM or NTDS.dit
    Client-&amp;gt;&amp;gt;Server: NTLM_NEGOTIATE
    Server-&amp;gt;&amp;gt;Client: NTLM_CHALLENGE with 8-byte nonce
    Note over Client: ResponseKeyNT equals NTOWFv1 of stored NT hash
    Note over Client: NtChallengeResponse equals DESL of ResponseKeyNT and nonce
    Client-&amp;gt;&amp;gt;Server: NTLM_AUTHENTICATE with response
    Server-&amp;gt;&amp;gt;Verifier: Look up stored NT hash for user
    Verifier--&amp;gt;&amp;gt;Server: Stored NT hash
    Note over Server: Recompute DESL of stored hash and nonce
    Server-&amp;gt;&amp;gt;Client: Authentication succeeds if responses match
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The hash is the password. Any long-term authentication artefact reachable by the process that uses it is replayable -- and every credential type the rest of this article discusses (Kerberos TGT, certificate private key, Primary Refresh Token session key) is a different instance of this same property. Defenses can isolate one artefact at a time; the property is intrinsic to the architecture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ashton&apos;s 1997 patch was the protocol-disclosure proof. He swapped a single function call -- &lt;code&gt;SMBencrypt(pass, cryptkey, pword)&lt;/code&gt; became &lt;code&gt;E_P24(p21, cryptkey, pword)&lt;/code&gt;, where &lt;code&gt;p21&lt;/code&gt; is the user&apos;s LM hash read directly from &lt;code&gt;smbpasswd&lt;/code&gt; -- and Samba&apos;s &lt;code&gt;smbclient&lt;/code&gt; authenticated to NT 3.51 and NT 4.0 file servers without ever knowing the user&apos;s password [@ashton-exploitdb-19197]. You can read the patch in five minutes. It is also, in a precise sense, the first proof that NTLM&apos;s response computation is hash-equivalent: if substituting the hash works, then mathematically the hash is what the protocol wanted all along.&lt;/p&gt;
&lt;p&gt;And then nothing happened for eleven years.&lt;/p&gt;
&lt;p&gt;That gap deserves its own explanation, because the eleven-year interregnum is the cleanest failure mode in the lineage.&lt;/p&gt;
&lt;p&gt;Wikipedia&apos;s modern summary of the pre-2008 limitation reads: &quot;even after performing NTLM authentication successfully using the pass the hash technique, tools like Samba&apos;s SMB client might not have implemented the functionality the attacker might want to use. This meant that it was difficult to attack Windows programs that use DCOM or RPC. Also, because attackers were restricted to using third-party clients when carrying out attacks, it was not possible to use built-in Windows applications, like Net.exe or the Active Directory Users and Computers tool amongst others, because they asked the attacker or user to enter the cleartext password to authenticate, and not the corresponding password hash value.&quot; [@wikipedia-pass-the-hash]&lt;/p&gt;

Inside Microsoft the 1997 patch was treated as confirming a known property of LSASS-resident credentials, not as a new attack class. The institutional position was that any compromise yielding the hash already implied SYSTEM-equivalent access, and that the realistic chain was &quot;exfiltrate the hash and crack it offline,&quot; not &quot;replay the hash.&quot; The architectural counter-claim -- that *replaying* the hash from inside a Windows process bypasses every native-tool obstacle -- took a decade to land in the practitioner literature. The 2012 Duckwall + Campbell Black Hat USA paper named the lag in its title: &quot;Still Passing the Hash 15 Years Later.&quot; [@duckwall-campbell-bh2012]
&lt;p&gt;If the obstacle is &quot;built-in Windows tools ask for cleartext,&quot; the architectural answer is to put the substituted hash &lt;em&gt;inside&lt;/em&gt; the Windows process that those tools rely on. That insight took eleven years to operationalise. The person who operationalised it was Hernan Ochoa, in 2008.&lt;/p&gt;
&lt;h2&gt;3. From Patch to Toolkit: The Windows-Native Pivot&lt;/h2&gt;
&lt;p&gt;By 2008, Ashton&apos;s 1997 patch had been sitting on NTBugtraq for eleven years. Hernan Ochoa had a different idea: instead of patching the client, patch the &lt;em&gt;credential cache&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The artefact Ochoa shipped at CanSecWest 2008 and Black Hat USA 2008 was called the &lt;em&gt;Pass-the-Hash Toolkit&lt;/em&gt;, distributed through Core Security Technologies&apos; open-source projects page [@corelabs-pshtoolkit-wayback]. It contained two executables. &lt;code&gt;IAM.EXE&lt;/code&gt; opened the LSASS process with &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, located the cached credential block for the current interactive logon session, and overwrote the NT hash and username fields with attacker-supplied values. &lt;code&gt;PTH.EXE&lt;/code&gt; spawned a target process under a substituted hash.&lt;/p&gt;
&lt;p&gt;Once the substitution was in place, every native Windows SSO consumer -- &lt;code&gt;net.exe&lt;/code&gt;, &lt;code&gt;wmic&lt;/code&gt;, &lt;code&gt;mstsc&lt;/code&gt; once Restricted Admin RDP shipped years later, SMB, RPC, DCOM -- transparently picked up the attacker-supplied hash, because the OS handed them what it believed were the legitimate user&apos;s credentials.&lt;/p&gt;
&lt;p&gt;Wikipedia summarises the architectural pivot in one paragraph: &quot;It allowed the user name, domain name, and password hashes cached in memory by the Local Security Authority to be changed at runtime &lt;em&gt;after&lt;/em&gt; a user was authenticated -- this made it possible to &apos;pass the hash&apos; using standard Windows applications, and thereby to undermine fundamental authentication mechanisms built into the operating system.&quot; [@wikipedia-pass-the-hash] The eleven-year limitation was gone. Pass-the-Hash was now a Windows-native attack that worked against any tool that read its credentials from LSASS -- which in practice meant &lt;em&gt;every&lt;/em&gt; Windows tool.&lt;/p&gt;

The user-mode Windows process (`lsass.exe`) that handles interactive logon, owns the Security Reference Monitor&apos;s policy decisions, and -- relevant to this article -- caches the in-memory credential material that supports Single Sign-On for the duration of each logon session: NT hashes for NTLM, Kerberos TGTs and session keys, certificate handles, and (since Azure AD / Entra ID device join) Primary Refresh Token material in the CloudAP plug-in. Every credential-replay technique in this article reaches its target by reading LSASS in some form.
&lt;p&gt;The 2012 retrospective is where the security industry stopped pretending Pass-the-Hash was solved. Alva Duckwall and Christopher Campbell shipped a Black Hat USA 2012 paper titled, unambiguously, &quot;Still Passing the Hash 15 Years Later.&quot; [@duckwall-campbell-bh2012] The title is the load-bearing pull-quote: it named Ashton 1997 as the origin, Ochoa 2008 as the Windows-native pivot, and the industry&apos;s continued failure to ship a structural fix as the central fact. From this point onwards Microsoft itself acknowledged Pass-the-Hash as a structural property of NTLM rather than a fixable bug.&lt;/p&gt;
&lt;p&gt;Hernan Ochoa&apos;s Windows Credentials Editor (WCE), released a year after the Pass-the-Hash Toolkit, developed the same LSASS-injection primitive on a separate code base. Two independent implementations converging on the same memory-access pattern in the same window is the clearest indication that the architectural insight -- &quot;the credential is sitting in a process you can write to&quot; -- was overdetermined once anyone went looking for it.&lt;/p&gt;
&lt;p&gt;What did Ashton&apos;s 1997 patch leave on the table? The other long-term credentials that LSASS held. The NT hash was the first. There would be more.&lt;/p&gt;
&lt;p&gt;If you can read the NT hash from LSASS, you can read the Kerberos TGT from LSASS. The same memory-access primitive that animates &lt;code&gt;IAM.EXE&lt;/code&gt; is one commit away from animating &lt;code&gt;sekurlsa::tickets&lt;/code&gt;. That commit shipped in May 2011. Its author was a twenty-five-year-old French programmer named Benjamin Delpy.&lt;/p&gt;
&lt;h2&gt;4. Mimikatz and the Kerberos Turn&lt;/h2&gt;
&lt;p&gt;In May 2011, Benjamin Delpy posted his first public release of a program he had been writing as a side project to learn C. He was twenty-five, working as an IT manager at an institution he has never publicly named. Andy Greenberg&apos;s Wired profile records the date: &quot;He released it publicly in May 2011, but as a closed source program.&quot; [@wired-greenberg-mimikatz] Wikipedia corroborates: &quot;He released the first version of the software in May 2011 as closed source software.&quot; [@wikipedia-mimikatz] The program was called Mimikatz.&lt;/p&gt;
&lt;p&gt;What made Mimikatz architecturally different from Ochoa&apos;s toolkit was that it was &lt;em&gt;modular&lt;/em&gt;. The credential-extraction primitives lived in named command groups: &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; dumped NT hashes from LSASS; &lt;code&gt;sekurlsa::tickets&lt;/code&gt; dumped Kerberos tickets from LSASS; &lt;code&gt;kerberos::ptt&lt;/code&gt; injected a stolen ticket into the current Kerberos cache via the documented &lt;code&gt;LsaCallAuthenticationPackage&lt;/code&gt; API with the &lt;code&gt;KerbSubmitTicketMessage&lt;/code&gt; message [@ms-lsa-call-auth-package]; &lt;code&gt;lsadump::dcsync&lt;/code&gt; (added August 2015, in collaboration with Vincent Le Toux) impersonated a domain controller and asked another DC for the krbtgt hash via the IDL_DRSGetNCChanges replication RPC [@adsec-dcsync-p1729].&lt;/p&gt;
&lt;p&gt;Same LSASS, different artefact, different protocol surface. The architectural property section 2 named had two artefacts to work with on Windows: the NT hash, and the Kerberos TGT.&lt;/p&gt;
&lt;p&gt;This is &lt;strong&gt;Pass-the-Ticket&lt;/strong&gt; (Generation 2). The stolen TGT plus its session key authenticates the holder as the original principal for the ticket&apos;s lifetime, which on a default AD deployment is ten hours, renewable for seven days. Time complexity per replay: O(1). The TGT session key is the load-bearing piece -- without it, the ticket is opaque encrypted bytes that the holder cannot decrypt, sign, or present back to the KDC. Mimikatz&apos;s &lt;code&gt;sekurlsa::tickets /export&lt;/code&gt; writes the ticket as a &lt;code&gt;.kirbi&lt;/code&gt; file on disk; &lt;code&gt;kerberos::ptt &amp;lt;file&amp;gt;&lt;/code&gt; re-injects on any machine where the user has a Kerberos credentials cache.&lt;/p&gt;

The long-lived Kerberos credential issued by the KDC&apos;s Authentication Service (AS-REP) in response to a successful AS-REQ. The TGT is encrypted under the KDC&apos;s own krbtgt-account long-term key and contains a session key that the client uses to subsequently request service tickets from the Ticket Granting Service (TGS). Specification: RFC 4120, section 3 [@rfc-4120]. On a Windows Active Directory deployment the default TGT lifetime is 10 hours with renewal up to 7 days.

The technique of extracting a Kerberos TGT (and its session key) from one machine&apos;s LSASS-resident Kerberos cache and injecting it into another machine&apos;s cache, so that subsequent service-ticket requests authenticate as the ticket&apos;s original principal. Tool of record: Mimikatz `sekurlsa::tickets` + `kerberos::ptt`; equivalent functionality in Rubeus and Impacket.

sequenceDiagram
    participant Victim as Victim host
    participant Attacker as Attacker host
    participant KDC
    Note over Victim: User logged in, TGT cached in LSASS Kerberos package
    Attacker-&amp;gt;&amp;gt;Victim: mimikatz sekurlsa::tickets export
    Victim--&amp;gt;&amp;gt;Attacker: TGT.kirbi (ticket plus session key)
    Note over Attacker: mimikatz kerberos::ptt TGT.kirbi
    Attacker-&amp;gt;&amp;gt;KDC: TGS-REQ presenting injected TGT
    KDC--&amp;gt;&amp;gt;Attacker: TGS-REP service ticket
    Attacker-&amp;gt;&amp;gt;Attacker: Authenticate to any Kerberos service as the victim
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A common shorthand says that Microsoft&apos;s Credential Guard isolated NT hashes, so attackers shifted to TGTs. That arrow runs backwards in time. Pass-the-Ticket predates Credential Guard by years -- the Mimikatz Kerberos primitives developed between the May 2011 closed-source release and the April 6, 2014 open-source commit (the earliest verifiable source-level evidence for &lt;code&gt;sekurlsa::tickets&lt;/code&gt; and &lt;code&gt;kerberos::ptt&lt;/code&gt;), and were presented in detail at Black Hat USA 2014 by Duckwall and Delpy [@infocondb-bh2014-duckwall] [@duckwall-delpy-bh2014-wp]. Pass-the-Ticket exists because TGTs are also in LSASS, not as a defensive response. The shift to a new artefact happened because the &lt;em&gt;architectural property&lt;/em&gt; of credential extraction generalised, not because Credential Guard pushed attackers there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The third generation followed shortly. &lt;strong&gt;Overpass-the-Hash&lt;/strong&gt; observes that for the RC4-HMAC Kerberos encryption type -- the Windows default from Windows 2000 through November 2022 -- the user&apos;s long-term Kerberos key is the unchanged NT hash.&lt;/p&gt;
&lt;p&gt;RFC 4757, authored by K. Jaganathan, L. Zhu, and J. Brezak of Microsoft and published as informational in December 2006, specifies the RC4-HMAC enctype&apos;s long-term key as the existing NT hash without modification [@rfc-4757]. An attacker who holds the NT hash can drive a legitimate Kerberos AS-REQ to the KDC, encrypt the timestamp pre-auth blob with the NT hash as the RC4-HMAC key, and receive a real TGT signed by the real krbtgt.&lt;/p&gt;
&lt;p&gt;The economic effect is large. Pass-the-Hash gets you NTLM-based services -- SMB, RPC, and any protocol over them. Overpass-the-Hash gets you the entire Kerberos surface: Kerberos-only services, services that require Kerberos for delegation, services with NTLM disabled at the GPO level. Same NT hash. Different downstream protocol. Strictly larger attack surface.&lt;/p&gt;

The technique of presenting a stolen NT hash to the KDC as the user&apos;s long-term RC4-HMAC Kerberos key (per RFC 4757 [@rfc-4757]), obtaining a real TGT signed by the real krbtgt, and operating as a real Kerberos client for the ticket&apos;s lifetime. Tool of record: Mimikatz `sekurlsa::pth /user: /domain: /ntlm: /run:` and Rubeus `asktgt /user: /rc4:`. Per Sean Metcalf&apos;s adsecurity.org reference, the technique is named &quot;over&quot; because the hash is promoted one notch up the protocol stack from NTLM into Kerberos [@adsec-mimikatz-p556] [@adsec-kerberos-p2293].

sequenceDiagram
    participant Attacker
    participant KDC
    participant Service as Kerberos service
    Note over Attacker: Holds NT hash for user (e.g. from sekurlsa::logonpasswords)
    Attacker-&amp;gt;&amp;gt;KDC: AS-REQ with PA-ENC-TIMESTAMP encrypted under RC4-HMAC(NT hash)
    KDC-&amp;gt;&amp;gt;KDC: Verify PA-ENC-TIMESTAMP decrypts cleanly
    KDC--&amp;gt;&amp;gt;Attacker: AS-REP with real TGT signed by krbtgt
    Attacker-&amp;gt;&amp;gt;KDC: TGS-REQ for Service
    KDC--&amp;gt;&amp;gt;Attacker: TGS-REP service ticket
    Attacker-&amp;gt;&amp;gt;Service: AP-REQ authenticate as user
    Service--&amp;gt;&amp;gt;Attacker: Access granted
&lt;p&gt;The naming has its own story. The Mimikatz capability is Delpy&apos;s; the term &quot;Overpass-the-Hash&quot; and the taxonomic framing that distinguishes it from straight Pass-the-Hash spread through the practitioner community via Sean Metcalf&apos;s adsecurity.org reference [@adsec-mimikatz-p556] and the Duckwall + Delpy Black Hat USA 2014 talk and whitepaper [@infocondb-bh2014-duckwall] [@duckwall-delpy-bh2014-wp]. The earliest archived snapshot of the adsecurity.org reference is October 1, 2014; the talk timestamp is August 7, 2014. The two sources are essentially contemporaneous, and Metcalf&apos;s later &quot;Red vs. Blue&quot; Black Hat USA 2015 whitepaper consolidates the practitioner taxonomy [@metcalf-bh2015-red-vs-blue].&lt;/p&gt;
&lt;p&gt;The &quot;Overpass&quot; coinage is a deliberate semantic argument that the technique is one notch &lt;em&gt;above&lt;/em&gt; Pass-the-Hash on the protocol stack: the NT hash, which began life as an NTLM response key, is being promoted into Kerberos as a long-term encryption key. The naming credit is socially distributed -- Metcalf, Delpy, Duckwall, and Mimikatz&apos;s own command group all carry traces of it -- so this article uses Metcalf&apos;s reference as the canonical practitioner explainer rather than as a single inventor citation.&lt;/p&gt;
&lt;p&gt;The DigiNotar incident in September 2011 is the first publicly attributed criminal use of Mimikatz, four months after Delpy&apos;s first public release. The Dutch certificate authority DigiNotar -- founded 1998, acquired by VASCO in January 2011, hacked in June 2011, declared bankrupt in September 2011 [@wikipedia-diginotar] -- was used to issue hundreds of fraudulent certificates that were then used in man-in-the-middle attacks on Iranian Gmail users [@wikipedia-diginotar] [@fox-it-operation-black-tulip].&lt;/p&gt;
&lt;p&gt;Greenberg&apos;s Wired profile records that Delpy was told by the breach investigators that Mimikatz had been used during the intrusion [@wired-greenberg-mimikatz]. The single-source attribution warrants a hedge -- Greenberg&apos;s source is Delpy himself, quoting investigators -- but the underlying breach timeline is solid.&lt;/p&gt;

The decision to open-source Mimikatz on April 6, 2014 is dated by the GitHub repository banner: `mimikatz 2.0 alpha (x86) release &quot;Kiwi en C&quot; (Apr  6 2014 22:02:03)` [@mimikatz-github]. The precipitating event, as Delpy told Wired, was a trip to Moscow: he returned to his hotel room to find a stranger at his laptop; a second man approached him in the lobby that evening and demanded source code on a USB stick. He decided defenders needed the source as much as the attackers already did, and pushed it to GitHub when he got home [@wired-greenberg-mimikatz].
&lt;p&gt;By 2014, the credential-replay family had three generations -- Pass-the-Hash, Pass-the-Ticket, Overpass-the-Hash -- and Microsoft&apos;s only documented response was a forty-page PDF. The next section is what that PDF said, and why documentation alone cannot end an attack class.&lt;/p&gt;
&lt;h2&gt;5. Documentation Is Not Defense&lt;/h2&gt;
&lt;p&gt;By December 2012, Microsoft had a problem. Duckwall and Campbell had just shipped a Black Hat USA paper titled &quot;Still Passing the Hash 15 Years Later&quot; [@duckwall-campbell-bh2012]. Mimikatz was eighteen months old. The institutional position that Pass-the-Hash was a &quot;post-compromise issue&quot; -- the line Microsoft had held since 1997 -- was no longer survivable in public.&lt;/p&gt;
&lt;p&gt;The institutional response came in two waves. &lt;em&gt;Mitigating Pass-the-Hash Attacks and Other Credential Theft&lt;/em&gt;, version 1, shipped in late 2012 (most practitioner secondaries place it in December 2012; no primary Microsoft URL with a verifiable v1 timestamp survives today).&lt;/p&gt;
&lt;p&gt;Version 2 followed in July 2014, extending the v1 playbook with the new defensive surfaces that shipped in Windows 8.1 and Windows Server 2012 R2: &lt;a href=&quot;https://paragmali.com/blog/who-is-allowed-to-log-in-where-the-kdc-side-answer-to-creden/&quot; rel=&quot;noopener&quot;&gt;Protected Users&lt;/a&gt; as a deployable security group, Restricted Admin RDP as a default-available feature, LSA Protection (RunAsPPL) as a registry-toggleable defense, and Authentication Policies and Silos as KDC-side restrictions [@ms-download-mitigating-pth-v2]. The two whitepapers are the closest thing the industry got to an institutional Microsoft acknowledgment that Pass-the-Hash was a load-bearing operational problem requiring a defensive playbook rather than a patch.&lt;/p&gt;
&lt;p&gt;What did the playbook recommend? Three orthogonal stopgaps, each with a published bypass.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protected Users&lt;/strong&gt; (Windows Server 2012 R2). A security group whose membership bans, on the DC side, NTLM authentication, DES and RC4 Kerberos pre-authentication, and Kerberos unconstrained delegation; and, on the device side, NTLM caching of the user&apos;s plaintext credentials or NTOWF and Kerberos DES/RC4 long-term keys. Member TGTs are capped at 240 minutes (four hours) with no renewal [@ms-protected-users]. Documented bypasses: requires explicit opt-in per account, breaks any service that depended on unconstrained delegation, does not apply to computer accounts or service accounts by default, and has no effect on Kerberos AES-key extraction from LSASS (since AES keys are not banned; only RC4 is).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Restricted Admin RDP&lt;/strong&gt; (introduced in Windows 8.1 / Server 2012 R2 RTM, October 2013; backported to Windows 7 / Server 2008 R2 / Windows 8 / Server 2012 by KB2871997 on May 13, 2014 [@ms-kb2871997-may2014]). An opt-in RDP mode that authenticates to the target without sending credentials, so a compromised target cannot harvest the RDP user&apos;s hash from its own LSASS. Documented bypass: opt-in per session, applies only to RDP, leaves SMB, WMI, and RPC unprotected. And it &lt;em&gt;enables&lt;/em&gt; Pass-the-Hash for RDP -- the BloodHound &lt;code&gt;CanRDP&lt;/code&gt; edge documents the abuse path with the exact Mimikatz command for injecting a stolen NT hash into &lt;code&gt;mstsc.exe /restrictedadmin&lt;/code&gt; [@bloodhound-canrdp].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LSA Protection / RunAsPPL&lt;/strong&gt; (Windows 8.1). A registry toggle that marks LSASS as a &lt;a href=&quot;https://paragmali.com/blog/protected-process-light-when-the-administrator-isnt-enough/&quot; rel=&quot;noopener&quot;&gt;Protected Process Light&lt;/a&gt;, so non-PPL processes (including unsigned admin tools) cannot open it with &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;. Documented bypass: any signed kernel driver -- including loadable third-party drivers -- can still read PPL memory, and an attacker with local admin can load such a driver. The itm4n analysis includes the verbatim Mimikatz output where &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; returns access-denied against a PPL-marked LSASS, and shows that an attacker who loads a signed driver via the BYOVD pattern (&quot;bring your own vulnerable driver&quot;) or escalates to kernel mode bypasses the marking. itm4n&apos;s framing -- &quot;Credential Guard and LSA Protection are actually complementary&quot; [@itm4n-lsass-runasppl] -- is also the prediction: PPL is part of the answer, but only when paired with the architectural pivot still to come.&lt;/p&gt;

A Windows Server 2012 R2 security group whose membership applies a set of restrictions, enforced jointly by the device and the domain controller, that block the most commonly extracted long-term credential material: no NTLM, no Kerberos RC4 or DES pre-auth, no unconstrained delegation, no NT-hash caching, and a 240-minute TGT lifetime with no renewal [@ms-protected-users].
&lt;p&gt;The structural point is this. Documentation tells administrators &lt;em&gt;what to do&lt;/em&gt;. It does not prevent the underlying LSASS-resident credential extraction. Every defense documented in v1 and v2 of the Mitigating-PtH whitepapers is bypassable, with a known and published technique, on any system where the attacker already has local administrator -- and local administrator is exactly what Pass-the-Hash exploitation &lt;em&gt;already implies&lt;/em&gt;. The defender&apos;s win condition is to keep the attacker from ever getting to local admin in the first place; once they have it, every documented mitigation is a speed bump rather than a wall.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The 2012-2014 era&apos;s load-bearing failure mode was assuming that telling administrators where credentials &lt;em&gt;should&lt;/em&gt; live would prevent extraction from where they &lt;em&gt;do&lt;/em&gt; live. Protected Users, Restricted Admin RDP, RunAsPPL, and Authentication Silos are all useful, and stacked together they raise the cost of post-admin exploitation. None of them moves the credential out of the address space the attacker can read.&lt;/p&gt;
&lt;/blockquote&gt;

A common secondary characterisation cites a &quot;v3 2017&quot; of the whitepaper alongside v1 and v2. That document does not exist in Microsoft Download Center ID 36036; the page lists Version 2.0; the 2023 Wayback snapshot of the same Download Center page records Date Published 7/7/2014, while the live page now shows a 2024 republication date for the same Version 2.0 PDF without a version bump [@ms-download-mitigating-pth-v2]. The Download Center page carries v2 metadata only -- v1&apos;s late-2012 date is sourced through contemporary practitioner literature rather than a primary Microsoft timestamp. After 2014 the post-v2 institutional documentation moves to the Microsoft Learn Credential Guard page rather than to a third whitepaper revision -- a structural choice, because by 2015 the architectural answer has shifted from prose to code.
&lt;p&gt;By mid-2014 Microsoft&apos;s institutional position was that the protocol-level fix was unavailable and the architectural answer would need to &lt;em&gt;relocate the credentials&lt;/em&gt;. If credentials cannot stay in LSASS where every admin process can read them, the credentials have to be moved to a place admin processes cannot read. That insight produces Credential Guard.&lt;/p&gt;
&lt;h2&gt;6. Credential Guard and the Architectural Pivot&lt;/h2&gt;
&lt;p&gt;On July 29, 2015, Microsoft shipped Windows 10 Enterprise [@ms-lifecycle-w10-enterprise]. Hidden in the RTM build was the first defense in the credential-replay lineage that wasn&apos;t documentation: hardware-rooted isolation. They called it Credential Guard.&lt;/p&gt;
&lt;p&gt;The architecture is worth unpacking carefully, because every later generation of the family is best read as &quot;what does this attack do to the assumptions Credential Guard makes?&quot;&lt;/p&gt;
&lt;p&gt;Credential Guard runs on top of Virtualization-Based Security. The Windows hypervisor partitions user mode into two virtual trust levels. VTL0 is the normal user partition: normal user-mode processes, including the normal LSASS, and the normal kernel. VTL1 is the isolated user partition: a small set of &lt;em&gt;trustlets&lt;/em&gt;, signed user-mode processes the hypervisor protects from VTL0 inspection. Credential Guard&apos;s trustlet is LSAISO (&quot;LSA Isolated&quot;), a stripped-down clone of the LSA credential cache holding the material Microsoft wants out of VTL0. Hypervisor-enforced Code Integrity (HVCI) below enforces W^X on the VTL0 kernel, blocking kernel-mode bypasses that would otherwise read VTL1 memory directly.&lt;/p&gt;

The Windows architecture that runs a Type-1 hypervisor below the normal Windows kernel and partitions user mode into VTL0 (the normal partition) and VTL1 (the isolated partition). VTL1 hosts trustlets that the hypervisor protects from VTL0 inspection, even from kernel-mode VTL0 code. VBS is the substrate for Credential Guard, HVCI, the System Guard secure-launch chain, and the secure kernel.

The Windows feature that relocates NT hashes, Kerberos TGT session keys, and &quot;credentials stored by applications as domain credentials&quot; from the in-VTL0 LSASS to the in-VTL1 LSAISO trustlet, so that the credential cache is unreadable from any VTL0 process or driver. Shipped in Windows 10 RTM (July 2015); default-enabled on hardware-eligible domain-joined non-DC systems in Windows 11 22H2 (September 2022) [@ms-learn-credential-guard].

The isolated-user-mode LSA process (`lsaiso.exe`) that holds Credential Guard&apos;s protected credential material. Runs in VTL1, unreadable from VTL0 kernel or user processes. Communicates with the VTL0 LSASS through a small RPC surface for authorised authentication operations only.
&lt;p&gt;What does Credential Guard isolate? The Microsoft Learn page is unambiguous: &quot;Credential Guard prevents credential theft attacks by protecting NTLM password hashes, Kerberos Ticket Granting Tickets (TGTs), and credentials stored by applications as domain credentials.&quot; [@ms-learn-credential-guard] Those three categories are also the three categories the previous three generations of the family targeted. Pass-the-Hash hits NTLM password hashes. Pass-the-Ticket hits Kerberos TGTs. Overpass-the-Hash hits NTLM password hashes promoted into Kerberos. Credential Guard moves all three out of VTL0 LSASS into VTL1 LSAISO. On a hardware-eligible domain-joined Windows 10/11 system with Credential Guard enabled, all three attacks return empty buffers.&lt;/p&gt;
&lt;p&gt;The institutional importance of the change is that under Microsoft&apos;s own &lt;em&gt;Windows Security Servicing Criteria&lt;/em&gt;, Credential Guard is a &lt;em&gt;security boundary&lt;/em&gt; -- which means a bypass is a CVE-class vulnerability rather than a documentation gap.&lt;/p&gt;
&lt;p&gt;The criteria&apos;s load-bearing definitions: &quot;A security boundary provides a logical separation between the code and data of security domains with different levels of trust&quot; and &quot;Does the vulnerability violate the goal or intent of a security boundary or a security feature?&quot; [@msrc-windows-servicing-criteria] Pre-2015 Pass-the-Hash defenses were documentation; Credential Guard is the first defense the criteria treats as CVE-class under the boundary &quot;admin -&amp;gt; VBS (LSAISO trustlet).&quot;&lt;/p&gt;

flowchart TD
    subgraph VTL0[VTL0 normal partition]
        A[User processes]
        B[LSASS]
        K[VTL0 kernel]
    end
    subgraph VTL1[VTL1 isolated partition]
        L[LSAISO trustlet]
        SK[Secure kernel]
    end
    H[Hypervisor]
    A --&amp;gt; B
    K --&amp;gt; B
    B -- authorised RPC only --&amp;gt; L
    H --&amp;gt; VTL0
    H --&amp;gt; VTL1
    SK --&amp;gt; L
    K -. blocked by HVCI .-&amp;gt; L
&lt;p&gt;What does Credential Guard &lt;em&gt;not&lt;/em&gt; isolate? This is the load-bearing question for the rest of the article. The same Microsoft Learn page enumerates four caveats, each verbatim.&lt;/p&gt;
&lt;p&gt;First, the Active Directory database and the SAM. &quot;Credential Guard doesn&apos;t provide protections for the Active Directory database or the Security Accounts Manager (SAM).&quot; [@ms-learn-credential-guard] This is the &lt;a href=&quot;https://paragmali.com/blog/two-checkmarks-and-the-keys-to-the-kingdom-how-active-direct/&quot; rel=&quot;noopener&quot;&gt;DCSync&lt;/a&gt; gap: an attacker with the right replication privileges can ask a DC to hand over every hash in the directory, and Credential Guard cannot intervene because the data is being released through a legitimate, authorised API rather than being read from LSASS.&lt;/p&gt;
&lt;p&gt;Second, domain controllers. &quot;Enabling Credential Guard on domain controllers isn&apos;t recommended. Credential Guard doesn&apos;t provide any added security to domain controllers.&quot; [@ms-learn-credential-guard] The KDC must read the krbtgt account&apos;s long-term key in cleartext to issue tickets; the architectural exception is intrinsic to Kerberos rather than a Microsoft oversight.&lt;/p&gt;
&lt;p&gt;Third, application credentials outside the &quot;domain credentials&quot; scope. Certificate private keys held by CryptoAPI key containers, third-party authentication package secrets, and -- the one this article eventually argues is the most consequential -- the Primary Refresh Token material held by the CloudAP authentication plug-in, are all out of scope by construction.&lt;/p&gt;
&lt;p&gt;Fourth, and most importantly, the institutional acknowledgment of the supersession pattern. Microsoft Learn reproduces it verbatim on the same page, the prophecy the rest of this article spends its time documenting being fulfilled:&lt;/p&gt;

While Credential Guard is a powerful mitigation, persistent threat attacks will likely shift to new attack techniques, and you should also incorporate other security strategies and architectures. -- Microsoft Learn, *Credential Guard overview* [@ms-learn-credential-guard]
&lt;p&gt;That sentence, written about the 2015 Credential Guard architecture, accurately predicts the 2021-2022 shift to Pass-the-Certificate and the 2020-present shift to Pass-the-PRT. It is Microsoft&apos;s own structural prediction that the family will continue to evolve to the next artefact Credential Guard&apos;s verbatim scope does not cover. The rest of this article reads as the unfolding of that prediction.&lt;/p&gt;

The Kerberos KDC must read the krbtgt account&apos;s long-term key to encrypt the TGT issued in every AS-REP. That key has to be available to the LSA process in cleartext, on every DC, on every ticket issuance, by protocol. Putting krbtgt behind LSAISO would mean issuing every TGT through an inter-trust-level RPC call -- a non-trivial performance penalty on every authentication in an Active Directory forest -- and would not actually close the architectural gap, because the trustlet itself would still need to do the cleartext work that LSASS does today. The exception is honest about an architectural reality rather than concealing it.
&lt;p&gt;PPL and Credential Guard are &lt;em&gt;complementary&lt;/em&gt;, not alternatives. itm4n&apos;s analysis [@itm4n-lsass-runasppl] makes the case carefully: RunAsPPL raises the bar from &quot;any admin process can read LSASS&quot; to &quot;any signed driver can read LSASS,&quot; and Credential Guard closes the signed-driver bypass with hardware-rooted hypervisor isolation. They stack. The 2026 best-practice Windows endpoint has both turned on.&lt;/p&gt;
&lt;p&gt;The default-enablement window shows how long this took to land. Credential Guard shipped enabled-by-policy in Windows 10 RTM in 2015, but did not become &lt;em&gt;default-enabled on hardware-eligible domain-joined non-DC systems&lt;/em&gt; until Windows 11 22H2 in September 2022 [@ms-learn-credential-guard]. Seven years of uneven deployment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Four residuals from the Microsoft Learn page: the Active Directory database and the SAM are out of scope; domain controllers are out of scope by recommendation; application credentials outside the &quot;domain credentials&quot; category (certificates, CloudAP material, third-party authentication packages) are out of scope by construction; and persistent threats are &lt;em&gt;expected&lt;/em&gt; to shift to new attack techniques. Each residual maps to a later generation of this article: AD database -&amp;gt; DCSync; certificates -&amp;gt; Pass-the-Certificate; CloudAP -&amp;gt; Pass-the-PRT.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each new credential type needs its own isolation boundary. Credential Guard isolates NT hashes and TGT session keys. It does not isolate certificate private keys, because in 2015 nobody was replaying certificates at scale. And it does not isolate the Primary Refresh Token, because in 2015 the Primary Refresh Token did not yet exist.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Each new credential type needs its own isolation boundary. The pattern is reusable but does not transfer automatically -- and the gap between &quot;what fits in the boundary&quot; and &quot;what credentials Windows actually uses&quot; is exactly the territory where the next attack generation grows.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;7. Pass-the-Certificate: The Predictable Response&lt;/h2&gt;
&lt;p&gt;If the NT hash is isolated and RC4-HMAC is banned, what is the next long-term credential Windows accepts? The answer was hiding in plain sight: every Active-Directory-integrated enterprise had been running Microsoft&apos;s PKI since 2008, and almost every PKI deployment had at least one template-level catastrophe.&lt;/p&gt;
&lt;p&gt;On June 17, 2021, Will Schroeder and Lee Christensen posted &quot;Certified Pre-Owned&quot; on Medium, with the accompanying 143-page whitepaper [@specterops-certified-pre-owned] [@specterops-certified-pre-owned-pdf]. The post named ESC1 through ESC8 in a single document, with paired DETECT and PREVENT recommendations, and shipped three pieces of tooling at the same Black Hat USA 2021 cycle: Certify (offensive enrollment), ForgeCert (golden-certificate forging using a stolen CA private key), and PSPKIAudit (defensive enumeration). The Medium post&apos;s tone was unsubtle:&lt;/p&gt;

Of note, nearly every environment with AD CS that we&apos;ve examined for domain escalation misconfigurations has been vulnerable. It&apos;s hard for us to overstate what a big deal these issues are. -- Will Schroeder and Lee Christensen, *Certified Pre-Owned* [@specterops-certified-pre-owned]
&lt;p&gt;The &lt;a href=&quot;https://paragmali.com/blog/certified-pre-owned-ad-cs-and-active-directorys-second-trust/&quot; rel=&quot;noopener&quot;&gt;ESC catalog&lt;/a&gt; organises certificate misconfigurations by the abuse primitive they enable. ESC1 is the canonical example: a published certificate template that allows the enrollee to supply the Subject Alternative Name, contains a client-authentication Extended Key Usage, has permissive enrollment rights, and has no effective approval gates.&lt;/p&gt;
&lt;p&gt;An attacker who can enroll for such a template requests a certificate naming a victim principal -- say, the domain administrator -- in the SAN. The certificate&apos;s private key is now the attacker&apos;s. PKINIT-authenticate to the KDC with that certificate, and the KDC issues a TGT for the named principal. Domain escalation, in three commands.&lt;/p&gt;

Microsoft&apos;s enterprise PKI. Issues X.509 certificates from administrator-defined templates that pin a certificate&apos;s permitted uses (Extended Key Usages), its enrollment authorisation rules, its subject and SAN generation policy, and its revocation behaviour. Ships as a Windows Server role; deployed in essentially every Active-Directory-integrated enterprise.

Kerberos pre-authentication using a certificate&apos;s private key in place of a long-term symmetric key. Specified by RFC 4556 (L. Zhu and B. Tung, Microsoft and Aerospace, June 2006) [@rfc-4556]. The certificate&apos;s UPN SAN (or its dNSHostName for computer accounts) maps the certificate to the principal whose TGT the KDC will issue. PKINIT is the protocol surface most commonly exercised by Pass-the-Certificate against domain controllers that support certificate-based authentication.

The Windows TLS implementation. Supports TLS client-certificate authentication, which authenticated LDAPS uses. When a domain controller does not support PKINIT (Schroeder + Christensen documented this case in the original catalog; AlmondOffSec built tooling for it), an attacker can authenticate to LDAPS over Schannel with a stolen client certificate and perform high-privilege LDAP operations without traversing the KDC.

The technique of authenticating to Active Directory with a stolen X.509 certificate&apos;s private key, via PKINIT to the KDC or via Schannel client-certificate authentication to LDAPS. Named in this form by Yannick Méheut&apos;s PassTheCert tool and blog post (May 2022) [@almondoffsec-passthecert-github] [@almondoffsec-passthecert-blog], though the technique class was catalogued by Schroeder and Christensen eleven months earlier [@specterops-certified-pre-owned]. Tool of record: Certify (C#), Certipy (Python, ESC1-ESC16 [@certipy-wiki-privesc]), and Rubeus PKINIT mode.

sequenceDiagram
    participant Atk as Attacker (user)
    participant CA as Enterprise CA
    participant KDC
    Atk-&amp;gt;&amp;gt;CA: Enrol for template ESC1, SAN field set to Domain Administrator
    CA--&amp;gt;&amp;gt;Atk: X.509 certificate plus private key
    Note over Atk: Now holds a certificate naming the victim principal
    Atk-&amp;gt;&amp;gt;KDC: AS-REQ with PKINIT pre-auth using the stolen private key
    KDC-&amp;gt;&amp;gt;KDC: Validate certificate, map SAN to victim principal
    KDC--&amp;gt;&amp;gt;Atk: AS-REP with TGT for victim principal
    Atk-&amp;gt;&amp;gt;KDC: TGS-REQ for any service
    KDC--&amp;gt;&amp;gt;Atk: TGS-REP service ticket
&lt;p&gt;The CVE-class case lands on May 10, 2022. Oliver Lyak of IFCR discloses Certifried, CVE-2022-26923, an Active Directory Domain Services elevation-of-privilege vulnerability in which the combination of three Microsoft defaults -- &lt;code&gt;ms-DS-MachineAccountQuota = 10&lt;/code&gt; (any authenticated user can add up to 10 computer accounts to the domain), the default Machine template (which a computer account can enroll for), and the KDC&apos;s permissive &lt;code&gt;dNSHostName&lt;/code&gt;-to-SAN binding logic -- lets any authenticated user obtain a certificate for any computer account in the forest, including domain controllers.&lt;/p&gt;
&lt;p&gt;PKINIT-authenticate as a domain controller, and the KDC issues you a TGT for the DC; from there, DCSync extracts the krbtgt key and the domain is yours. Domain escalation from any authenticated user, with the only required misconfiguration being &lt;em&gt;Microsoft&apos;s defaults&lt;/em&gt; [@nvd-cve-2022-26923] [@semperis-cve-2022-26923].&lt;/p&gt;
&lt;p&gt;The defensive response shipped the same day. Microsoft published KB5014754 on May 10, 2022 -- coordinated disclosure, with the patch shipping in the same window as the CVE -- introducing a new X.509 extension &lt;code&gt;szOID_NTDS_CA_SECURITY_EXT&lt;/code&gt; (OID &lt;code&gt;1.3.6.1.4.1.311.25.2&lt;/code&gt;) that carries the requesting principal&apos;s SID at certificate issuance.&lt;/p&gt;
&lt;p&gt;The KDC&apos;s new strong-mapping logic refuses certificates that fail one of four conditions: the SID extension is present and matches; an issuer-serial mapping is present; a Subject Key Identifier mapping is present; or a SHA1-public-key mapping is present. The KB&apos;s load-bearing sentence: &quot;In Full Enforcement mode, if a certificate fails the strong (secure) mapping criteria (see Certificate mappings), authentication will be denied.&quot; [@ms-kb5014754]&lt;/p&gt;
&lt;p&gt;The KB5014754 change-log preserves a forensic artefact of the coordinated-disclosure timeline that is easy to miss. The current change-log row reads, verbatim: &quot;9/10/2025 - Corrected the Enforcement mode date from September 10, 2025, to September 9, 2025.&quot; [@ms-kb5014754] An off-by-one date correction, captured in the public KB. The kind of detail that only shows up when a small team has had to ship a date repeatedly against a multi-year audit-to-enforcement schedule.&lt;/p&gt;
&lt;p&gt;The enforcement timeline tells you how long even a CVE-class fix took to drive through deployment. Audit mode (May 10, 2022). Enforcement mode with a registry escape that admins could use to revert to compatibility (February 11, 2025). Final cutover with no escape (September 9, 2025) [@ms-kb5014754]. Three years and four months between the patch and the day Microsoft stopped accepting non-strong certificate mappings. Faster than the Credential Guard default-enablement window, but still measured in years.&lt;/p&gt;
&lt;p&gt;The naming history deserves a disambiguation. The &lt;em&gt;catalog&lt;/em&gt; -- ESC1 through ESC8, the full taxonomy of AD CS misconfigurations -- is Schroeder and Christensen, June 2021 [@specterops-certified-pre-owned]. The &lt;em&gt;wire-level technique name&lt;/em&gt; &quot;Pass-the-Certificate&quot; is popularised by AlmondOffSec&apos;s PassTheCert PoC (Yannick Méheut, May 4, 2022), which targets LDAP/S via Schannel client-cert authentication when PKINIT is unavailable, as a fallback path for environments where domain controllers do not support certificate-based Kerberos pre-authentication [@almondoffsec-passthecert-github] [@almondoffsec-passthecert-blog]. The blog post documents the &lt;code&gt;KDC_ERR_PADATA_TYPE_NOSUPP&lt;/code&gt; error path that diverts the PKINIT-blocked attacker into Schannel.&lt;/p&gt;
&lt;p&gt;The AlmondOffSec blog post acknowledges the social attribution of the term: &quot;Note for Googlers: this tool extends the notion of Pass the Certificate, thus dubbed by @_nwodtuhs in his Twitter thread on AD CS and PKINIT.&quot; [@almondoffsec-passthecert-blog] The technique name is socially attributed; the catalog framing is editorial.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A common shorthand says that KB5014754 bound NTOWFs to Kerberos, and that this is what forced attackers to shift to certificates. That arrow runs backwards in time. KB5014754 is the &lt;em&gt;response&lt;/em&gt; to Certifried, not the cause of Pass-the-Certificate. The technique class was catalogued by Schroeder and Christensen in June 2021, eleven months before KB5014754 shipped, and the PassTheCert tool that gave the technique its wire-level name appeared six days before Certifried&apos;s disclosure. The shift to certificates happened because certificates were the next long-term credential type Credential Guard did not isolate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What does KB5014754 actually close? Three specific CVEs in the Certifried family: CVE-2022-26923 (the original SID-spoof Certifried disclosure), CVE-2022-26931 (UPN / sAMAccountName collision spoof), and CVE-2022-34691 (the certificate-pre-dating-account-creation case) [@ms-kb5014754]. What does it &lt;em&gt;not&lt;/em&gt; close? The broader ESC2 through ESC8 catalog, which is administrative hardening rather than CVE-class control. And it does not close ESC9 through ESC16, which were enumerated &lt;em&gt;after&lt;/em&gt; KB5014754 shipped and include cases like the &lt;code&gt;CT_FLAG_NO_SECURITY_EXTENSION&lt;/code&gt; template flag that &lt;em&gt;exempts&lt;/em&gt; a template from the very SID extension the patch introduced [@specterops-certs-patches-2022] [@certipy-wiki-privesc].&lt;/p&gt;
&lt;p&gt;The current state of the catalog: as of the 2025 Certipy 5.x documentation, ESC1 through ESC16 is the practitioner enumeration, with each technique characterised by a template-level, ACL-level, CA-administrator-level, NTLM-relay-level, SID-extension-level, or mapping-level abuse primitive [@certipy-wiki-privesc]. Microsoft Defender for Identity&apos;s certificates posture assessment tracks nine distinct ESC numbers as of the 2025 documentation -- ten posture assessments, because ESC4 owner and ESC4 ACL are tracked as separate sub-cases (ESC1, ESC2, ESC3, ESC4 owner, ESC4 ACL, ESC6 preview, ESC7, ESC8, ESC11, ESC15) [@ms-defender-id-certs]. Same pattern as Pass-the-Hash in 2012-2014: documentation tells administrators what to do; the structural exposure is downstream of how each enterprise built its templates years earlier.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ESC ID&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Closed by KB5014754&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ESC1&lt;/td&gt;
&lt;td&gt;Template -- enrollee supplies SAN, client-auth EKU, permissive enrollment&lt;/td&gt;
&lt;td&gt;Partial: SID extension binds requester at issuance; ESC1 still works if the SID extension is absent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC2&lt;/td&gt;
&lt;td&gt;Template -- enrollee supplies SAN, Any-Purpose or no EKU&lt;/td&gt;
&lt;td&gt;No -- administrative hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC3&lt;/td&gt;
&lt;td&gt;Template -- Certificate Request Agent enrollment-agent abuse&lt;/td&gt;
&lt;td&gt;No -- administrative hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC4&lt;/td&gt;
&lt;td&gt;ACL -- writeable template configuration&lt;/td&gt;
&lt;td&gt;No -- administrative hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC6&lt;/td&gt;
&lt;td&gt;CA -- &lt;code&gt;EDITF_ATTRIBUTESUBJECTALTNAME2&lt;/code&gt; flag set on the CA&lt;/td&gt;
&lt;td&gt;No -- CA-level hardening (was MS22-23, separately patched)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC8&lt;/td&gt;
&lt;td&gt;NTLM relay -- HTTP enrolment endpoints reachable from low-privilege contexts&lt;/td&gt;
&lt;td&gt;No -- relay-defence hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC9&lt;/td&gt;
&lt;td&gt;Template -- &lt;code&gt;CT_FLAG_NO_SECURITY_EXTENSION&lt;/code&gt; exempts template from the SID extension&lt;/td&gt;
&lt;td&gt;No -- by design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC11&lt;/td&gt;
&lt;td&gt;NTLM relay -- ICPR RPC endpoint without sign / seal&lt;/td&gt;
&lt;td&gt;No -- relay-defence hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESC16&lt;/td&gt;
&lt;td&gt;CA -- security-extension disabled at the CA level&lt;/td&gt;
&lt;td&gt;No -- CA-level hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Table 1. A representative slice of the ESC1-ESC16 catalog showing what KB5014754 closes and what remains administrative hardening [@specterops-certify-wiki] [@certipy-wiki-privesc] [@specterops-certs-patches-2022].&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;KB5014754 is a CVE-class fix for one sub-case. The broader ADCS catalog is administrative hardening. And the &lt;em&gt;next&lt;/em&gt; credential type -- the one that defeats Credential Guard, Protected Users, and KB5014754 simultaneously -- was already shipping in commodity Mimikatz code by August 2020.&lt;/p&gt;
&lt;h2&gt;8. Pass-the-PRT: The CloudAP Frontier&lt;/h2&gt;
&lt;p&gt;By August 2020, Microsoft had two architectural defenses against credential replay that the security industry actually trusted: Credential Guard for local Active Directory credentials, and (eighteen months later) KB5014754 for the certificate-replay class. Then a Dutch security researcher named Dirk-jan Mollema published a 21-minute read that broke both, in the same paragraph, by stealing a different credential type.&lt;/p&gt;
&lt;p&gt;The credential is the &lt;a href=&quot;https://paragmali.com/blog/inside-the-primary-refresh-token-the-cryptographic-seam-betw/&quot; rel=&quot;noopener&quot;&gt;Primary Refresh Token&lt;/a&gt;. The two foundational write-ups are Mollema&apos;s &quot;Abusing Azure AD SSO with the Primary Refresh Token&quot; [@mollema-prt-abusing] and its follow-on &quot;Digging further into the Primary Refresh Token&quot; [@mollema-prt-digging], both posted in August 2020. The second post is the single most-cited primary source in the fifth generation of the family. Read it once and you understand why Pass-the-PRT is structurally different from everything that came before.&lt;/p&gt;
&lt;p&gt;A PRT is a JSON Web Token refresh token issued by Microsoft Entra ID (formerly Azure AD) to Entra-joined or Hybrid-joined Windows devices, paired with a session key (HMAC-SHA256 secret) and bound to a device key registered at device join.&lt;/p&gt;
&lt;p&gt;The Microsoft Entra documentation describes the artefact precisely: &quot;A Primary Refresh Token (PRT) is a key artifact of Microsoft Entra authentication ... Once issued, a PRT is valid for 90 days and is continuously renewed as long as the user actively uses the device.&quot; [@ms-entra-concept-prt] On Windows the PRT is renewed every four hours during sign-in. The device-key registration binds the PRT to the device that owns it -- and is what an attacker has to work around to use a stolen PRT on a different device.&lt;/p&gt;

The Microsoft Entra-issued long-lived refresh token for SSO on Entra-joined or Hybrid-joined Windows devices. Carries a session key (HMAC-SHA256) used to sign per-request `x-ms-RefreshTokenCredential` cookies, and binds to a device transport key registered at device join. Default lifetime is 90 days with sliding renewal as long as the user actively uses the device; an inactivity timeout governs when an idle PRT must be re-acquired [@ms-entra-concept-prt]. The PRT is the load-bearing artefact for Single Sign-On to every Entra-integrated resource the device&apos;s user can reach.
&lt;p&gt;The PRT default lifetime is 90 days per the Microsoft Entra documentation, with renewal every four hours during Windows sign-in [@ms-entra-concept-prt]. The 14-day figure that sometimes appears in secondary references is the inactivity timeout on certain device states, not the PRT lifetime itself; this article uses the Microsoft Entra documentation&apos;s value to avoid the conflation.&lt;/p&gt;
&lt;p&gt;Where the PRT &lt;em&gt;lives&lt;/em&gt; is what makes the rest of the architecture work -- and what makes it vulnerable. The PRT is &lt;em&gt;hybrid&lt;/em&gt;: issued and revoked cloud-side by Entra ID, stored and used client-side via the &lt;strong&gt;CloudAP&lt;/strong&gt; authentication plug-in, which is loaded into LSASS like any other Windows authentication package.&lt;/p&gt;
&lt;p&gt;The load-bearing structural fact is that CloudAP is &lt;em&gt;in LSASS&lt;/em&gt;, not behind the LSAISO trustlet. Credential Guard&apos;s classical isolation does not extend to the CloudAP plug-in&apos;s working memory, because Credential Guard&apos;s scope is the three credential categories its design predates -- NT hashes, Kerberos TGTs, and &quot;domain credentials&quot; -- and the PRT is none of those [@mollema-prt-abusing].&lt;/p&gt;

The Windows authentication package (`cloudap.dll`, loaded into LSASS) that handles authentication against Microsoft Entra ID for Entra-joined and Hybrid-joined devices. Holds the device&apos;s Primary Refresh Token, its session key, and the derived material used to sign per-request PRT cookies. Sits inside LSASS in VTL0, *not* inside the LSAISO trustlet in VTL1; Credential Guard does not currently extend its isolation to CloudAP&apos;s working memory.
&lt;p&gt;The mechanism, as Mollema and Delpy developed it through the second half of 2020, runs as follows. Mimikatz &lt;code&gt;dpapi::cloudapkd /unprotect&lt;/code&gt; extracts the PRT (the encrypted-by-Entra refresh-token blob) and the session key from CloudAP&apos;s working memory.&lt;/p&gt;
&lt;p&gt;The attacker constructs an &lt;code&gt;x-ms-RefreshTokenCredential&lt;/code&gt; JWT carrying the PRT in the &lt;code&gt;refresh_token&lt;/code&gt; claim, &lt;code&gt;is_primary: true&lt;/code&gt;, and a &lt;code&gt;request_nonce&lt;/code&gt; obtained by an unauthenticated POST against the Entra ID v1 token endpoint at &lt;code&gt;https://login.microsoftonline.com/common/oauth2/token&lt;/code&gt; with form-encoded body &lt;code&gt;grant_type=srv_challenge&lt;/code&gt; (the server-challenge nonce pattern used by the ROADtools &lt;code&gt;roadtx prt&lt;/code&gt; reference implementation; the response is a JSON object with a &lt;code&gt;Nonce&lt;/code&gt; field). The signature is HMAC-SHA256 over the JWT under the session key. The completed cookie is presented to &lt;code&gt;login.microsoftonline.com&lt;/code&gt; from any machine, and Entra ID returns access and refresh tokens for any resource the original user can reach. Mollema&apos;s second post describes the collaboration that built the tooling:&lt;/p&gt;

Around the same time Benjamin Delpy took up my &apos;challenge&apos; of recovering PRT data from `lsass` with mimikatz. We combined forces and ended up with tooling that is not only able to extract the PRT and associated cryptographic keys (such as the session key) from memory, but can also use these keys to create new SSO cookies or modify existing ones. -- Dirk-jan Mollema, *Digging further into the Primary Refresh Token* [@mollema-prt-digging]
&lt;p&gt;The operational tooling closed quickly. Mollema&apos;s &lt;code&gt;roadtx prt&lt;/code&gt; (part of ROADtools [@roadtools-github]) automates the full chain end-to-end -- extract the material, mint the cookie, complete the OAuth dance, hand the attacker an access token. The Mimikatz &lt;code&gt;dpapi::cloudapkd&lt;/code&gt; command landed in the open-source repository the same window. Pass-the-PRT moved from research artefact to commodity tooling in months, not years.&lt;/p&gt;

sequenceDiagram
    participant Victim as Victim device (Entra-joined)
    participant Attacker as Attacker device
    participant Entra as login.microsoftonline.com
    Note over Victim: PRT plus session key held by CloudAP in LSASS
    Attacker-&amp;gt;&amp;gt;Victim: mimikatz dpapi::cloudapkd /unprotect
    Victim--&amp;gt;&amp;gt;Attacker: PRT (encrypted blob) plus session key
    Attacker-&amp;gt;&amp;gt;Entra: POST /common/oauth2/token grant_type=srv_challenge (unauthenticated)
    Entra--&amp;gt;&amp;gt;Attacker: request_nonce
    Note over Attacker: Build x-ms-RefreshTokenCredential JWT
    Note over Attacker: Sign HMAC-SHA256 with extracted session key
    Attacker-&amp;gt;&amp;gt;Entra: POST /token with PRT cookie
    Entra--&amp;gt;&amp;gt;Attacker: Access and refresh tokens
    Attacker-&amp;gt;&amp;gt;Attacker: Authenticate to any Entra resource as victim user
&lt;p&gt;Now the analytical core. Pass-the-PRT defeats three Microsoft defenses &lt;em&gt;simultaneously&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Credential Guard&lt;/strong&gt; is out of scope. The CloudAP material is not an NT hash, not a Kerberos TGT, and not &quot;credentials stored by applications as domain credentials&quot; in the verbatim sense the Credential Guard documentation uses. Credential Guard&apos;s VBS-based isolation does not extend to CloudAP. The defense was designed in 2015 against the three credential types the family had then; the PRT is a credential type the family had not yet evolved into [@ms-learn-credential-guard].&lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;KB5014754&lt;/strong&gt; is out of scope. The PRT cookie does not traverse the KDC&apos;s certificate-mapping logic at all; it is a JWT signed by an HMAC and authenticated at the Entra ID token endpoint. The strong certificate mapping that Microsoft drove through five years of audit-to-enforcement timeline has no relevance to a credential that never touches the KDC [@ms-kb5014754].&lt;/p&gt;
&lt;p&gt;Third, &lt;strong&gt;Protected Users&lt;/strong&gt; is out of scope. Protected Users is an Active-Directory-only construct, enforced on Windows Server domain controllers and on AD-joined member devices. Entra ID is a separate identity provider with separate enforcement; the 240-minute TGT cap, the NTLM ban, and the RC4 ban that Protected Users enforces simply do not apply [@ms-protected-users].&lt;/p&gt;
&lt;p&gt;The TPM-sealing finding is where the architectural pattern becomes most precise. Microsoft began sealing the PRT session key to 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-bound key&lt;/a&gt; on TPM-2.0-eligible hardware -- a defense that, in principle, makes the raw session key cryptographically non-exportable. Mollema&apos;s finding in the August 2020 second post is that the seal does not close the attack, because CloudAP holds &lt;em&gt;derived&lt;/em&gt; PRT-cookie-signing material in its own working memory in LSASS, and the attacker only needs the derived material:&lt;/p&gt;

despite the session key of the PRT is stored in the TPM whenever possible, this doesn&apos;t prevent us from extracting the PRT and the required information to create SSO cookies. The result of this is that regardless of whether the PRT is protected by the TPM or not, with Administrator access it is possible to extract the PRT from LSASS and use the PRT on a different device than it was issued to. -- Dirk-jan Mollema, *Digging further into the Primary Refresh Token* [@mollema-prt-digging]
&lt;p&gt;The structural reason the standard hardware-rooted defense pattern does not transfer: the attacker does not need the raw session key out of the TPM. They need only the in-memory derived material CloudAP itself uses to sign the cookies, and that derived material lives in the same address space Credential Guard does not isolate.&lt;/p&gt;
&lt;p&gt;The TPM seals the key. CloudAP uses the key. Whatever CloudAP can read, an attacker with administrator and a memory-access primitive can also read. The defense pattern that worked for NT hashes (move them out of the address space) has not been applied to CloudAP -- and until it is, the TPM seal is a speed bump rather than a wall.&lt;/p&gt;
&lt;p&gt;{`
// Pedagogical demonstration of the JWT structure used in Pass-the-PRT
// cookie minting. Uses placeholder values throughout; no real PRT material.&lt;/p&gt;
&lt;p&gt;const base64url = (buf) =&amp;gt; Buffer.from(buf).toString(&apos;base64&apos;)
  .replace(/=+$/, &apos;&apos;).replace(/\+/g, &apos;-&apos;).replace(/\//g, &apos;_&apos;);&lt;/p&gt;
&lt;p&gt;const header = { alg: &apos;HS256&apos;, ctx: &apos;AAAAAAAA&apos; };
const payload = {
  // The PRT itself, an opaque refresh-token string Entra issued to the
  // device. In a real attack this comes from mimikatz dpapi::cloudapkd.
  refresh_token: &apos;AQABAAAAAAA...redacted...&apos;,
  // Marks this cookie as a primary refresh token cookie.
  is_primary: &apos;true&apos;,
  // Fresh nonce from an unauthenticated POST against the v1 token endpoint
  // at login.microsoftonline.com/common/oauth2/token with form body
  // grant_type=srv_challenge (returns JSON with Nonce field; the canonical
  // server-challenge pattern used by ROADtools roadtx prt).
  request_nonce: &apos;AwABAAEAAAAC...&apos;,
  iat: Math.floor(Date.now() / 1000),
};&lt;/p&gt;
&lt;p&gt;// HMAC-SHA256 over the JWT under the session key recovered from CloudAP.
// Placeholder key for demonstration only.
const sessionKey = Buffer.alloc(32); // 32 bytes of zeros (fake)
const crypto = require(&apos;crypto&apos;);&lt;/p&gt;
&lt;p&gt;const h = base64url(JSON.stringify(header));
const p = base64url(JSON.stringify(payload));
const sig = base64url(
  crypto.createHmac(&apos;sha256&apos;, sessionKey).update(h + &apos;.&apos; + p).digest()
);&lt;/p&gt;
&lt;p&gt;console.log(&apos;Header segment:    &apos; + h);
console.log(&apos;Payload segment:   &apos; + p);
console.log(&apos;Signature segment: &apos; + sig);
console.log();
console.log(&apos;Full PRT cookie: &apos; + h + &apos;.&apos; + p + &apos;.&apos; + sig);
// In a real attack the attacker would now POST this as the
// x-ms-RefreshTokenCredential cookie to login.microsoftonline.com.
`}&lt;/p&gt;
&lt;p&gt;The current partial mitigations are worth enumerating, because none of them closes the gap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Token Protection&lt;/strong&gt; (a &lt;a href=&quot;https://paragmali.com/blog/who-decided-this-token-is-good-a-field-guide-to-conditional-/&quot; rel=&quot;noopener&quot;&gt;Conditional Access&lt;/a&gt; session control) attempts to ensure that only device-bound sign-in session tokens are accepted at the Entra ID token endpoint for protected resources. The Microsoft Learn page is explicit about both the design intent and the deployment limits: &quot;Token Protection is a Conditional Access session control that attempts to reduce token replay attacks by ensuring only device bound sign-in session tokens, like Primary Refresh Tokens (PRTs), are accepted by Microsoft Entra ID when applications request access to protected resources.&quot; [@ms-entra-token-protection] As of the current documentation the &lt;em&gt;supported resources&lt;/em&gt; are five named applications: Exchange Online, SharePoint Online, Microsoft Teams, Azure Virtual Desktop, and Windows 365. Browser applications are out of scope; &quot;Token Protection currently supports native applications only. Browser-based applications are not supported.&quot; [@ms-entra-token-protection] Most Entra-integrated SaaS is unbound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuous Access Evaluation&lt;/strong&gt; (CAE) shortens the window during which a stolen PRT is operationally usable, by allowing the token endpoint to revoke tokens within minutes of a triggering signal (password change, risk-based detection, conditional-access policy update) [@ms-entra-cae]. CAE is evaluation-time, not isolation. It shortens the window between extraction and detection-driven revocation; it does not prevent extraction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hybrid-joined PRT renewal binding&lt;/strong&gt; partially closes the cross-tenant case for hybrid Azure AD Join configurations, but does not address the same-tenant Pass-the-PRT case that Mollema&apos;s original 2020 posts described [@ms-entra-hybrid-join-plan].&lt;/p&gt;
&lt;p&gt;The institutional acknowledgment of the supersession pattern is the verbatim Microsoft Learn sentence already quoted in section 6 [@ms-learn-credential-guard]: written about the 2015 Credential Guard architecture, it accurately predicts the 2020 Pass-the-PRT shift. The credential-replay family has reached the point where &lt;em&gt;every Microsoft defense&lt;/em&gt; in the on-prem stack runs in parallel against an attack the on-prem stack cannot reach.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Pass-the-PRT defeats Credential Guard, KB5014754, and Protected Users simultaneously because each defense was designed around a different long-term artefact, and the PRT is none of them. The architectural property -- a long-term authentication artefact reachable from the using process is replayable -- is unchanged. The artefact moved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Six years after Mollema&apos;s disclosure, the TPM-resilience finding still holds. The CloudAP plug-in is still in LSASS. Credential Guard still does not extend its boundary. Pass-the-PRT remains the operational frontier in 2026.&lt;/p&gt;
&lt;h2&gt;9. The 5x5 Matrix and the Irregular Cadence&lt;/h2&gt;
&lt;p&gt;Five generations of attack. Five generations of defense. They map onto each other unevenly; the gaps are not five years.&lt;/p&gt;
&lt;p&gt;The matrix below consolidates the lineage at a glance. Rows are the attack generations (in the order they entered the practitioner literature). Columns are the defense generations (in the order they shipped). Each cell records whether that defense closes that attack on a fully-deployed hardware-eligible 2026 Windows 11 endpoint with the control turned on. &quot;Closed&quot; means the attack returns empty buffers or fails authentication; &quot;Partial&quot; means the defense increases attacker cost or closes one sub-case; &quot;Open&quot; means the defense&apos;s design scope does not include that attack.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack \ Defense&lt;/th&gt;
&lt;th&gt;Mitigating-PtH whitepapers (2012/2014)&lt;/th&gt;
&lt;th&gt;Protected Users + RunAsPPL + Restricted Admin (2013-2014)&lt;/th&gt;
&lt;th&gt;Credential Guard / LSAISO (2015)&lt;/th&gt;
&lt;th&gt;KB5014754 strong mapping (2022)&lt;/th&gt;
&lt;th&gt;Token Protection + CAE (2023-2025)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Pass-the-Hash (Ashton 1997, Ochoa 2008)&lt;/td&gt;
&lt;td&gt;Open (documentation)&lt;/td&gt;
&lt;td&gt;Partial (Protected Users members)&lt;/td&gt;
&lt;td&gt;Closed (on enabled endpoints)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass-the-Ticket (Delpy 2011, Duckwall+Delpy 2014)&lt;/td&gt;
&lt;td&gt;Open (documentation)&lt;/td&gt;
&lt;td&gt;Partial (4-hour TGT cap for Protected Users)&lt;/td&gt;
&lt;td&gt;Closed (TGT session key in LSAISO)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overpass-the-Hash (Delpy / Metcalf 2014)&lt;/td&gt;
&lt;td&gt;Open (documentation)&lt;/td&gt;
&lt;td&gt;Partial (RC4 banned for Protected Users)&lt;/td&gt;
&lt;td&gt;Closed (NT hash in LSAISO)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass-the-Certificate (Schroeder + Christensen 2021, Méheut 2022)&lt;/td&gt;
&lt;td&gt;Open (documentation)&lt;/td&gt;
&lt;td&gt;Open (cert keys outside scope)&lt;/td&gt;
&lt;td&gt;Open (cert keys outside scope)&lt;/td&gt;
&lt;td&gt;Partial (closes Certifried sub-case; ESC2-ESC16 remain)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass-the-PRT (Mollema + Delpy 2020)&lt;/td&gt;
&lt;td&gt;Open (Entra ID is separate IDP)&lt;/td&gt;
&lt;td&gt;Open (Entra ID is separate IDP)&lt;/td&gt;
&lt;td&gt;Open (CloudAP not in LSAISO)&lt;/td&gt;
&lt;td&gt;Open (not in scope)&lt;/td&gt;
&lt;td&gt;Partial (5 named resources; browser apps out of scope)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Table 2. The 5x5 attack/defense matrix. The union of every cell in the rightmost column of &quot;Closed&quot; entries is the set of attacks Microsoft&apos;s published 2026 defenses close on hardware-eligible non-DC endpoints with every control turned on; that set is precisely the first three rows.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The matrix makes the structure visible. No single defense closes all attacks, and no single attack is closed by all defenses. The union of every defense closes Pass-the-Hash, Pass-the-Ticket, and Overpass-the-Hash on hardware-eligible non-DC Windows 10/11 systems with all controls enabled. It partially closes Pass-the-Certificate (for the Certifried sub-case) and partially closes Pass-the-PRT (for five named resources). Both of the most recent generations remain operationally open against any deployment that does not run those specific controls -- which is most deployments.&lt;/p&gt;
&lt;p&gt;The cadence is just as uneven as the matrix. The original input that prompted this article claimed &quot;every Windows defense against credential replay buys about five years before the attack class evolves to the next credential type.&quot; Memorable. Also wrong. The actual timeline produces gaps from eleven months to eleven years, with one negative interval:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1997 -&amp;gt; 2008&lt;/strong&gt; (eleven years) for the Samba-patch -&amp;gt; Windows-native pivot. Pass-the-Hash existed for over a decade as a Unix-side novelty before Ochoa&apos;s LSASS-injection insight made it Windows-native.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2008 -&amp;gt; 2011&lt;/strong&gt; (three years) for the Mimikatz Pass-the-Ticket extension. The same memory-access primitive that animated &lt;code&gt;IAM.EXE&lt;/code&gt; was retargeted at a different artefact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2012/2014 -&amp;gt; 2015&lt;/strong&gt; (one to three years) for the Mitigating-PtH whitepapers -&amp;gt; Credential Guard pivot. Documentation took a year and a half to ship; the architectural counter took another.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2021 -&amp;gt; 2022&lt;/strong&gt; (eleven months) for the AD CS catalog -&amp;gt; KB5014754 response. Coordinated disclosure compressed this gap; Certifried&apos;s CVE-class status forced a CVE-class response.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2020 -&amp;gt; 2025+&lt;/strong&gt; (open-ended) for Pass-the-PRT with no Credential-Guard-equivalent shipped. As of the Windows 11 25H2 cycle there is no public roadmap for VBS-class isolation of CloudAP material.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most striking gap is the 2020/2021 &lt;em&gt;negative&lt;/em&gt; interval. Pass-the-PRT (Mollema, August 2020) and the AD CS catalog (Schroeder + Christensen, June 2021) are siblings rather than sequential; Pass-the-PRT predates Pass-the-Certificate as a &lt;em&gt;named technique&lt;/em&gt; by ten months, even though the article treats them as Generation 4 and Generation 5 in narrative order. The Generation N -&amp;gt; N+1 framing is &lt;em&gt;taxonomic&lt;/em&gt;, not strictly chronological. The reader needs this distinction to read the lineage accurately: the attack class evolves along the architectural property, not along the calendar.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &quot;every Windows defense buys five years&quot; framing is what you see if you select the cleanest pairings (Mitigating-PtH 2012/2014 to Credential Guard 2015 plus an artificial 2020-targeted &quot;next attack&quot;). When you look at the actual intervals, you see eleven years (1997-2008), three years (2008-2011), eleven months (2021-2022), and an open-ended interval (2020 onwards). The pattern is the architectural property persisting across artefact changes, not a calendar drumbeat.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The storage-class progression is the cleanest way to see the property hold across the lineage. Each row names the long-term artefact, where it lives, and which defense moved or shielded that storage class.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;th&gt;Long-term artefact&lt;/th&gt;
&lt;th&gt;Storage location&lt;/th&gt;
&lt;th&gt;Defense that isolated it&lt;/th&gt;
&lt;th&gt;Status 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1A (1997 Samba)&lt;/td&gt;
&lt;td&gt;NT hash (and LM hash)&lt;/td&gt;
&lt;td&gt;Local SAM file on disk&lt;/td&gt;
&lt;td&gt;&quot;Do not store LAN Manager hash&quot; policy (Vista default-on); SAM hash extraction still works&lt;/td&gt;
&lt;td&gt;LM hash retired; NT hash extraction still works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1B (2008 Windows-native)&lt;/td&gt;
&lt;td&gt;NT hash&lt;/td&gt;
&lt;td&gt;LSASS credential cache&lt;/td&gt;
&lt;td&gt;Credential Guard relocates to LSAISO&lt;/td&gt;
&lt;td&gt;Closed on Credential-Guard-enabled endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2 (2011 Mimikatz)&lt;/td&gt;
&lt;td&gt;Kerberos TGT plus session key&lt;/td&gt;
&lt;td&gt;LSASS Kerberos package&lt;/td&gt;
&lt;td&gt;Credential Guard relocates to LSAISO&lt;/td&gt;
&lt;td&gt;Closed on Credential-Guard-enabled endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 (2014)&lt;/td&gt;
&lt;td&gt;NT hash promoted to RC4-HMAC Kerberos key&lt;/td&gt;
&lt;td&gt;LSASS, same buffer as Pass-the-Hash&lt;/td&gt;
&lt;td&gt;Credential Guard relocates to LSAISO; KB5021131 makes AES the default&lt;/td&gt;
&lt;td&gt;Closed on Credential-Guard-enabled endpoints; RC4 deprecated in favour of AES [@ms-kb5021131]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 (2021 AD CS catalog)&lt;/td&gt;
&lt;td&gt;X.509 certificate private key&lt;/td&gt;
&lt;td&gt;CryptoAPI key container, TPM, or smart card&lt;/td&gt;
&lt;td&gt;TPM-resident or VSC-resident keys are cryptographically non-exportable; KB5014754 binds certificates to SIDs at issuance&lt;/td&gt;
&lt;td&gt;Partial; ESC2-ESC16 misconfigurations remain administrative hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 (2020 Pass-the-PRT)&lt;/td&gt;
&lt;td&gt;PRT session key plus derived signing material&lt;/td&gt;
&lt;td&gt;CloudAP plug-in in LSASS (session key optionally TPM-sealed)&lt;/td&gt;
&lt;td&gt;None deployed; Token Protection partially shields five resources&lt;/td&gt;
&lt;td&gt;Open&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Table 3. Storage-class progression. Each attack generation targets the next long-term artefact whose storage location is not isolated by the previous generation&apos;s defense.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The matrix and the storage-class table jointly produce the structural prediction: each generation shifts to the next available long-term artefact whose storage class the latest defense does not isolate. The graph-based formalisation of these storage-class transitions is the BloodHound edge catalog -- the &lt;code&gt;HasSession&lt;/code&gt;, &lt;code&gt;AdminTo&lt;/code&gt;, and &lt;code&gt;CanRDP&lt;/code&gt; family that operationalises &quot;which principal can reach which credential from where&quot; as a queryable property of an enterprise&apos;s directory [@bloodhound-edges]. The pattern predicts a Generation 6 outside whatever isolation scope arrives next.&lt;/p&gt;
&lt;p&gt;The most credible candidate today is &lt;strong&gt;Pass-the-DeviceKey&lt;/strong&gt;: extraction or abuse of the device transport key the PRT binds to, or of the CloudAP-derived material the cookie-signing process produces from it [@mollema-prt-phishing]. Mollema&apos;s 2023-2025 continuation work documents the underlying device-transport-key primitives in detail; the September 2025 Actor-tokens disclosure shows that cross-tenant abuse of related Entra-side material is also operational in the wild [@mollema-actor-tokens] [@mollema-federated-credentials].&lt;/p&gt;

flowchart TD
    A1[Pass-the-Hash 1A Samba&lt;br /&gt;Ashton 1997]
    A2[Pass-the-Hash 1B Windows-native&lt;br /&gt;Ochoa 2008]
    A3[Pass-the-Ticket&lt;br /&gt;Delpy 2011]
    A4[Overpass-the-Hash&lt;br /&gt;Delpy / Metcalf 2014]
    A5[Pass-the-Certificate&lt;br /&gt;Schroeder + Christensen 2021]
    A6[Pass-the-PRT&lt;br /&gt;Mollema + Delpy 2020]
    A7[Pass-the-DeviceKey forecast]
    D1[Mitigating-PtH whitepapers&lt;br /&gt;v1 2012, v2 2014]
    D2[Protected Users + RunAsPPL + Restricted Admin&lt;br /&gt;2013-2014]
    D3[Credential Guard / LSAISO&lt;br /&gt;2015, default 2022]
    D4[KB5014754 strong mapping&lt;br /&gt;2022, enforced 2025]
    D5[Token Protection + CAE&lt;br /&gt;2023-2025]
    D6[CloudAP isolation forecast]
    A1 --&amp;gt; A2
    A2 --&amp;gt; A3
    A3 --&amp;gt; A4
    A4 --&amp;gt; A5
    A4 --&amp;gt; A6
    A6 --&amp;gt; A7
    D1 --&amp;gt; D2
    D2 --&amp;gt; D3
    D3 --&amp;gt; D4
    D4 --&amp;gt; D5
    D5 -.- D6
    A2 -.- D1
    A2 -.- D2
    A3 -.- D3
    A4 -.- D3
    A5 -.- D4
    A6 -.- D5
    A7 -.- D6
&lt;p&gt;If the pattern holds, Generation 6 is already in research literature. Mollema&apos;s 2023-2025 continuation work [@mollema-prt-phishing] [@mollema-federated-credentials] [@mollema-actor-tokens] documents the device-transport-key extraction primitives. The only things missing are the name and the commodity tool. The historical pattern says we probably get both before VBS-class CloudAP isolation ships.&lt;/p&gt;
&lt;h2&gt;10. Open Problems and the 2026-2030 Forecast&lt;/h2&gt;
&lt;p&gt;The credential-replay family has six load-bearing open problems in 2026. Each is structural rather than mathematical; the cryptographic primitives that would close them already exist.&lt;/p&gt;
&lt;p&gt;The architectural lower bound -- the only configuration that closes the family in principle -- is the union of three things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Universal hardware-rooted non-extractable keys&lt;/strong&gt;: every long-term authentication artefact lives in a TPM, secure enclave, FIDO2 authenticator, or smart card, with key attestation, and is never released to software memory. &lt;strong&gt;Universal protocol-layer token binding&lt;/strong&gt;: every issued token (Kerberos service ticket, OAuth refresh token, OIDC ID token, SAML assertion) is cryptographically bound to the device that requested it, and a verifier rejects any presentation from a non-bound device. &lt;strong&gt;Universal continuous evaluation&lt;/strong&gt;: every protected resource queries the issuer in near-real-time and revokes within minutes of a triggering signal. Each component is deployed &lt;em&gt;somewhere&lt;/em&gt;; none is deployed &lt;em&gt;everywhere&lt;/em&gt;; no single vendor controls all three layers.&lt;/p&gt;
&lt;p&gt;The five concrete open problems flow from the lower bound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The CloudAP isolation problem.&lt;/strong&gt; When does Microsoft extend VBS-class isolation to the CloudAP plug-in&apos;s working memory in LSASS? No public roadmap as of 2026. Until it ships, Pass-the-PRT remains operationally open against every Entra-joined Windows endpoint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The token-binding adoption problem.&lt;/strong&gt; Token Protection&apos;s verbatim 2026 scope is the five named resources enumerated in section 8 [@ms-entra-token-protection], which covers approximately five percent of typical Entra-integrated SaaS surface area; every other Entra-integrated resource accepts unbound tokens. The OAuth working group&apos;s RFC 9449 (DPoP, September 2023) standardises proof-of-possession at the OAuth layer [@rfc-9449], but adoption across SaaS providers and enterprise applications is uneven.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Pass-the-DeviceKey forecast.&lt;/strong&gt; Mollema&apos;s 2023-2025 continuation work exercises device-transport-key extraction primitives, federated-credential persistence on Entra applications, and cross-tenant Actor-token abuse [@mollema-prt-phishing] [@mollema-federated-credentials] [@mollema-actor-tokens]. The pattern of every previous generation predicts that whichever of these primitives commoditises first will be the next named &quot;Pass-the-X&quot; technique.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The ESC9-ESC16 hardening problem.&lt;/strong&gt; The AD CS catalog has grown from 8 entries (June 2021) to 16 (current Certipy and Certify wikis [@certipy-wiki-privesc] [@specterops-certify-wiki]); most additions are misconfiguration-class rather than CVE-class. ESC9 specifically describes the &lt;code&gt;CT_FLAG_NO_SECURITY_EXTENSION&lt;/code&gt; template flag that &lt;em&gt;exempts&lt;/em&gt; a template from the very SID extension KB5014754 introduced -- so administrators who turn that flag on for legacy compatibility reasons silently re-enable the Certifried-class abuse path on those templates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware-backed identity ubiquity.&lt;/strong&gt; When does the union of Pluton + FIDO2 + virtual smart cards + TPM key attestation eliminate the long-term software-extractable artefact class? Human interactive sign-in to Entra ID can already be fully passwordless on supported hardware. The long tail of service accounts, scheduled tasks, on-prem AD workflows, and legacy applications resists migration; the migration is a years-long enterprise project, not a feature flag.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The non-Microsoft sibling lineages.&lt;/strong&gt; The credential-replay family is not Windows-specific. Okta session-cookie theft, Google IDP refresh-token reuse, Apple ASWebAuthSession token replay, and AWS STS session-token theft all face the same architectural property. An enterprise running Microsoft plus Okta plus Google inherits the union of every vendor&apos;s residual replay surface. The family generalises beyond Microsoft because the architectural property generalises beyond Microsoft.&lt;/p&gt;

Okta&apos;s `sessionToken` and OAuth `refresh_token` artefacts live on the device that requested them, and have been used in commodity offensive tooling since at least 2022. Google&apos;s IDP refresh tokens face the same exposure surface on managed Chromebooks. Apple&apos;s ASWebAuthSession tokens are device-bound at the platform level, which closes the cross-device replay case but not the same-device extraction case. AWS STS session tokens are not device-bound at all. The credential-replay family is a property of long-term software-extractable authentication artefacts in general; this article is Windows-specific only because Windows has the longest documented lineage.
&lt;p&gt;The institutional position is that the protocol-level fix is unavailable -- Microsoft&apos;s framing of Pass-the-Hash as a structural property of NTLM generalises directly to every later generation. A universal fix would require replacing every long-term software-extractable artefact globally with hardware-bound primitives, with mandatory token binding at every issuer and every resource server, with continuous evaluation everywhere. Each step is incrementally closable; the union has not yet closed for any deployment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Universal hardware-rooted non-extractable keys, universal protocol-layer token binding, universal continuous evaluation. Each component is deployed somewhere; none is deployed everywhere. No single vendor controls all three layers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The architectural property the family shares has held for twenty-nine years; the defensive lineage will not close it without making &lt;em&gt;every&lt;/em&gt; long-term artefact live in hardware-rooted isolation that exceeds the host&apos;s privilege. Whether that happens in the next five years, the next ten, or the next twenty-five, is the open question the next chapter of this lineage will answer.&lt;/p&gt;
&lt;h2&gt;11. The 2026 Defender Playbook&lt;/h2&gt;
&lt;p&gt;Architectural humility does not mean defensive passivity. The 2026 estate is defensible against generations 1 through 3 and partially against generation 4; the playbook is to deploy every available control while reading Mollema&apos;s 2025 posts to know what&apos;s coming for generation 5 and beyond.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Credential Guard everywhere it can run.&lt;/strong&gt; Hardware-eligible non-DC Windows 10/11 endpoints, with the four-residual disclosure (AD database, DCs, certificate keys, CloudAP) documented for the SOC so that detection engineering does not assume Credential Guard covers categories it explicitly excludes [@ms-learn-credential-guard].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LSA Protection (RunAsPPL), UEFI-anchored&lt;/strong&gt; stacked underneath, per itm4n&apos;s &quot;complementary&quot; framing [@itm4n-lsass-runasppl]. The UEFI-anchored variant resists the registry-based bypass that a kernel-mode attacker can otherwise apply at boot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication Silos and Protected Users for Tier-0 accounts.&lt;/strong&gt; Expect to encounter unconstrained-delegation breakage on legacy services and budget remediation; the 240-minute TGT cap is the lever that prevents long-lived Tier-0 ticket reuse [@ms-protected-users].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;KB5014754 strong-mapping enforcement&lt;/strong&gt; -- fully on by the September 9, 2025 cutover -- plus an annual certificate-template audit cycle against the ESC1-ESC16 catalog using Certipy or PSPKIAudit [@ms-kb5014754] [@certipy-wiki-privesc]. The audit is the load-bearing control because the strong-mapping fix only closes Certifried-class abuses; the template misconfigurations Schroeder and Christensen catalogued are still administrative responsibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conditional Access with Token Protection where supported&lt;/strong&gt; -- the five resources Microsoft Learn enumerates [@ms-entra-token-protection]. Device-bound sign-ins for privileged accounts; FIDO2 for human interactive sign-in. Know that the long tail of Entra-integrated SaaS does not enforce binding, and that a stolen PRT used against an unbound resource will still authenticate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PRT-extraction telemetry.&lt;/strong&gt; Detect CloudAP-plug-in token access from non-CloudAP processes; tie to Endpoint DLP; alert on out-of-band access to &lt;code&gt;cloudap.dll&lt;/code&gt;-owned regions of LSASS memory. Mollema&apos;s &lt;code&gt;roadtx&lt;/code&gt; and BARK produce signal patterns worth modelling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mental model: assume the PRT is the next NT hash.&lt;/strong&gt; Architect today as if Credential Guard for CloudAP shipped tomorrow -- which means TPM-attested device joins as standard, FIDO2 for every human sign-in, hardware-backed identity for service accounts wherever the vendor supports it, and conditional access policies that treat unmanaged or non-attested devices as untrusted by default.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

Open PowerShell as administrator and run:&lt;p&gt;&lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard | Format-List&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The result of interest is &lt;code&gt;SecurityServicesRunning&lt;/code&gt;. A value of &lt;code&gt;1&lt;/code&gt; in that list means Credential Guard is actively running (per the Win32_DeviceGuard documentation: &lt;code&gt;1 = Credential Guard&lt;/code&gt;, &lt;code&gt;2 = HVCI&lt;/code&gt;, &lt;code&gt;3 = System Guard secure launch&lt;/code&gt;, etc.). &lt;code&gt;SecurityServicesConfigured&lt;/code&gt; tells you what the policy intends; &lt;code&gt;SecurityServicesRunning&lt;/code&gt; tells you what the hypervisor is actually enforcing right now. The two values disagree more often than you would expect, usually because the hardware did not meet a prerequisite at boot.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The minimum-viable layer: Credential Guard on every hardware-eligible non-DC endpoint, KB5014754 enforcement-mode certificate strong mapping with an annual ESC catalog audit, and PRT-extraction telemetry tied to a real detection workflow. The first two are commodity Microsoft features that close real attack classes today; the third is the only meaningful signal you can get on the attack class that none of the published defenses currently closes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;None of this closes Pass-the-PRT. All of it shortens the dwell time.&lt;/p&gt;
&lt;h2&gt;12. Frequently Asked Questions&lt;/h2&gt;


No. The Primary Refresh Token sits in the CloudAP plug-in, which is outside Credential Guard&apos;s verbatim three-credential scope -- see section 6 (&quot;What does Credential Guard isolate?&quot;) and section 8 (&quot;Pass-the-PRT defeats three Microsoft defenses simultaneously&quot;) for the full mechanism.

No. The 1997 Ashton patch and the 2008 Ochoa Windows-native pivot are both pre-Mimikatz; see section 1 and section 3 for the full origin story. Mimikatz is the dominant *tool* (May 2011 first release) but it is not the *origin* of Pass-the-Hash.

No. The PRT is *hybrid* -- issued and revoked cloud-side by Entra ID, but stored and used client-side via the CloudAP plug-in inside LSASS. See section 8 (&quot;Where the PRT *lives*&quot;) for why this hybrid architecture is what makes Pass-the-PRT operationally tractable today.

No. It closed the three Certifried-class CVEs (CVE-2022-26923, CVE-2022-26931, CVE-2022-34691) but not the broader ESC2 through ESC16 catalog. See section 7 (&quot;What does KB5014754 actually close?&quot;) and Table 1 for the per-template breakdown.

For human interactive sign-in to Entra ID, mostly, if the entire enterprise migrates -- the FIDO2 authenticator holds a non-extractable private key in hardware, and the resulting authentication is bound to that key. For service accounts, scheduled tasks, on-prem Kerberos workflows, hybrid identity scenarios, and the long tail of legacy applications, no -- those paths still rely on long-term software-extractable artefacts (passwords, hashes, keys) by construction. The architectural counter is universal hardware-rooted non-extractable keys plus universal token binding plus universal continuous evaluation; the operational reality is partial coverage.

No public v3. See section 5 (&quot;The Mitigating-PtH v3 that never shipped&quot;) for the source-by-source disambiguation against Microsoft Download Center ID 36036.

&lt;h2&gt;13. The Pattern That Outlived Six Defenses&lt;/h2&gt;
&lt;p&gt;The 1997 patch and the 2026 attack are the same attack because the architectural property the family shares is unchanged. The artefact moved; the property did not.&lt;/p&gt;
&lt;p&gt;A long-term authentication artefact reachable by the using process is replayable. The NT hash sat in LSASS on Windows NT 4.0 and replayed against SMB. The Kerberos TGT sat in LSASS on Windows Server 2003 and replayed against Kerberos services. The NT hash sat in LSASS on Windows Server 2008 and replayed against the KDC&apos;s RC4-HMAC authentication path as a real Kerberos client.&lt;/p&gt;
&lt;p&gt;The X.509 certificate private key sat in a CryptoAPI key container on Windows Server 2012 R2 and replayed against PKINIT-supporting domain controllers as the principal in the SAN. The Primary Refresh Token sits in the CloudAP plug-in inside LSASS on Windows 11 23H2 today, and replays against Entra ID as the device&apos;s user from any machine that holds the extracted session key.&lt;/p&gt;
&lt;p&gt;Each defense relocated the artefact to a harder-to-reach storage class. The &quot;Do not store LAN Manager hash&quot; policy retired LM. RunAsPPL marked LSASS as a Protected Process Light. Credential Guard moved NT hashes and TGT session keys out of LSASS in VTL0 into the LSAISO trustlet in VTL1. KB5014754 bound certificates to SIDs at issuance, so that a certificate without the SID extension fails strong mapping at the KDC. Token Protection bound PRTs to devices, so that a stolen PRT used against a supported resource from a non-bound device fails.&lt;/p&gt;
&lt;p&gt;Each defense was real. Each closed a generation. The family did not close.&lt;/p&gt;
&lt;p&gt;The reason the family does not close is structural. Every generation finds the next long-term artefact whose storage class the latest defense did not isolate. Pass-the-Hash worked because the NT hash was reachable. Pass-the-Ticket worked because the TGT was reachable. Overpass-the-Hash worked because the NT hash was reachable &lt;em&gt;and&lt;/em&gt; the KDC accepted RC4-HMAC. Pass-the-Certificate worked because certificate templates were misconfigured and the SID extension did not exist. Pass-the-PRT works because CloudAP is in LSASS in VTL0 and Token Protection covers five resources.&lt;/p&gt;
&lt;p&gt;The architectural lower bound -- universal hardware-rooted non-extractable keys plus universal token binding plus universal continuous evaluation -- is the only configuration that closes the family, and it is not deployed anywhere as a complete stack.&lt;/p&gt;
&lt;p&gt;The playbook in the previous section is what to do today. The forecast in section 10 is what to architect for next. The closing observation is the one this article exists to register: when you read about the next named &quot;Pass-the-X&quot; technique, you already know what it will look like. A long-term authentication artefact, reachable from the process that holds it, replayed from a different machine, defeating the latest defense because that defense was designed for a different artefact.&lt;/p&gt;
&lt;p&gt;Generation 6 is already in research literature. The only thing missing is the name.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;pass-the-hash-to-pass-the-prt&quot; keyTerms={[
  { term: &quot;NT hash&quot;, definition: &quot;16-byte MD4 of the user&apos;s password as UTF-16 little-endian; the long-term Windows authentication secret since the early NT releases, unsalted by design.&quot; },
  { term: &quot;NTLM challenge-response&quot;, definition: &quot;Family of Windows authentication protocols (NTLMv1 and NTLMv2) in which the server sends a random challenge and the client returns a keyed cryptographic response computed under a key derived from the user&apos;s password; the password is never transmitted.&quot; },
  { term: &quot;Pass-the-Hash&quot;, definition: &quot;Authenticating with a stolen NT hash by feeding it directly to the protocol&apos;s response-construction function instead of typing a password; Paul Ashton, NTBugtraq, April 1997.&quot; },
  { term: &quot;LSASS&quot;, definition: &quot;Local Security Authority Subsystem Service; the user-mode Windows process that caches in-memory credential material (hashes, tickets, certificate handles, PRT material) for the duration of each logon session.&quot; },
  { term: &quot;Kerberos TGT&quot;, definition: &quot;Ticket Granting Ticket: the long-lived Kerberos credential issued by the KDC&apos;s Authentication Service, encrypted under the krbtgt long-term key, carrying a session key for subsequent service-ticket requests.&quot; },
  { term: &quot;Pass-the-Ticket&quot;, definition: &quot;Extracting a Kerberos TGT (and its session key) from one machine&apos;s LSASS-resident Kerberos cache and injecting it into another machine&apos;s cache.&quot; },
  { term: &quot;Overpass-the-Hash&quot;, definition: &quot;Presenting a stolen NT hash to the KDC as the user&apos;s long-term RC4-HMAC Kerberos key (per RFC 4757) to obtain a real TGT signed by the real krbtgt.&quot; },
  { term: &quot;Credential Guard&quot;, definition: &quot;Windows feature that relocates NT hashes, Kerberos TGT session keys, and &apos;credentials stored by applications as domain credentials&apos; from LSASS in VTL0 to the LSAISO trustlet in VTL1, isolated by the Windows hypervisor.&quot; },
  { term: &quot;LSAISO trustlet&quot;, definition: &quot;The isolated-user-mode LSA process (lsaiso.exe) that holds Credential Guard&apos;s protected credential material in VTL1; unreadable from any VTL0 process or driver.&quot; },
  { term: &quot;PKINIT&quot;, definition: &quot;Kerberos pre-authentication using a certificate&apos;s private key in place of a long-term symmetric key (RFC 4556); the SAN of the certificate maps to the principal whose TGT the KDC will issue.&quot; },
  { term: &quot;Pass-the-Certificate&quot;, definition: &quot;Authenticating to Active Directory with a stolen X.509 certificate&apos;s private key via PKINIT to the KDC or Schannel client-cert authentication to LDAPS.&quot; },
  { term: &quot;szOID_NTDS_CA_SECURITY_EXT&quot;, definition: &quot;X.509 extension introduced by KB5014754 (OID 1.3.6.1.4.1.311.25.2) that carries the requesting principal&apos;s SID at certificate issuance; the basis of KDC strong certificate mapping.&quot; },
  { term: &quot;Primary Refresh Token (PRT)&quot;, definition: &quot;Microsoft Entra-issued long-lived refresh token for SSO on Entra-joined or Hybrid-joined Windows devices; carries a session key (HMAC-SHA256) and binds to a device transport key; default 90-day lifetime with sliding renewal.&quot; },
  { term: &quot;CloudAP&quot;, definition: &quot;Cloud Authentication Provider; the Windows authentication package (cloudap.dll) loaded into LSASS that holds Microsoft Entra credential material including the PRT; not currently inside Credential Guard&apos;s isolation scope.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>active-directory</category><category>kerberos</category><category>credential-theft</category><category>credential-guard</category><category>entra-id</category><category>pass-the-hash</category><category>pass-the-prt</category><category>windows-security</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Above the Kernel: The Windows Security Wars Part 4 (2015-2019)</title><link>https://paragmali.com/blog/above-the-kernel-the-windows-security-wars-part-4-2015-2019/</link><guid isPermaLink="true">https://paragmali.com/blog/above-the-kernel-the-windows-security-wars-part-4-2015-2019/</guid><description>Windows 10 ships Virtualization-Based Security and finally puts the credential store above the kernel -- in the same five years that ransomware became a billion-dollar industry.</description><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><content:encoded>
Between July 2015 and December 2019, Windows shipped its largest structural security discontinuity since the NT design itself: Virtualization-Based Security (VBS), which moves the credential store and the kernel code-integrity policy into a Secure Kernel running at a privilege level the NT kernel cannot reach. In the same five-year window, ransomware industrialized from spray-and-pray to double extortion -- WannaCry, NotPetya, Ryuk, REvil, Maze -- and a third axis, Meltdown / Spectre, proved the CPU itself could be the attacker&apos;s primitive. The paradox of simultaneity is the whole story: a kernel-isolated 2017 Enterprise laptop and a paralyzed NHS trust both ran &quot;Windows&quot; that May 12, and the difference between them was not architecture but operations -- a missing patch on a network nobody had segmented.
&lt;h2&gt;1. Two Scenes, One Five-Year Window&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Scene A.&lt;/strong&gt; A red-team operator, sometime in late 2016, sits in front of a freshly-imaged Windows 10 1607 Enterprise laptop with Credential Guard enabled. They open an elevated PowerShell, drop &lt;code&gt;mimikatz.exe&lt;/code&gt; to disk, launch it, type &lt;code&gt;privilege::debug&lt;/code&gt;. The prompt returns &lt;code&gt;&apos;20&apos; OK&lt;/code&gt;. They type &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt;. Output scrolls. The &lt;code&gt;NTLM&lt;/code&gt; and &lt;code&gt;Kerberos&lt;/code&gt; fields, where the cached hash and the Ticket Granting Ticket would normally appear, are empty. Not denied. Not access-restricted. Empty. The local LSASS process still exists; it still answers requests; the API surface is intact. But the secrets the operator came to read no longer live in this kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scene B.&lt;/strong&gt; 11:00 a.m. UTC, May 12, 2017. The Royal London Hospital&apos;s radiology department. A workstation displays a red ransom note in eight languages. By 4:00 p.m., the National Audit Office will later determine, the attack has disrupted at least 34 percent of NHS trusts in England; some 19,000 patient appointments will be cancelled; ambulances will divert; junior doctors will hand-write prescriptions on paper [@nao-wannacry]. The exploit that delivered the worm to that machine, CVE-2017-0144, is one of the SMBv1 remote code execution flaws patched in Microsoft Security Bulletin MS17-010 [@ms-ms17-010] [@nvd-cve-2017-0144]. The patch shipped on March 14, 2017. It is, on May 12, one month and twenty-eight days old [@ms-ms17-010].&lt;/p&gt;
&lt;p&gt;Both scenes happened. Both Windows boxes ran versions of the same operating system released in the same five-year window. Neither scene is hyperbole.&lt;/p&gt;
&lt;p&gt;How can both be true at once? And what does the answer teach us about architectural defense -- its limits and its genuine accomplishments?&lt;/p&gt;
&lt;h2&gt;2. The Same-Privilege Paradox (1993-2014)&lt;/h2&gt;
&lt;p&gt;Here is a sentence to carry through the rest of this article: &lt;strong&gt;a defense that lives at the same privilege level as the attacker can always be turned off.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That sentence is the lesson of every Windows defense built between NT 3.51 in 1993 and Windows 8.1 in 2013. It is also the reason VBS had to exist at all.&lt;/p&gt;
&lt;p&gt;Consider the pattern. The NT security model rests on access tokens and privileges. The privilege named &lt;code&gt;SeDebugPrivilege&lt;/code&gt; lets a holder open any other process and read its memory. Local administrators get it by default; Mimikatz, released by Benjamin Delpy in May 2011, weaponized it [@wired-mimikatz]. Once an attacker reached local SYSTEM, &lt;code&gt;SeDebugPrivilege&lt;/code&gt; let them walk into the Local Security Authority Subsystem Service (LSASS) and lift NTLM hashes and Kerberos tickets verbatim. The privilege check was working exactly as designed; the design assumed that whoever had the privilege deserved the data.&lt;/p&gt;
&lt;p&gt;In 2005, with x64 versions of Windows Server 2003 SP1 and Windows XP, Microsoft introduced Kernel Patch Protection -- PatchGuard -- alongside Kernel-Mode Code Signing [@ms-patchguard]. PatchGuard&apos;s job was to detect modifications to critical kernel structures (the SSDT, the IDT, the GDT) and bugcheck the machine if it saw tampering. It was a watchdog inside the kernel watching the kernel.&lt;/p&gt;
&lt;p&gt;By 2007, the indie research journal &lt;code&gt;Uninformed&lt;/code&gt; published Skywing&apos;s third installment in a public series demonstrating how a kernel-mode attacker could disarm PatchGuard by rewriting its own code paths in-place [@skywing-patchguard]. The bypass was not a clever exploit; it was an inevitability. A monitor running in ring 0 has no privilege the rootkit lacks.&lt;/p&gt;
&lt;p&gt;Driver Signing Enforcement followed the same logic and met the same fate [@ms-patchguard] [@skywing-patchguard]. So did Authenticode, AppLocker, and every other gate placed at the attacker&apos;s reachable privilege level. James Forshaw&apos;s August 2016 Project Zero work on AppContainer escape via shadow object directories rounded out the pattern: even the lowest-privilege sandboxes on Windows could be punctured by symbolic-link redirection executed at the sandbox&apos;s own privilege level [@pz-forshaw-shadow].&lt;/p&gt;
&lt;p&gt;By 2012, three independent vectors had converged on the same insight. Bromium, co-founded by Xen architect Ian Pratt, shipped vSentry: a Type-1 micro-hypervisor that wrapped every risky task -- a browser tab, an opened document, an email attachment -- in its own micro-VM running underneath the Windows kernel [@wiki-bromium] [@silicon-bromium]. Microsoft&apos;s own massive investment in Hyper-V for Server 2012 had matured the company&apos;s hypervisor codebase. Intel&apos;s broad consumer-silicon rollout of Extended Page Tables and Second-Level Address Translation made hardware-assisted virtualization the default rather than the exception.&lt;/p&gt;

The structural observation that any defensive mechanism running at the same CPU privilege level as the attacker can be disabled by the attacker. Gates at ring 3 fall to ring 3 code; gates at ring 0 fall to ring 0 code. The only structural escape is to relocate the defender to a privilege level the attacker cannot reach.

gantt
    title Windows defenses 1993-2014 and what disarmed each one
    dateFormat YYYY
    axisFormat %Y
    section Ring 3 gates
    SeDebugPrivilege (NT 1993)     :done, sedebug, 1993, 2011
    Mimikatz weaponization         :crit, mimi, 2011, 2012
    AppContainer (Win 8 2012)      :done, appc, 2012, 2016
    Symbolic link bypass (Forshaw) :crit, fshaw, 2016, 2017
    LSA Protection (RunAsPPL)      :done, ppl, 2013, 2015
    mimidrv.sys PPL bit removal    :crit, mimidrv, 2015, 2016
    section Ring 0 gates
    PatchGuard (Server 2003 SP1)   :done, pg, 2005, 2007
    Skywing PatchGuard bypass      :crit, sky, 2007, 2008
    Driver Signing Enforcement     :done, dse, 2007, 2012
&lt;p&gt;The shared pattern in those tracks is not a series of individual failures. It is one structural failure repeated. Each &quot;broken&quot; line is a same-privilege primitive arriving on schedule and turning off the gate above it.&lt;/p&gt;
&lt;p&gt;If every same-privilege defense fails the same way, what does a defense that does not live at the same privilege level look like?&lt;/p&gt;
&lt;h2&gt;3. Why Every Pre-VBS Credential Fix Failed&lt;/h2&gt;
&lt;p&gt;Picture a penetration tester in early 2015 working on a Windows 8.1 Pro host. The customer has done its homework. LSA Protection is enabled per Microsoft&apos;s guidance: the registry key &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RunAsPPL&lt;/code&gt; is set to &lt;code&gt;1&lt;/code&gt;, so the operating system launches &lt;code&gt;lsass.exe&lt;/code&gt; as a &lt;a href=&quot;https://paragmali.com/blog/protected-process-light-when-the-administrator-isnt-enough/&quot; rel=&quot;noopener&quot;&gt;Protected Process Light&lt;/a&gt; [@ms-lsa-protection]. The tester opens Mimikatz, types &lt;code&gt;privilege::debug&lt;/code&gt;, gets &lt;code&gt;OK&lt;/code&gt;, and runs &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt;. Access denied. The user-mode &lt;code&gt;OpenProcess&lt;/code&gt; call against a PPL target fails for any non-PPL caller, regardless of how much administrator the caller has.&lt;/p&gt;
&lt;p&gt;That looks like a win for the defender. It is not.&lt;/p&gt;
&lt;p&gt;The tester drops to disk the signed Mimikatz driver, &lt;code&gt;mimidrv.sys&lt;/code&gt;. They load it with a single &lt;code&gt;sc create / sc start&lt;/code&gt; pair. From kernel mode, the driver locates the &lt;code&gt;EPROCESS&lt;/code&gt; structure for LSASS and clears the &lt;code&gt;Protection&lt;/code&gt; bits in the &lt;code&gt;_PS_PROTECTION&lt;/code&gt; field. From the same elevated PowerShell, the tester re-runs &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt;. The hashes scroll past.&lt;/p&gt;
&lt;p&gt;The PPL bit was a gate. The gate was at the same ring as the lever that opened the gate. The lever was a signed kernel driver shipped by the same project that shipped the dumper.&lt;/p&gt;
&lt;p&gt;itm4n, who maintains the most-cited reference write-up on RunAsPPL behavior, puts the point in one sentence: &quot;Credential Guard and LSA Protection are actually complementary&quot; [@itm4n-runasppl]. They are complementary because they live at different privilege boundaries. PPL is a same-privilege gate inside VTL0. Credential Guard, as we will see in Section 5, is something structurally different.&lt;/p&gt;

&quot;Credential Guard and LSA Protection are actually complementary.&quot; -- itm4n, &quot;Do You Really Know About LSA Protection (RunAsPPL)?&quot;
&lt;p&gt;Microsoft did not stop at PPL. Between 2013 and 2014 the company shipped three credential-theft mitigations, each genuinely useful, none structurally sufficient.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Defense (year)&lt;/th&gt;
&lt;th&gt;What it stops&lt;/th&gt;
&lt;th&gt;What still works&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Restricted Admin RDP (KB2871997, April 2014)&lt;/td&gt;
&lt;td&gt;RDP no longer pushes plaintext or NTLM credentials to the destination machine&lt;/td&gt;
&lt;td&gt;Lateral movement via pass-the-hash from a locally-captured hash; any local credential extraction on the source machine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protected Users security group (Server 2012 R2, Oct 2013)&lt;/td&gt;
&lt;td&gt;Disables NTLM and CredSSP credential delegation for member accounts; pre-Windows 8.1 cached creds purged&lt;/td&gt;
&lt;td&gt;Plaintext credential capture during interactive sign-in; non-member accounts; pass-the-ticket once a TGT is obtained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSA Protection / RunAsPPL (Win 8.1, Oct 2013) [@ms-lsa-protection]&lt;/td&gt;
&lt;td&gt;User-mode &lt;code&gt;OpenProcess&lt;/code&gt; against &lt;code&gt;lsass.exe&lt;/code&gt; for non-PPL callers fails; conventional Mimikatz from user-land is blocked&lt;/td&gt;
&lt;td&gt;A kernel-mode primitive (&lt;code&gt;mimidrv.sys&lt;/code&gt;, BYOVD, or a vulnerable signed driver) clears the PPL bits from &lt;code&gt;_PS_PROTECTION&lt;/code&gt; and the dump proceeds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Read the right-hand column as a single sentence. &lt;em&gt;Every defense in the left column was bypassed by the same class of move: the attacker reached a privilege at or above the privilege of the gate, and then the gate opened.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That is not a flaw in any one of these features. That is the same-privilege paradox arriving in three different costumes.&lt;/p&gt;
&lt;p&gt;itm4n&apos;s full write-up is worth reading end-to-end if you defend Windows endpoints. The author&apos;s &lt;code&gt;PPLdump&lt;/code&gt; proof-of-concept builds the BYOVD-against-PPL attack as a single tool, and the post is unambiguous that PPL is a &quot;same-privilege gate&quot; while Credential Guard is a &quot;cross-privilege isolation&quot; -- the exact distinction this section turns on.&lt;/p&gt;
&lt;p&gt;The reader who has watched a working defender press-release call any of these features &quot;the answer to Mimikatz&quot; will recognize the move by now. Every fix between 2013 and 2014 was at the attacker&apos;s privilege level. Every fix between 2013 and 2014 fell to a primitive at that privilege level. The pattern is not implementation bug. The pattern is structure.&lt;/p&gt;
&lt;p&gt;If incremental fixes at the attacker&apos;s privilege level cannot work, what does a structural fix look like?&lt;/p&gt;
&lt;h2&gt;4. Three Generations Toward Cross-Privilege Isolation&lt;/h2&gt;
&lt;p&gt;The structural answer arrived in three generations, only one of which worked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation A2 -- the kernel monitors the kernel (2005-2014).&lt;/strong&gt; PatchGuard, KMCS, Driver Signing Enforcement. We have already met this generation. Microsoft did not abandon these defenses; the Windows kernel still bugchecks on PatchGuard violations today. But by 2014 the security research community had collectively documented enough kernel-mode bypasses that nobody serious treated PatchGuard as a primary defense [@ms-patchguard] [@skywing-patchguard]. Its function was to raise the cost of low-skill kernel rootkits, not to stop a SYSTEM-privileged attacker.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation A3 -- the process is sandboxed (2008-2015).&lt;/strong&gt; Internet Explorer&apos;s Protected Mode (2006), Chrome&apos;s renderer sandbox (2008), and Microsoft&apos;s own &lt;a href=&quot;https://paragmali.com/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/&quot; rel=&quot;noopener&quot;&gt;AppContainer model&lt;/a&gt; in Windows 8 (2012) reduced the privilege of risky processes -- the browser tab, the document parser, the network listener -- below that of the parent user [@ms-appcontainer]. The threat model is RCE-in-renderer. The threat model is &lt;em&gt;not&lt;/em&gt; SYSTEM-privilege takeover, because a sandbox does not stop credential theft once an attacker is already inside the user&apos;s session at full privilege. James Forshaw&apos;s August 2016 demonstration of AppContainer escape via shadow object directories closed the chapter [@pz-forshaw-shadow]. Sandboxes remain essential at the edge; they do not solve the post-exploitation problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation A4 -- cross-privilege isolation (2012-2015).&lt;/strong&gt; Bromium&apos;s vSentry, launched commercially in September 2012, was the first product to deliver the idea that mattered: a Type-1 micro-hypervisor running underneath the Windows kernel, with each risky task placed in its own micro-VM [@silicon-bromium] [@wiki-bromium]. The hypervisor sits at a privilege level the guest kernel cannot reach. If the guest kernel falls, the micro-VM is destroyed and the rest of the host is untouched. By 2015, Microsoft had taken the same architectural idea and built it into the operating system. Generation A4 is the only generation in which the defender&apos;s privilege level changes.&lt;/p&gt;

flowchart LR
    A1[Generation A2&lt;br /&gt;2005-2014&lt;br /&gt;Kernel monitors kernel&lt;br /&gt;PatchGuard, KMCS, DSE]
    A2[Generation A3&lt;br /&gt;2008-2015&lt;br /&gt;Process sandbox&lt;br /&gt;AppContainer, Protected Mode]
    A3[Generation A4&lt;br /&gt;2012-2015&lt;br /&gt;Cross-privilege isolation&lt;br /&gt;Bromium uVisor, then VBS]
    A1 --&amp;gt; R1[Outcome&lt;br /&gt;Same ring as attacker&lt;br /&gt;Same-privilege bypass]
    A2 --&amp;gt; R2[Outcome&lt;br /&gt;Below user privilege&lt;br /&gt;Wrong threat model for SYSTEM-takeover]
    A3 --&amp;gt; R3[Outcome&lt;br /&gt;Above guest kernel&lt;br /&gt;Defender unreachable from VTL0]
&lt;p&gt;The structural lesson, said plainly: &lt;em&gt;the only escape from the same-privilege paradox is to move the defender&apos;s privilege level, not to harden the gate.&lt;/em&gt;&lt;/p&gt;

HP Inc. acquired Bromium in September 2019 [@wiki-bromium]. The uVisor concept survived as HP Sure Click, a vertical-market product shipped on HP business notebooks. Bromium&apos;s contribution to the public story of Windows security is that it shipped the cross-privilege-isolation thesis as a working commercial product three years before Microsoft put it in the box. The reader who sees &quot;Bromium&quot; in a vendor presentation now knows the lineage: same idea, narrower market, earlier ship date.
&lt;p&gt;What did Microsoft actually ship?&lt;/p&gt;
&lt;h2&gt;5. The Breakthrough: VBS, the Secure Kernel, and Trustlets&lt;/h2&gt;
&lt;p&gt;On July 29, 2015, Microsoft shipped Windows 10 version 1507, build 10240 [@wiki-win10-versions]. The same release window delivered five components -- Virtualization-Based Security, Credential Guard, Device Guard with Windows Defender Application Control, the Antimalware Scan Interface, and Control Flow Guard. One week later, on August 6, Alex Ionescu walked onto the Black Hat USA stage in Las Vegas and explained the internals in a deck titled &lt;em&gt;Battle of SKM and IUM: How Windows 10 Rewrites OS Architecture&lt;/em&gt; [@ionescu-bh2015].&lt;/p&gt;
&lt;p&gt;That deck is the load-bearing primary for the rest of this section. Where the prose below cites an internal mechanism -- an EKU OID, a process attribute, a syscall ordinal -- it is reading Ionescu first and Microsoft Learn second.&lt;/p&gt;

A Windows security architecture that uses hardware virtualization extensions (Intel VT-x, AMD-V) and Second-Level Address Translation to run two isolated kernel environments on the same physical machine: the conventional NT kernel and a stripped-down Secure Kernel. Microsoft&apos;s official framing is that VBS &quot;creates an isolated virtual environment that becomes the root of trust of the OS that assumes the kernel can be compromised&quot; [@ms-vbs].
&lt;h3&gt;5.1 Hyper-V as the substrate&lt;/h3&gt;
&lt;p&gt;VBS does not invent a new hypervisor. It reuses the &lt;a href=&quot;https://paragmali.com/blog/above-ring-zero-how-the-windows-hypervisor-became-a-security/&quot; rel=&quot;noopener&quot;&gt;Hyper-V hypervisor&lt;/a&gt; Microsoft had already shipped for Server 2008 and matured through Server 2012 [@ms-tlfs-vsm]. On a machine with VBS enabled, the Windows boot path is: UEFI Secure Boot -&amp;gt; Hyper-V hypervisor -&amp;gt; Hyper-V root partition. Inside that root partition, the NT kernel runs in one Virtual Trust Level and the &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel&lt;/a&gt; runs in another.&lt;/p&gt;

A Hyper-V hypervisor abstraction that partitions a single virtual machine into multiple privilege domains. Higher-numbered VTLs are strictly more privileged than lower-numbered ones; lower VTLs cannot read or write higher-VTL memory. The Hyper-V Top-Level Functional Specification reserves up to 16 VTLs, of which only VTL0 (NT kernel) and VTL1 (Secure Kernel) are used in shipped Windows configurations [@ms-tlfs-vsm].
&lt;p&gt;A process running with full SYSTEM privilege in VTL0 sees the conventional NT API surface. It can call &lt;code&gt;NtReadVirtualMemory&lt;/code&gt; on any VTL0 process. It cannot read VTL1 memory at all, because the hypervisor&apos;s Extended Page Tables for VTL1 simply do not map VTL1 pages into the VTL0 address space. The Mimikatz dumper that read &lt;code&gt;lsass.exe&lt;/code&gt; in 2011 is technically still running on the new machine. It is just reading the empty husk of LSASS, because the secret bytes were never copied into VTL0 in the first place.&lt;/p&gt;
&lt;h3&gt;5.2 The Secure Kernel&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;securekernel.exe&lt;/code&gt;, the binary that backs VTL1, is on the order of a few hundred kilobytes. It has no device drivers. It has no graphics stack. Its scheduler is minimal [@ionescu-bh2015]. Its paging is handled by asking the VTL0 NT kernel for help -- the Secure Kernel treats the NT kernel as an untrusted resource manager that may return a page or not, and signs and encrypts anything it sends out to be paged. The smallness is not aesthetic. Smallness is part of the threat model. The Secure Kernel is small so that its attack surface is enumerable, and so that the team responsible for its correctness can review every line.The audited binary size is also why VBS does not run user applications in VTL1. The Secure Kernel hosts only &quot;trustlets&quot; -- a tightly bounded set of Microsoft-signed processes designed to do one cryptographic or measurement task each. Putting your code in VTL1 is not on the application developer&apos;s path; it is a privilege Microsoft grants its own modules.&lt;/p&gt;
&lt;h3&gt;5.3 Isolated User Mode and trustlets&lt;/h3&gt;
&lt;p&gt;Above the Secure Kernel, in user-mode VTL1, runs a stripped-down user-mode environment Microsoft calls Isolated User Mode (IUM). The processes hosted by IUM are called &lt;a href=&quot;https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;trustlets&lt;/a&gt;.&lt;/p&gt;

The VTL1 user-mode environment in which trustlets execute. IUM provides a deliberately reduced syscall surface compared to VTL0 user mode -- Ionescu&apos;s BH 2015 deck enumerates an approximately 48-syscall allow-list, all routed through the Secure Kernel rather than through `ntoskrnl.exe` [@ionescu-bh2015].

A Microsoft-signed process that runs in Isolated User Mode and is protected from VTL0 inspection. A binary becomes a trustlet only by passing five gates at process creation, all enumerated in Ionescu&apos;s Black Hat 2015 deck [@ionescu-bh2015]: (1) a process attribute set on the `NtCreateProcessEx` call, (2) two Enhanced Key Usage OIDs in the Authenticode signature at Signature Level 12 -- the Microsoft Windows System Component Verification EKU `1.3.6.1.4.1.311.10.3.6` and the IUM EKU `1.3.6.1.4.1.311.10.3.37`, (3) a `.tpolicy` PE section, (4) a Trustlet Instance GUID, and (5) loading via the trustlet-specific loader that enforces the syscall allow-list.
&lt;p&gt;The two EKU OIDs are worth memorizing because they are the primary way a defender or auditor can tell, by inspecting a signed binary, whether it is permitted to run as a trustlet at all. Ionescu&apos;s deck flagged a typographic error in one OID on a slide; cross-cite Microsoft documentation for the canonical form. The OIDs above are the canonical form [@ionescu-bh2015].&lt;/p&gt;
&lt;p&gt;The five-gate pattern matters because it explains what an attacker has to do to &lt;em&gt;create&lt;/em&gt; a trustlet, and the answer is: forge a Microsoft signature. The five gates are not security in series; they are security in identity. A binary either has the EKUs Microsoft issues or it does not.&lt;/p&gt;
&lt;h3&gt;5.4 The canonical 1507-era trustlet roster&lt;/h3&gt;
&lt;p&gt;Three trustlets shipped in the first 1507 wave. Ionescu&apos;s deck enumerates their integer IDs [@ionescu-bh2015]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trustlet ID 1 -- LSAISO&lt;/strong&gt; (the Local Security Authority Isolated). The Credential Guard secret-keeper. Holds the NTLM hashes, the Kerberos Ticket Granting Tickets, and any other credentials Credential Guard is protecting.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trustlet ID 2 -- vTPM&lt;/strong&gt;. The virtual Trusted Platform Module used by Hyper-V shielded VMs in the Server 2016 timeframe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trustlet ID 3 -- the Biometrics trustlet&lt;/strong&gt; (Windows Hello). Holds biometric template data; in later Windows 11 documentation the same isolation primitive is marketed as Enhanced Sign-in Security (ESS), but that name is a Windows 11-era rebrand and post-dates the 2015 enumeration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ID 0 in the IUM trustlet table is reserved as a system bootstrap slot per the table&apos;s 1-indexing convention; the publicly available 1507-era material -- Ionescu&apos;s Black Hat USA 2015 deck and the &lt;em&gt;Windows Internals&lt;/em&gt; 7th edition Chapter 7 -- does not separately attest ID 0 as an end-user-deployable trustlet, so it is best read as a system-reserved slot rather than as a named credential-isolation primitive [@ionescu-bh2015] [@mspress-windows-internals-7e].&lt;/p&gt;

The trustlet that backs Credential Guard. The conventional LSASS process continues to run in VTL0 and answers the same API calls it always did, but on a Credential Guard-enabled system the NTLM hash and Kerberos TGT are stored inside LSAISO in VTL1. When LSASS needs to use a credential -- for example, to construct a Kerberos pre-authentication response -- it crosses the secure-call channel to LSAISO, which performs the cryptographic operation inside VTL1 and returns only the derived result. The raw secret never crosses the VTL boundary back into VTL0 [@ms-credential-guard].
&lt;h3&gt;5.5 The secure-call channel&lt;/h3&gt;
&lt;p&gt;VTL0 and VTL1 talk via a small set of secure-call ordinals. The canonical primitive Ionescu names is &lt;code&gt;IumSetTrustletInstance&lt;/code&gt; at ordinal &lt;code&gt;0x80000001&lt;/code&gt;, paired with a handful of agent-trustlet RPC patterns [@ionescu-bh2015]. The semantic invariant is the same on every call: VTL0 sends a request, VTL1 performs work on protected data, VTL1 returns either a result the requester is permitted to see or a failure. The secret never leaves VTL1.&lt;/p&gt;

flowchart TB
    HW[Hardware&lt;br /&gt;CPU with VT-x/AMD-V&lt;br /&gt;SLAT, IOMMU, TPM 2.0]
    UEFI[UEFI Secure Boot]
    HV[Hyper-V hypervisor]
    HW --&amp;gt; UEFI --&amp;gt; HV
    subgraph VTL0[VTL0 -- NT environment]
        NTK[NT kernel&lt;br /&gt;ntoskrnl.exe, drivers]
        UMP[User-mode processes&lt;br /&gt;LSASS, services, apps]
        NTK --- UMP
    end
    subgraph VTL1[VTL1 -- Secure environment]
        SK[Secure Kernel&lt;br /&gt;securekernel.exe]
        IUM[Isolated User Mode&lt;br /&gt;trustlets: LSAISO, vTPM, ESS]
        SK --- IUM
    end
    HV --&amp;gt; VTL0
    HV --&amp;gt; VTL1
    VTL0 -.secure-call channel.-&amp;gt; VTL1
    ATK[Attacker reach&lt;br /&gt;caps at VTL0 SYSTEM] -.-&amp;gt; NTK
&lt;p&gt;The diagram is worth reading twice. The attacker&apos;s reachable privilege ceiling is the dashed line into VTL0. Everything above the secure-call channel is, by hardware-enforced page-table convention, unreachable from below.&lt;/p&gt;

sequenceDiagram
    participant App as Caller
    participant NT as NT kernel
    participant Loader as Trustlet loader
    participant SK as Secure Kernel
    App-&amp;gt;&amp;gt;NT: NtCreateProcessEx with trustlet process attribute
    NT-&amp;gt;&amp;gt;Loader: Validate Authenticode signature
    Loader-&amp;gt;&amp;gt;Loader: Check EKU 1.3.6.1.4.1.311.10.3.6
    Loader-&amp;gt;&amp;gt;Loader: Check EKU 1.3.6.1.4.1.311.10.3.37
    Loader-&amp;gt;&amp;gt;Loader: Parse .tpolicy PE section
    Loader-&amp;gt;&amp;gt;SK: Assign Trustlet Instance GUID
    SK-&amp;gt;&amp;gt;SK: Install reduced syscall allow-list
    SK--&amp;gt;&amp;gt;App: Trustlet process handle
&lt;h3&gt;5.6 The conceptual hinge&lt;/h3&gt;
&lt;p&gt;Stop here and reread the architecture. The NT kernel is still compromisable. A driver bug, a BYOVD attack, a kernel race condition -- all of those still pop SYSTEM in VTL0 the same way they did in 2014. VBS does not pretend otherwise. The Microsoft Learn VBS landing page is explicit that VBS &quot;assumes the kernel can be compromised&quot; [@ms-vbs]. The defensive invariant has nothing to do with keeping attackers out of the NT kernel. The defensive invariant is that the secrets they came for are not in the NT kernel.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; VBS does not protect the NT kernel from compromise. It guarantees that even a fully-compromised NT kernel cannot reach the secrets held in VTL1 trustlets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sentence is the entire defensive thesis of Windows 10. Once a reader has it, every component shipped between 1507 and 1909 -- Credential Guard, HVCI, AMSI, CFG, Process Mitigation Policies -- reads as a follow-on instance of the same trust-topology move, modulated by what is hardware-rooted versus software-instrumented.&lt;/p&gt;
&lt;p&gt;LSAISO holds the NTLM hash and the Kerberos TGT. That handles credential theft. What about the rest of the attack surface?&lt;/p&gt;
&lt;h2&gt;6. The 2019 Defensive Stack&lt;/h2&gt;
&lt;p&gt;By Windows 10 version 1909, shipped November 12, 2019 [@ms-release-info] [@wiki-win10-versions], the VBS architecture had grown a six-feature shipping stack -- Credential Guard, HVCI, WDAC, AMSI, CFG, and Process Mitigation Policies -- plus a cloud-backed endpoint detection and response backend in Defender Advanced Threat Protection. Each closes a specific attack class. Each has a deliberate, named bypass surface. The mature defender&apos;s question by the end of 2019 was no longer &quot;is it deployed&quot; but &quot;which class is left.&quot;&lt;/p&gt;
&lt;h3&gt;6.1 Credential Guard&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s documentation describes &lt;a href=&quot;https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/&quot; rel=&quot;noopener&quot;&gt;Credential Guard&apos;s scope&lt;/a&gt; precisely: it &quot;prevents credential theft attacks by protecting NTLM password hashes, Kerberos Ticket Granting Tickets (TGTs), and credentials stored by applications as domain credentials&quot; [@ms-credential-guard]. Mechanism: LSA in VTL0 retains the API surface; the secret bytes relocate to LSAISO in VTL1; the secure-call dispatch performs the cryptographic step and returns derived output. The Mimikatz LSASS-scrape family -- &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt;, &lt;code&gt;sekurlsa::tickets&lt;/code&gt;, &lt;code&gt;lsadump::secrets&lt;/code&gt; -- returns empty fields on a Credential Guard-enabled system because the bytes it scans for are no longer in the address space it can read.&lt;/p&gt;
&lt;p&gt;What Credential Guard does &lt;em&gt;not&lt;/em&gt; stop is worth naming, because the apologist failure mode is to claim it stops everything. It does not stop pass-the-ticket replay of a TGT captured before Credential Guard was enabled. It does not stop sign-in-time keylogging that scrapes the plaintext password as the user types it. It does not stop a stolen-DC-krbtgt attack that forges Golden Tickets offline. And it does not retroactively scrub credentials presented over RDP outside Restricted Admin mode. Each of those is a meaningful threat. Each lives in a class Credential Guard was not engineered to address.&lt;/p&gt;

sequenceDiagram
    participant App as Application
    participant LSA as LSA (VTL0)
    participant SCD as Secure-call dispatch
    participant ISO as LSAISO (VTL1)
    App-&amp;gt;&amp;gt;LSA: LsaCallAuthenticationPackage
    LSA-&amp;gt;&amp;gt;SCD: secure-call with TGT request
    SCD-&amp;gt;&amp;gt;ISO: forwarded across VTL boundary
    ISO-&amp;gt;&amp;gt;ISO: derive Kerberos session key with stored TGT
    ISO--&amp;gt;&amp;gt;SCD: derived session key (raw TGT stays in VTL1)
    SCD--&amp;gt;&amp;gt;LSA: derived result
    LSA--&amp;gt;&amp;gt;App: success
&lt;h3&gt;6.2 HVCI&lt;/h3&gt;

A Windows VBS feature, also marketed as Memory Integrity, that uses the Hyper-V hypervisor to enforce write-XOR-execute on VTL0 kernel pages via Extended Page Tables. Microsoft&apos;s documentation calls HVCI a &quot;critical component that protects and hardens Windows by running kernel mode code integrity within the isolated virtual environment of VBS&quot; [@ms-hvci]. The practical effect is that the classical kernel code-injection attack class -- write shellcode into a kernel page, then execute -- is closed.
&lt;p&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; shipped first in Windows 10 1507 in limited form, and rolled out broadly with the 1607 Anniversary Update. Its enforcement is hardware-accelerated by Intel&apos;s Mode-Based Execute Control or AMD&apos;s equivalent Guest Mode Execute Trap [@ms-hvci]. On supported silicon, the kernel-page W^X check happens in EPT permission bits with no measurable per-page-fault overhead. The attack class HVCI does not close is not &quot;rootkit&quot;; the attack class HVCI does close is &quot;kernel code injection&quot;. An attacker can still call existing kernel functions in unintended sequences -- the data-only kernel attack -- and that is a known and acknowledged residual.&lt;/p&gt;
&lt;h3&gt;6.3 WDAC&lt;/h3&gt;
&lt;p&gt;Windows Defender Application Control, the rebranded successor to Device Guard&apos;s code-integrity component, enforces kernel-mode and user-mode code-integrity policy authored in XML and compiled to a binary &lt;code&gt;.cip&lt;/code&gt; file [@ms-wdac]. The policy is consulted at every image load by &lt;code&gt;CI.dll&lt;/code&gt;. Signed-policy mode binds the policy to a signing key and rejects updates that are not co-signed by the same key, which is the canonical answer to the &quot;attacker rewrites the policy file from SYSTEM&quot; objection.&lt;/p&gt;
&lt;p&gt;WDAC&apos;s known weaknesses are not architectural. They are XML-authoring complexity (production policies routinely run to thousands of rules), bring-your-own-vulnerable-driver against permissive driver allow-lists, and abuse of legitimately-signed Living-Off-the-Land binaries -- &lt;code&gt;rundll32.exe&lt;/code&gt;, &lt;code&gt;regsvr32.exe&lt;/code&gt;, &lt;code&gt;msbuild.exe&lt;/code&gt; -- that pass any signature-based allow-list because Microsoft signed them itself. AppLocker, the older peer technology that ships in Pro SKUs, is functionally subsumed; new deployments default to WDAC [@ms-wdac].&lt;/p&gt;
&lt;h3&gt;6.4 AMSI&lt;/h3&gt;
&lt;p&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; is a Component Object Model interface that lets script-host runtimes -- PowerShell, Windows Script Host (JScript and VBScript), Office VBA, and WMI -- hand a freshly-deobfuscated string buffer to the configured anti-malware provider before executing it [@ms-amsi].&lt;/p&gt;

A user-mode COM interface introduced in Windows 10 1507 that allows scripting and macro hosts to submit a buffer (typically a deobfuscated script body) to the configured anti-malware provider for inspection before execution. Lee Holmes&apos;s June 9, 2015 Microsoft Security Blog post announced AMSI alongside the Windows 10 1507 ship [@ms-leeholmes-amsi]. Microsoft Defender is the default provider; third-party engines register via `IAntimalwareProvider`.
&lt;p&gt;AMSI matters because pre-AMSI, an obfuscated PowerShell command line was opaque to the anti-malware engine until after it had run. AMSI runs the engine on the post-deobfuscation buffer. The engine sees the cleartext.&lt;/p&gt;
&lt;p&gt;The bypass class AMSI exposes is a deliberate tradeoff. AMSI is a hook from user-mode script hosts. An attacker who already has code execution in the same user-mode process can patch the AMSI hook out -- the canonical reflection trick sets &lt;code&gt;AmsiUtils.amsiInitFailed&lt;/code&gt; to &lt;code&gt;True&lt;/code&gt; via .NET reflection, and MDSec&apos;s June 2018 PowerShell AMSI evasion write-up walks through the family in detail [@mdsec-amsi-bypass]. AMSI is a hook, not a sandbox. The bypass surface is part of the design tradeoff.&lt;/p&gt;

AMSI did not ship as a single event. Windows 10 1507 (July 2015) brought PowerShell 5.0, Windows Script Host, and Office VBA macro coverage. Office 365 client applications integrated AMSI for Office VBA macros in September 2018 per Microsoft&apos;s announcement [@ms-office-amsi]. The Windows 10 1903 release in May 2019 added the AMSI-for-WMI provider [@ms-win10-1903]. The same product name covered four very different runtimes, and the runtime that was missing from your endpoint was the runtime an attacker used. Treat &quot;AMSI is enabled&quot; as a question with four sub-questions until 1903.
&lt;h3&gt;6.5 Control Flow Guard&lt;/h3&gt;
&lt;p&gt;Burow, Carr, Nash, Larsen, Brunthaler, Payer, and Franz&apos;s 2017 ACM Computing Surveys review &lt;em&gt;Control-Flow Integrity: Precision, Security, and Performance&lt;/em&gt; is the academic reference that classifies what &lt;a href=&quot;https://paragmali.com/blog/control-flow-integrity-on-windows-cfg-xfg-and-the-cet-shadow/&quot; rel=&quot;noopener&quot;&gt;CFG&lt;/a&gt; actually is [@burow-cfi-csur2017]. In the Burow et al. taxonomy, CFG is forward-edge, coarse-grained, software CFI.&lt;/p&gt;

A platform security feature that &quot;was created to combat memory corruption vulnerabilities&quot; by validating indirect call targets against a compile-time-known set of valid functions [@ms-cfg]. The compiler emits a call to `__guard_check_icall_fptr` before every indirect call; the runtime consults an OS-maintained bitmap of valid call targets in the loaded process image; an invalid target traps to the kernel and the process is terminated.
&lt;p&gt;The mechanism is small enough to describe in code. The OS maintains a per-process bitmap indexed by 16-byte-aligned function addresses; each bit indicates whether that address is a valid indirect-call target. Before every indirect call, the compiler emits a bitmap lookup. If the bit is clear, the program is terminated.&lt;/p&gt;
&lt;p&gt;{`
// Simulated CFG bitmap and indirect-call check
const bitmap = new Uint8Array(1024);&lt;/p&gt;
&lt;p&gt;function markValidTarget(addr) {
  // Each bit covers a 16-byte-aligned function address
  const bitIndex = (addr &amp;gt;&amp;gt; 4);
  bitmap[bitIndex &amp;gt;&amp;gt; 3] |= (1 &amp;lt;&amp;lt; (bitIndex &amp;amp; 7));
}&lt;/p&gt;
&lt;p&gt;function guardCheckIcall(targetAddr) {
  const bitIndex = (targetAddr &amp;gt;&amp;gt; 4);
  const isValid = (bitmap[bitIndex &amp;gt;&amp;gt; 3] &amp;gt;&amp;gt; (bitIndex &amp;amp; 7)) &amp;amp; 1;
  if (!isValid) {
    throw new Error(&apos;CFG violation: terminate process&apos;);
  }
}&lt;/p&gt;
&lt;p&gt;markValidTarget(0x1400);
markValidTarget(0x1500);&lt;/p&gt;
&lt;p&gt;guardCheckIcall(0x1400);
console.log(&apos;Valid call site allowed.&apos;);&lt;/p&gt;
&lt;p&gt;try {
  guardCheckIcall(0x1410);
} catch (e) {
  console.log(e.message);
}
`}&lt;/p&gt;
&lt;p&gt;The known limits of CFG are the limits Burow et al. enumerate for forward-edge, coarse-grained, software CFI in general [@burow-cfi-csur2017]. CFG protects only forward edges -- indirect calls and indirect jumps -- so an attacker who corrupts a return address is unaffected by CFG and needs a backward-edge defense (Intel Control-flow Enforcement Technology shadow stacks, in the Part 5 story). CFG&apos;s bitmap is coarse: any function whose address is taken is a valid target. And non-CFG-instrumented DLLs in the process create gaps; the bitmap has no bit set for code the compiler did not see.&lt;/p&gt;
&lt;h3&gt;6.6 Process Mitigation Policies&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/process-mitigation-policies-cfg-acg-cig-and-the-layer-betwee/&quot; rel=&quot;noopener&quot;&gt;Per-app process mitigation policies&lt;/a&gt;, exposed in 1709 (October 2017) through the Windows Defender Exploit Guard GUI and the PowerShell &lt;code&gt;Set-ProcessMitigation&lt;/code&gt; cmdlet [@ms-exploit-protection] [@ms-set-processmitigation], unified the menagerie of legacy Enhanced Mitigation Experience Toolkit settings into a documented, group-policy-deployable per-process opt-in. The kernel-side &lt;code&gt;PROCESS_MITIGATION_POLICY_INFORMATION&lt;/code&gt; API shipped in Windows 8; the per-app management surface arrived three years later. Each policy in the 1709 set closes a specific exploitation primitive at the per-process boundary. The ones worth knowing by mechanism:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arbitrary Code Guard (ACG).&lt;/strong&gt; ACG refuses to commit a page as &lt;code&gt;PAGE_EXECUTE_READWRITE&lt;/code&gt; and refuses any &lt;code&gt;VirtualProtect&lt;/code&gt; request that adds executable permission to a page that was previously non-executable. The kernel&apos;s &lt;code&gt;MiArbitraryUserPointer&lt;/code&gt; and &lt;code&gt;MiAllocateVirtualMemory&lt;/code&gt; paths fail those requests with &lt;code&gt;STATUS_DYNAMIC_CODE_BLOCKED&lt;/code&gt;. The effect is process-level W^X: an attacker who lands a write primitive cannot turn it into a JIT-the-shellcode-then-execute primitive. The Microsoft Edge content process is the canonical example. Edge&apos;s JavaScript JIT runs &lt;em&gt;out-of-process&lt;/em&gt; in a separate JIT-only process and ships compiled code to the renderer through a one-way shared-memory channel, so the renderer itself never needs an RWX page. The flag name is &lt;code&gt;PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON&lt;/code&gt; [@ms-set-processmitigation].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code Integrity Guard (CIG).&lt;/strong&gt; CIG refuses to load any DLL whose Authenticode signature does not chain to a Microsoft trust root. The PE load path in &lt;code&gt;MiLoadImage&lt;/code&gt; validates the signature and fails with &lt;code&gt;STATUS_INVALID_IMAGE_HASH&lt;/code&gt; or &lt;code&gt;STATUS_INVALID_SIGNATURE&lt;/code&gt; if the policy is violated. This closes the &quot;drop a malicious DLL in the search path and let &lt;code&gt;LoadLibrary&lt;/code&gt; find it&quot; exploitation class for a content process. The flag is &lt;code&gt;PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON&lt;/code&gt;. CIG composes with WDAC at the system level: CIG is the per-process narrow case, WDAC is the system policy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strict Handle Check.&lt;/strong&gt; Strict Handle Check terminates the process on the first invalid handle reference rather than returning &lt;code&gt;STATUS_INVALID_HANDLE&lt;/code&gt; and recovering. Closes handle-reuse and type-confusion exploitation where the attacker substitutes a handle of a different type and rides the resulting use-after-free, which is a recurring browser-sandbox bug pattern. The flag is &lt;code&gt;PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image Load mitigations.&lt;/strong&gt; Three related policies harden the DLL loader. &lt;code&gt;PreferSystem32Images&lt;/code&gt; makes the loader prefer &lt;code&gt;\Windows\System32&lt;/code&gt; before searching the application directory, defeating the classic DLL search-order hijack (a malicious &lt;code&gt;version.dll&lt;/code&gt; planted in the app directory). &lt;code&gt;NoLowMandatoryLabelImages&lt;/code&gt; refuses to load DLLs whose mandatory integrity label is Low, closing the &quot;browser sandbox creates a Low-IL file, then the parent process loads it&quot; class. &lt;code&gt;NoRemoteImages&lt;/code&gt; refuses to load DLLs from UNC paths, defeating cross-machine DLL injection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disable Win32k System Calls.&lt;/strong&gt; Any syscall whose service-table index is in the Win32k range -- the second syscall service table -- is rejected at the entry-stub level. The mitigation removes the GDI and USER attack surface from the process. The Win32k subsystem has historically been the largest source of kernel CVEs, so processes that do not need a window station -- content processes, network services -- can opt out wholesale. The flag is &lt;code&gt;PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON&lt;/code&gt;. Edge content processes ship with it on. Chromium&apos;s &lt;code&gt;--disable-win32k-lockdown&lt;/code&gt; flag is the dual-use override developers reach for when something downstream breaks.&lt;/p&gt;
&lt;p&gt;The 1709 set also keeps the conventional triad -- ASLR with bottom-up randomization, Data Execution Prevention, and a NoCFG-allowed-RWX refusal -- applied per-process.&lt;/p&gt;
&lt;p&gt;The Edge content process is the canonical &quot;stack of mitigations&quot; example. It enables almost the full PMP suite simultaneously: ACG, CIG, Disable Win32k, the Image Load mitigations, Strict Handle Check, AppContainer, and an AC sandbox. That stack is what makes an Edge content-process RCE &lt;em&gt;not&lt;/em&gt; equivalent to a SYSTEM-level Windows compromise. The attacker has compromised the renderer, but still faces a sandbox escape, then an elevation of privilege, then (depending on the target) a credential-extraction step before reaching anything Credential Guard then closes.&lt;/p&gt;
&lt;h3&gt;6.7 Defender ATP, later Defender for Endpoint&lt;/h3&gt;
&lt;p&gt;The cloud-backed endpoint detection and response backend launched as Windows Defender Advanced Threat Protection in 2016 and was renamed &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;Microsoft Defender for Endpoint&lt;/a&gt; in September 2020 [@ms-mde-overview].&lt;/p&gt;
&lt;p&gt;&quot;Defender ATP&quot; and &quot;Defender for Endpoint&quot; are the same product. The 2020 rename matters only for citation literacy: pre-2020 sources cite ATP, post-2020 sources cite MDE, and confusing the two as separate products is a common reading error.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What MDE actually sees.&lt;/strong&gt; The sensor consumes a curated set of Event Tracing for Windows providers and file-system and registry events: &lt;code&gt;Microsoft-Windows-Kernel-Process&lt;/code&gt; for process create and exit; &lt;code&gt;Microsoft-Windows-Kernel-Image&lt;/code&gt; for image load; the file-system minifilter for create, write, and delete; the registry transaction log for create and write; &lt;code&gt;Microsoft-Windows-Kernel-Network&lt;/code&gt; for network connections; the LSA and Kerberos authentication providers for authentication events; the AMSI script-content stream for post-deobfuscation script bodies; the Defender behavioral-engine fire events; and the per-process Code Integrity event stream that surfaces HVCI violations. That last stream is the SOC&apos;s anchor for HVCI-violation telemetry and is the one piece of integration no third-party EDR can replicate, because it depends on running inside the VBS substrate Microsoft also ships.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Detection latency tiering.&lt;/strong&gt; The cloud-correlation pipeline operates in two tiers. Single-event high-confidence detections -- a known-malicious hash, an AMSI Mimikatz string match, a Cobalt Strike named-pipe pattern -- fire in seconds to low minutes. Behavioral aggregation across a process tree -- Ryuk-style staging behavior, Big Game Hunting lateral-movement patterns, Emotet-to-TrickBot-to-Ryuk chains -- fires in minutes to low hours. The two-tier architecture is the detection-philosophy distinction MDE held against its 2019 EDR competitors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The 2019 EDR competitor field.&lt;/strong&gt; Four credible competitors shipped comparable cloud-correlation architectures by the 2019 cutline. CrowdStrike Falcon was the cloud-native sensor with the heaviest cloud-side intelligence pipeline of the era; CrowdStrike Inc. was founded in 2011 with the cloud-native vision, and the Threat Graph correlation platform debuted with Falcon in June 2013 and has expanded continuously since. Carbon Black carried the legacy Bit9 application-allow-list lineage with a behavioral hybrid layered on top, and was acquired by VMware in October 2019. SentinelOne shipped a lighter kernel agent with on-endpoint behavioral analytics, founded in 2013. Cylance staked out the divergent philosophical position of pre-LLM-era machine-learning static analysis with no behavioral pipeline at all, and was acquired by BlackBerry in February 2019.&lt;/p&gt;
&lt;p&gt;All four offered cloud-correlation EDR by the 2019 cutline. MDE&apos;s distinguishing feature was OS-native integration with Defender, the ETW providers, and the VBS substrate -- specifically, the per-process Code Integrity event stream the third-party agents could not see.&lt;/p&gt;
&lt;p&gt;Together, the six VBS-anchored pillars plus Defender for Endpoint constitute what a 2019 defender meant by &quot;the modern Windows endpoint.&quot; A reasonable summary is the head-to-head table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;Privilege model&lt;/th&gt;
&lt;th&gt;Closes&lt;/th&gt;
&lt;th&gt;Known residual&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Credential Guard&lt;/td&gt;
&lt;td&gt;Cross-VTL isolation&lt;/td&gt;
&lt;td&gt;Mimikatz LSASS-scrape family&lt;/td&gt;
&lt;td&gt;Pre-CG TGTs, sign-in keyloggers, stolen-DC krbtgt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HVCI&lt;/td&gt;
&lt;td&gt;Cross-VTL kernel W^X&lt;/td&gt;
&lt;td&gt;Classical kernel code injection&lt;/td&gt;
&lt;td&gt;BYOVD, data-only kernel attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WDAC&lt;/td&gt;
&lt;td&gt;Kernel-enforced CI policy&lt;/td&gt;
&lt;td&gt;Unsigned and unauthorized code&lt;/td&gt;
&lt;td&gt;LOLBins, BYOVD against permissive policies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMSI&lt;/td&gt;
&lt;td&gt;User-mode COM hook&lt;/td&gt;
&lt;td&gt;Post-deobfuscation script visibility&lt;/td&gt;
&lt;td&gt;In-process hook patches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CFG&lt;/td&gt;
&lt;td&gt;Compiler-inserted forward-edge CFI&lt;/td&gt;
&lt;td&gt;ROP gadget chains via indirect call&lt;/td&gt;
&lt;td&gt;Return-address corruption, non-CFG DLLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process Mitigation Policies&lt;/td&gt;
&lt;td&gt;Per-app opt-in mitigations&lt;/td&gt;
&lt;td&gt;Per-process exploit primitives&lt;/td&gt;
&lt;td&gt;Apps that do not opt in&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Windows kernel performance impact of KVA Shadow on older silicon will preview in Section 10 -- MariaDB&apos;s MyISAM workload regressed 37 to 40 percent on Haswell-era CPUs when the Meltdown mitigations landed [@mariadb-kpti]. That is the empirical anchor for &quot;more significant slowdowns&quot; in Terry Myerson&apos;s January 2018 tiered guidance [@ms-myerson-meltdown].&lt;/p&gt;
&lt;p&gt;This is the stack Microsoft shipped. In the same five years, three other OS communities -- Linux, Apple, and ChromeOS -- shipped their own answers to overlapping problems, and the formal-verification community produced a fourth. How do those four answers compare?&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches: Linux KPTI, Apple T2, ChromeOS, seL4&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s VBS is one of four serious architectural answers shipped in the 2015-2019 window. The others made different bets. Reading them side by side is the fastest way to see what VBS chose and what it gave up.&lt;/p&gt;
&lt;h3&gt;7.1 Linux KPTI vs Windows KVA Shadow&lt;/h3&gt;
&lt;p&gt;Linux Kernel Page-Table Isolation (KPTI) and Microsoft&apos;s KVA Shadow are parallel responses to the same forced architectural change. Both descend from Gruss et al.&apos;s 2017 ESORICS paper &quot;KASLR is Dead: Long Live KASLR,&quot; which introduced KAISER -- the technique of stripping kernel mappings out of the user-mode page-table view to defeat side-channel attacks on Kernel Address Space Layout Randomization [@gruss-kaiser]. KAISER landed before Meltdown was public. When the Project Zero coordinated disclosure broke on January 3, 2018, it was the structural retrofit both kernels needed [@pz-meltdown-spectre].&lt;/p&gt;
&lt;p&gt;Linux merged KPTI into mainline before the 4.15 release in January 2018, with backports into 4.14, 4.9, and 4.4 LTS branches gated by &lt;code&gt;CONFIG_PAGE_TABLE_ISOLATION&lt;/code&gt; [@lwn-kpti] [@kroah-meltdown]. Microsoft shipped KVA Shadow in the January 9, 2018 cumulative update. Both implementations split the per-process page-table into a user-mode shadow and a full kernel-mode view, swap CR3 at every user-kernel transition, and lean on the Process Context Identifier feature in Skylake-and-later silicon to amortize the TLB-flush penalty. The fact that two OSes with very different histories converged on functionally identical code, within days of each other, is the lesson: the x86 page-table format dictated the answer. Neither team designed the mechanism. The hardware bug did.&lt;/p&gt;
&lt;h3&gt;7.2 Apple T2: a second processor instead of a second privilege level&lt;/h3&gt;
&lt;p&gt;Apple shipped the &lt;a href=&quot;https://paragmali.com/blog/apple-secure-enclave-vs-microsoft-pluton-two-roads-to-hardwa/&quot; rel=&quot;noopener&quot;&gt;T2 chip&lt;/a&gt; in the iMac Pro on December 14, 2017, and rolled it across the Mac line through 2018 [@apple-t2]. The T2 is a separate Arm-based co-processor with its own boot ROM, AES engine, Secure Enclave, and Memory Protection Engine that encrypts the enclave&apos;s DRAM region with an ephemeral key [@apple-secure-enclave]. Where Microsoft answered the same-privilege paradox by adding a second privilege level on the same CPU, Apple answered it by adding a second physical CPU.&lt;/p&gt;
&lt;p&gt;The tradeoff is stark. T2 has no cross-VTL Spectre v2 problem because the secret lives on a different silicon die. T2 also costs an extra SoC in every machine&apos;s bill of materials, requires a second firmware-update pipeline, and demanded hardware replacements when the checkm8 bootrom vulnerability hit the T2&apos;s A10-derived bootrom in 2020 [@ironpeak-t2].The T2&apos;s predecessor in the 2016 Touch Bar MacBook Pro, the T1, was S2-based; the T2 itself derives from the A10 Fusion CPU found in the iPhone 7, per ironpeak&apos;s October 2020 analysis. VBS runs on existing Intel and AMD silicon with no incremental hardware cost; T2 requires Apple to ship custom silicon in every box. Both architectures relocate the secret. They relocate it to different places.&lt;/p&gt;
&lt;h3&gt;7.3 ChromeOS: do not ship a Secure Kernel because you do not ship a general-purpose kernel&lt;/h3&gt;
&lt;p&gt;ChromeOS does not deploy a Secure Kernel. It deploys verified boot. The architecture is: firmware-write-protected hardware root, signed kernel partition with the dm-verity root hash baked in, and a read-only root filesystem mounted with dm-verity active so every block read is checked against a signed Merkle tree at runtime [@chromeos-verified-boot] [@dm-verity]. The user-facing surface is the Chrome browser, with per-site renderers and utility processes confined by seccomp-bpf sandboxes. There is no LSASS to scrape, no Active Directory TGT to steal, no general-purpose third-party kernel-driver supply to attack.&lt;/p&gt;
&lt;p&gt;The architectural lesson is that VBS solves the problem of &quot;we shipped a large general-purpose kernel and we cannot retract that decision.&quot; ChromeOS sidesteps the problem by not shipping that kernel in the first place. ChromeOS is the principled alternative for an OS whose threat model assumes a single-application workload.&lt;/p&gt;
&lt;h3&gt;7.4 seL4: the verification path VBS chose not to take&lt;/h3&gt;
&lt;p&gt;seL4 is approximately 8,700 lines of C plus 600 lines of assembly, machine-checked against an Isabelle/HOL abstract specification with roughly 200,000 lines of proof script, and verified end-to-end from spec to C to binary [@klein-sel4-sosp2009] [@klein-sel4-cacm] [@sewell-sel4-pldi]. The 2009 SOSP paper established the proof chain, the 2010 CACM Research Highlight recapped it for a wider audience, and the 2013 PLDI follow-on closed the compiler gap by translation-validating GCC output against the C source. The total effort: on the order of 20 person-years for a microkernel one-tenth the size of &lt;code&gt;securekernel.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s Secure Kernel is roughly 150 kilobytes of unverified C code [@ionescu-bh2015]. A meaningful verification would require an Isabelle-level specification of the secure-call interface, refinement proofs through the C source, translation validation to the shipped binary, a formal model of Hyper-V&apos;s SLAT enforcement, and a credible story for microarchitectural side channels that seL4 in 2009 did not have to address. A plausible order-of-magnitude estimate is 100 to 200 person-years for the structural pieces alone. No shipping general-purpose OS -- macOS, iOS, ChromeOS, or Windows -- has chosen that path. seL4 itself runs in specialized embedded and defense deployments, not on desktops.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Trust root&lt;/th&gt;
&lt;th&gt;Verification&lt;/th&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Open residuals&lt;/th&gt;
&lt;th&gt;Deployment scale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Windows VBS (2015)&lt;/td&gt;
&lt;td&gt;Hyper-V hypervisor + UEFI Secure Boot&lt;/td&gt;
&lt;td&gt;None (unverified C)&lt;/td&gt;
&lt;td&gt;Ships on existing silicon at Windows scale&lt;/td&gt;
&lt;td&gt;BYOVD, secure-call bugs, cross-VTL side channels&lt;/td&gt;
&lt;td&gt;Hundreds of millions of endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux KPTI (2018)&lt;/td&gt;
&lt;td&gt;Page-table split per process&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Forced retrofit; correct in mainline within weeks&lt;/td&gt;
&lt;td&gt;Spectre family beyond v3&lt;/td&gt;
&lt;td&gt;Server-side and developer workstation majority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple T2 (2017)&lt;/td&gt;
&lt;td&gt;Second physical processor&lt;/td&gt;
&lt;td&gt;None (different threat model)&lt;/td&gt;
&lt;td&gt;No cross-VTL side-channel surface&lt;/td&gt;
&lt;td&gt;Firmware bugs require hardware fix&lt;/td&gt;
&lt;td&gt;All Intel Macs 2018-2022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;seL4 (2009)&lt;/td&gt;
&lt;td&gt;Microkernel + Isabelle/HOL proof chain&lt;/td&gt;
&lt;td&gt;Functional correctness, integrity, non-interference&lt;/td&gt;
&lt;td&gt;Formally guaranteed against named bug classes&lt;/td&gt;
&lt;td&gt;Outside-TCB hardware and side channels&lt;/td&gt;
&lt;td&gt;Specialized embedded / defense&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Each of these four answers makes a different tradeoff against the same problem. Windows chose &quot;second privilege level, large attack surface, ship-at-scale.&quot; What does that tradeoff leave on the table -- where are VBS&apos;s irreducible residuals?&lt;/p&gt;
&lt;h2&gt;8. What VBS Cannot Defend Against&lt;/h2&gt;
&lt;p&gt;Every architecturally honest defense names its bypass classes before its critics do. VBS, at the 2019 cutline, has six enumerable bypasses plus one structural caveat about availability. None of them undermines the architectural claim that the LSASS-scrape attack class is closed. All of them shape the operator&apos;s deployment decisions.&lt;/p&gt;

An attack class in which an adversary loads a legitimately Microsoft-co-signed third-party kernel driver that contains an exploitable bug. The driver passes Driver Signing Enforcement and HVCI&apos;s code-integrity check because it is signed; the bug gives the attacker arbitrary kernel-mode primitives (read, write, execute) without requiring a Microsoft-issued signature. BYOVD is the dominant in-the-wild HVCI and Credential Guard bypass class through the 2019 cutline.
&lt;p&gt;&lt;strong&gt;Bypass class one -- BYOVD.&lt;/strong&gt; A vulnerable signed driver provides the same kernel-mode primitives PatchGuard-era rootkits relied on. With kernel-mode arbitrary write, an attacker can disable HVCI on a per-process basis, clear the PPL bits on a target, or hook secure-call dispatch sites. Microsoft formally acknowledged BYOVD as a class with the October 2022 Vulnerable Driver Blocklist update KB5020779 [@ms-vuln-driver-kb], operationalized through the same &lt;code&gt;microsoft-recommended-driver-block-rules&lt;/code&gt; document used by Windows Defender Application Control [@ms-vuln-driver-blockrules]. That arrived three years after the cutline of this article, which is part of the lesson: the dominant residual at 2019 was not closed by Windows 10 itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bypass class two -- hypervisor and secure-kernel vulnerabilities.&lt;/strong&gt; The Secure Kernel is not infallible code. Saar Amar and Daniel King&apos;s Black Hat USA 2020 talk &quot;Breaking VSM by Attacking SecureKernel&quot; disclosed CVE-2020-0917 and CVE-2020-0918 in the secure-call interface handlers &lt;code&gt;SkmmUnmapMdl&lt;/code&gt; and &lt;code&gt;SkmiReleaseUnknownPTEs&lt;/code&gt; [@amar-king-bh2020]. The Amar-King work landed after this article&apos;s window, but the bypass-class anchor it establishes -- VTL0 to VTL1 escape via the secure-call interface -- was already known to insiders by 2019. The steady-state finding rate for that class is on the order of one to three critical bugs per year.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bypass class three -- hardware and DMA attacks.&lt;/strong&gt; A peripheral device attached over Thunderbolt or PCIe can, in the absence of an Input-Output Memory Management Unit enforcement, read and write physical memory directly. The 2019 NDSS paper &quot;Thunderclap&quot; demonstrated DMA reads of VTL0 and VTL1 memory on machines without Kernel DMA Protection enabled [@markettos-thunderclap]. The Windows mitigation is IOMMU enforcement plus Kernel DMA Protection, both of which require firmware support that mixed-vintage hardware does not always have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bypass class four -- microarchitectural side channels.&lt;/strong&gt; Spectre variant 2 -- branch target injection -- is the only Spectre-family variant whose threat model overlaps the VBS boundary, because mispredicting an indirect call inside a secure-call handler can leak data across the VTL boundary. The mitigation is enabling Indirect Branch Restricted Speculation around the secure-call entry. Section 10 walks the larger story; here it is enough to note that microarchitectural side channels are an open surface against VBS that grows with each new variant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bypass class five -- trustlet-signing-root compromise.&lt;/strong&gt; Every trustlet is identified by two Authenticode EKUs that Microsoft signs at Signature Level 12 [@ionescu-bh2015]. If an attacker controls either the signing key or the issuing infrastructure that hands out the IUM EKU, they can ship a malicious binary that the Secure Kernel admits as a legitimate trustlet -- with the same VTL1 access as LSAISO.&lt;/p&gt;
&lt;p&gt;This class was theoretical at the 2019 cutline. Microsoft&apos;s July 2023 Storm-0558 disclosure put it on the forward roadmap: an Azure consumer-MSA signing key was used to forge enterprise tokens [@ms-storm-0558], and the September 2023 root-cause investigation traced the original key acquisition to a crash dump that crossed from production into a corporate debugging environment that the actor had already compromised [@msrc-storm-0558-keyacq]. The Storm-0558 incident was a token-signing-key compromise rather than a trustlet-signing-key compromise, but the architectural lesson is identical. A signing root is a single point of trust whose compromise admits arbitrary binaries to the protected privilege level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bypass class six -- the VTL0 agent surface.&lt;/strong&gt; Most VBS features ship a VTL0 process that brokers requests to a VTL1 trustlet. LSA in VTL0 brokers credential operations to LSAISO. The System Guard runtime attestation agent and the Windows Defender Application Guard broker likewise mediate between user-mode applications and their VTL1 counterparts.&lt;/p&gt;
&lt;p&gt;Bugs in those agents are still VTL0 bugs. An agent that mishandles user-controlled input before the secure-call dispatch -- a parsing error, a use-after-free, a type confusion -- can leak partial information or trigger unintended VTL1 operations even when the Secure Kernel&apos;s API is sound. The failure surface is in VTL0; the consequences can reach into VTL1 by routing through the agent. This is the everyday-engineering residual that shows up in routine MSRC advisories rather than in conference papers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Caveat -- availability is not a VBS invariant.&lt;/strong&gt; The Hyper-V Top-Level Functional Specification is explicit on this point [@ms-tlfs-vsm]. VTL0 can deny service to VTL1 by refusing to schedule the Secure Kernel, by refusing to provide pages for paging, or by refusing to dispatch secure-calls. Confidentiality and integrity are protected. Availability is not. A compromised NT kernel can stop a trustlet from running. The VBS designers made that tradeoff deliberately, because guaranteeing availability would require the Secure Kernel to manage its own scheduler and paging, which would balloon its trusted code base out of audit range.&lt;/p&gt;

VTL0 can DOS VTL1 by design. -- Microsoft Hyper-V Top-Level Functional Specification, Virtual Secure Mode
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bypass class&lt;/th&gt;
&lt;th&gt;Attack family&lt;/th&gt;
&lt;th&gt;Residual mitigation at 2019&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;BYOVD&lt;/td&gt;
&lt;td&gt;Vulnerable signed driver as kernel-mode primitive&lt;/td&gt;
&lt;td&gt;Microsoft-recommended block rules (manual at 2019; default-on with KB5020779 in Oct 2022)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hypervisor / Secure Kernel bugs&lt;/td&gt;
&lt;td&gt;Secure-call interface vulnerabilities&lt;/td&gt;
&lt;td&gt;Patch velocity; reduce secure-call surface; formal verification research&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware / DMA&lt;/td&gt;
&lt;td&gt;Pre-IOMMU PCIe / Thunderbolt DMA reads&lt;/td&gt;
&lt;td&gt;Kernel DMA Protection + IOMMU enforcement (firmware-dependent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microarchitectural side channels&lt;/td&gt;
&lt;td&gt;Spectre v2 cross-VTL leakage&lt;/td&gt;
&lt;td&gt;IBRS on secure-call entry; per-variant microcode mitigations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trustlet-signing-root compromise&lt;/td&gt;
&lt;td&gt;Forged or stolen IUM EKU signing key&lt;/td&gt;
&lt;td&gt;Signing-infrastructure hardening; no operator-side control at 2019&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VTL0 agent surface&lt;/td&gt;
&lt;td&gt;Bugs in LSA, System Guard agent, WDAG broker&lt;/td&gt;
&lt;td&gt;Conventional MSRC patching; harden agent input validation&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; Five observations on the residual map. BYOVD is the &lt;em&gt;dominant&lt;/em&gt; in-the-wild residual at the 2019 cutline -- it is what attackers actually used to bypass HVCI and Credential Guard, and the canonical Microsoft mitigation came three years late. The secure-call interface is the &lt;em&gt;quietest&lt;/em&gt; residual: most readers had never heard of it before Amar-King in 2020. Microarchitectural side channels are the &lt;em&gt;interaction&lt;/em&gt; class that links the bypass map in Section 8 to the third axis in Section 10. Trustlet-signing-root compromise is the &lt;em&gt;forward&lt;/em&gt; class -- theoretical at 2019, made concrete by Storm-0558 in 2023. VTL0 agent bugs are the &lt;em&gt;everyday-engineering&lt;/em&gt; class that shows up in routine MSRC advisories. Knowing which residual matters for which threat model is half of operational VBS deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every architecturally honest defense names its bypass classes before its critics do. VBS has six: BYOVD, hypervisor secure-call bugs, hardware DMA, microarchitectural side channels, trustlet-signing-root compromise, and the VTL0 agent surface. The architectural gap is small. The deployment gap, as the next section will show, is much larger.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These are the architectural residuals. The operational residuals turned out to be bigger by orders of magnitude. The path from a kernel-isolated 2017 Enterprise laptop to a paralyzed hospital starts with a missed patch.&lt;/p&gt;
&lt;h2&gt;9. The Offensive Story: Ransomware Industrialization (2017-2019)&lt;/h2&gt;
&lt;p&gt;Between May 12, 2017 and November 21, 2019, the criminal Windows-attack industry went through five generations of business-model evolution in thirty months. Worm-spray ransomware. State-actor wiper. Targeted enterprise extortion. Ransomware-as-a-Service. Encryption plus exfiltration -- the double-extortion playbook. None of the five required novel exploitation against VBS-class defenses. They required only that VBS-class defenses not be deployed.&lt;/p&gt;
&lt;p&gt;The 2017-2019 arc has a predecessor that explains the rest. In September 2013, Symantec Security Response reported a new family of Windows ransomware called CryptoLocker, distributed by Evgeniy Bogachev&apos;s peer-to-peer Gameover Zeus botnet, encrypting victim files with per-victim 2048-bit RSA keys and demanding payment in Bitcoin or MoneyPak. Ransom demands ran in the low three figures to low four figures: enough to be commercially viable against consumers, capped by what consumers could pay.&lt;/p&gt;
&lt;p&gt;On June 2, 2014, a joint operation -- the FBI, Europol, the UK National Crime Agency, Dutch and German law-enforcement, plus Symantec, Dell SecureWorks, CrowdStrike, F-Secure, Microsoft, Trend Micro, and McAfee -- executed Operation Tovar [@doj-operation-tovar] [@europol-operation-tovar] [@fbi-goz]. The operation seized the Gameover Zeus command-and-control and sinkholed the peer-to-peer overlay; FireEye and Fox-IT used the recovered keypair database to stand up a free decryption portal for CryptoLocker victims.&lt;/p&gt;
&lt;p&gt;Operation Tovar disrupted the vector. It did not disrupt the business model. Within months, CryptoWall surpassed CryptoLocker in infection volume under different operators [@secureworks-cryptowall]. The lesson the next five years would teach is that &lt;em&gt;takedown alone does not solve the ransomware problem&lt;/em&gt;: the underlying economics -- encryption plus extortion against a Bitcoin-receivable -- are the asset, and the operators are commodity. From CryptoLocker forward, the criminal arc forks into the worm-spray fork (WannaCry, NotPetya, Bad Rabbit) and the targeted-enterprise fork (SamSam, Ryuk, REvil, Maze) that converge at Maze double extortion in November 2019.&lt;/p&gt;
&lt;h3&gt;9.1 WannaCry (May 12, 2017)&lt;/h3&gt;
&lt;p&gt;The patch-gap timeline is the spine of the WannaCry story. Microsoft published Security Bulletin MS17-010 on March 14, 2017, patching CVE-2017-0143 through CVE-2017-0148 in the &lt;a href=&quot;https://paragmali.com/blog/the-connection-that-refused-to-downgrade-twenty-five-years-o/&quot; rel=&quot;noopener&quot;&gt;SMBv1 server&lt;/a&gt; [@ms-ms17-010] [@nvd-cve-2017-0144]. Thirty-one days later, on April 14, 2017, the Shadow Brokers leaked the NSA Equation Group&apos;s &quot;Lost in Translation&quot; toolkit, which included the EternalBlue exploit weaponizing CVE-2017-0144 over SMBv1 and DoublePulsar, a kernel-mode SMB backdoor [@wiki-eternalblue]. Twenty-eight days after that, on May 12, 2017, WannaCry began propagating. Total patch-to-outbreak window: fifty-nine days.&lt;/p&gt;
&lt;p&gt;The exploit, mechanically, is two pieces. EternalBlue exploits a race condition in the SMBv1 Transaction2 subcommand processing in &lt;code&gt;srv.sys&lt;/code&gt;, achieving controlled kernel-pool corruption that lets the attacker write a controlled &lt;code&gt;SrvNet&lt;/code&gt; buffer into a controlled location -- enough to land kernel-mode code execution. DoublePulsar plants a kernel-mode backdoor that listens for follow-on shellcode over SMB. Sean Dillon&apos;s RiskSense paper &lt;em&gt;EternalBlue: Exploit Analysis and Port to Microsoft Windows 10&lt;/em&gt; (2018) is the canonical reverse-engineering account [@dillon-risksense-eternalblue].&lt;/p&gt;

sequenceDiagram
    participant Atk as Attacker
    participant Srv as srv.sys (SMBv1)
    participant Krn as Kernel pool
    participant DP as DoublePulsar
    Atk-&amp;gt;&amp;gt;Srv: SMBv1 Trans2 request with crafted parameters
    Srv-&amp;gt;&amp;gt;Krn: pool allocation hits race condition
    Atk-&amp;gt;&amp;gt;Srv: groom SrvNet buffer
    Srv-&amp;gt;&amp;gt;Krn: controlled overwrite, ring 0 execution
    Krn-&amp;gt;&amp;gt;DP: install kernel-mode backdoor
    Atk-&amp;gt;&amp;gt;DP: deliver ransomware payload over SMB
    DP--&amp;gt;&amp;gt;Atk: payload running as SYSTEM
&lt;p&gt;The propagation halted at 15:03 UTC on May 12, 2017 when Marcus Hutchins, a then-22-year-old British researcher writing as MalwareTech, registered an unregistered domain hard-coded into the WannaCry binary as a kill-switch test. Hutchins thought he was sinkholing for telemetry. He had accidentally stopped the worm [@malwaretech-killswitch].The kill-switch domain registration is well-attested at 15:03 UTC; the moment global propagation visibly slowed lagged the registration by minutes to hours as the sinkhole DNS record propagated through caching resolvers worldwide.&lt;/p&gt;
&lt;p&gt;Damage at the National Health Service was severe but not maximal: the National Audit Office&apos;s October 2017 investigation reports that the attack disrupted at least 34 percent of trusts in England, NHS England identified 6,912 cancelled appointments, and the estimate of total cancelled appointments was over 19,000 [@nao-wannacry]. The NAO is clear that no NHS organization paid the ransom. The British government and NHS England later attributed the WannaCry outbreak to North Korea, formally on December 19, 2017, in a White House press briefing that coordinated attribution with the United Kingdom, Australia, Canada, New Zealand, and Japan [@wh-wannacry].&lt;/p&gt;
&lt;p&gt;CISA, then US-CERT, had issued an alert during the May 12 outbreak window [@cisa-may-2017-ransomware]. Global damage estimates ran to around four billion US dollars across cancelled production, recovery costs, and downtime at Renault-Nissan plants, FedEx, Telefonica, Deutsche Bahn, and the NHS.&lt;/p&gt;
&lt;p&gt;The architectural lesson of WannaCry is not that VBS failed. VBS was not running on the affected NHS workstations, which were largely unpatched Windows 7 boxes. The architectural lesson of WannaCry is that &lt;em&gt;patch velocity remained the dominant defense in 2017&lt;/em&gt;, and that the deployment-gap problem was, and remains, the larger lever than the architectural-gap problem.&lt;/p&gt;
&lt;h3&gt;9.2 NotPetya (June 27, 2017)&lt;/h3&gt;
&lt;p&gt;Six weeks later, on June 27, 2017, the world saw what an actually-state-actor-grade Windows campaign looks like. The vector was a supply-chain compromise of M.E.Doc, the Ukrainian tax-and-accounting software whose update channel pushed the malicious binary to thousands of M.E.Doc-running endpoints [@talos-medoc]. ESET&apos;s TeleBots write-up confirmed the operator: the BlackEnergy-lineage Sandworm group [@eset-telebots].&lt;/p&gt;
&lt;p&gt;The payload self-propagated using EternalBlue plus EternalRomance plus credential reuse via a bundled Mimikatz-style routine, then encrypted Master File Tables and boot sectors. Kaspersky&apos;s analysis -- &quot;Schroedinger&apos;s Pet(ya)&quot; -- is the canonical evidence that the malware was a wiper masquerading as ransomware: &quot;After an analysis of the encryption routine of the malware used in the Petya/ExPetr attacks, we have thought that the threat actor cannot decrypt victims&apos; disk, even if a payment was made&quot; [@kaspersky-petya]. The Salsa20 key derivation made decryption impossible by design.&lt;/p&gt;
&lt;p&gt;The Maersk story, told most memorably in Andy Greenberg&apos;s WIRED feature and at book length in his 2019 Doubleday volume &lt;em&gt;Sandworm: A New Era of Cyberwar and the Hunt for the Kremlin&apos;s Most Dangerous Hackers&lt;/em&gt;, is the iconic case [@wired-notpetya] [@greenberg-sandworm-book]. Maersk&apos;s IT department recovered from a single, accidentally-offline domain controller in Ghana [@wired-notpetya] [@greenberg-sandworm-book].&lt;/p&gt;
&lt;p&gt;The aggregate damage estimate from the February 15, 2018 White House attribution statement is &quot;billions of dollars in damage&quot; with the headline language: &quot;In June 2017, the Russian military launched the most destructive and costly cyber-attack in history&quot; [@wh-notpetya]. The UK&apos;s National Cyber Security Centre issued parallel attribution to the Russian military [@ncsc-russia-notpetya]. The US Department of Justice indicted six GRU Unit 74455 officers on October 19, 2020 -- Andrienko, Detistov, Frolov, Kovalev, Ochichenko, Pliskin -- for NotPetya, Olympic Destroyer, and related campaigns [@doj-gru-notpetya].&lt;/p&gt;

In June 2017, the Russian military launched the most destructive and costly cyber-attack in history. -- White House Press Secretary statement, February 15, 2018

The October 19, 2020 indictment in the Western District of Pennsylvania names the six GRU officers and ties them to NotPetya, Olympic Destroyer, the OPCW intrusion, the 2015 and 2016 Ukrainian power grid attacks, and the 2017 French election hack-and-leak [@doj-gru-notpetya]. The indictment lands three years after this article&apos;s primary window closes, but the canonical US attribution record for NotPetya lives in that document.
&lt;p&gt;The architectural lesson of NotPetya is &lt;em&gt;not&lt;/em&gt; patch velocity. NotPetya owned its initial victims through a trusted update channel; patch cadence does not help against an installer signed by your software vendor. The lesson is that &lt;strong&gt;build-pipeline integrity is the next frontier&lt;/strong&gt;, and SolarWinds in December 2020 -- the Part 5 chapter of this series -- will make that lesson industry-canonical.&lt;/p&gt;
&lt;h3&gt;9.3 Bad Rabbit (October 24, 2017)&lt;/h3&gt;
&lt;p&gt;Bad Rabbit was a four-month-later, smaller-scale cousin. Distribution was via drive-by infection from compromised Russian and Ukrainian media sites, with a payload masquerading as an Adobe Flash Player installer. Lateral movement used EternalRomance, not EternalBlue, and Kaspersky&apos;s analysis confirms code overlap with NotPetya [@kaspersky-bad-rabbit]. The blast radius was Slavic-language-region targeted. One paragraph of treatment matches the historical importance: enough to triangulate Sandworm, not enough to change the architectural story.&lt;/p&gt;
&lt;h3&gt;9.4 The Big Game Hunting Transition (2018-2019)&lt;/h3&gt;
&lt;p&gt;By the second half of 2018, ransomware crews had decided that mass spray was leaving money on the table. The pattern crystallized into what CrowdStrike named, in late 2018 and early 2019, &lt;em&gt;big game hunting&lt;/em&gt; [@crowdstrike-ryuk].&lt;/p&gt;

A targeted ransomware business model in which a human operator gains access to a victim network, performs hands-on-keyboard reconnaissance, escalates to Domain Admin, locates backup infrastructure, and deploys ransomware enterprise-wide in a single coordinated event. Ransom demands scale to victim revenue. CrowdStrike&apos;s January 2019 write-up of WIZARD SPIDER&apos;s Ryuk operations is the standard reference for the term [@crowdstrike-ryuk].
&lt;p&gt;The proto-Big-Game-Hunting predecessor is SamSam, operated from December 2015 through November 2018 by the Iranian operators Faramarz Shahi Savandi and Mohammad Mehdi Shah Mansouri. SamSam combined Internet-facing RDP brute force and JBoss exploitation with manual lateral movement and ransomware-of-the-domain-controller, caused more than $30 million in aggregate damages, and collected more than $6 million in ransom payments, per the November 28, 2018 DOJ indictment of Savandi and Mansouri [@doj-samsam]. The thirty-million figure is the DOJ&apos;s &lt;em&gt;damages / losses&lt;/em&gt; characterization, not the &lt;em&gt;demanded ransom&lt;/em&gt; amount: per-victim SamSam demands ran in the five- to fifty-thousand-dollar range, and the aggregate damages include downtime, recovery, and unrecovered ransom rather than the operators&apos; headline ask. SamSam was the phase from 2016 forward; CrowdStrike named the phase in 2018.&lt;/p&gt;
&lt;p&gt;The named-and-canonical Big Game Hunting lineage runs through three families.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ryuk&lt;/strong&gt; first appeared in August 2018, operated by CrowdStrike&apos;s WIZARD SPIDER (the TrickBot crew). Check Point&apos;s first-wave analysis identified the code overlap with the earlier HERMES ransomware, originally attributed to the Lazarus Group, though Check Point notes the toolchain overlap rather than asserting shared operations [@checkpoint-ryuk]. The killchain Cybereason later detailed was the Emotet -&amp;gt; TrickBot -&amp;gt; Ryuk trifecta: a phishing-delivered Emotet loader, TrickBot for credential theft and lateral movement, hands-on-keyboard reconnaissance, and Ryuk for the encryption payload.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;REvil&lt;/strong&gt; -- also called Sodinokibi -- emerged in April 2019. The Talos analysis published April 30, 2019 attributed first observed in-the-wild exploitation of CVE-2019-2725 to a Sodinokibi-deploying campaign active since at least April 17, 2019 [@talos-sodinokibi]; April 30 is the &lt;em&gt;publication&lt;/em&gt; date of the Talos write-up, not the first-observed exploitation date. Secureworks attributed the operation to the GOLD SOUTHFIELD group and noted Sodinokibi was &quot;likely associated with the GandCrab ransomware due to similar code and the emergence of REvil as GandCrab activity declined&quot; [@secureworks-revil].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maze&lt;/strong&gt; entered the field in May 2019 [@malwarebytes-maze-2020].&lt;/p&gt;

flowchart LR
    A[Spear-phish&lt;br /&gt;Emotet loader]
    B[TrickBot&lt;br /&gt;credential theft]
    C[Hands-on-keyboard&lt;br /&gt;lateral movement]
    D[Domain Admin]
    E[Backup-network&lt;br /&gt;reconnaissance]
    F[Mass deployment&lt;br /&gt;SCCM, GPO, PsExec]
    G[Exfiltration]
    H[Encryption]
    I[Leak-site pressure]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D --&amp;gt; E --&amp;gt; F --&amp;gt; H
    E --&amp;gt; G --&amp;gt; I
    H --&amp;gt; I
&lt;h3&gt;9.5 Maze and Double Extortion (November 21, 2019)&lt;/h3&gt;
&lt;p&gt;The fifth-generation business model arrived in late 2019. Maze&apos;s operators attacked the security-staffing firm Allied Universal in November 2019. When Allied Universal refused to pay, Maze threatened to release the stolen files publicly. In December 2019, Maze published a leak site listing victims who had not paid, with sample data to prove possession. Brian Krebs broke the story on December 16, 2019: &quot;Less than 48 hours ago, the cybercriminals behind the Maze Ransomware strain erected a Web site on the public Internet... that changed at the end of last month, when the crooks behind Maze Ransomware threatened Allied Universal that if they did not pay the ransom, they would release their files&quot; [@krebs-maze].&lt;/p&gt;

A ransomware business model in which the operator exfiltrates victim data before encrypting it, then threatens public disclosure of the data as a separate pressure axis if the ransom is not paid. Maze, beginning with the November 2019 Allied Universal case and the December 2019 dedicated leak site, is the canonical first systematic deployment [@krebs-maze]. Snatch had threatened similar disclosure earlier in October 2019, but did not operate dedicated leak-site infrastructure [@sophos-snatch].
&lt;p&gt;The economic logic is simple. The ransomware-only business model assumed the victim&apos;s only pressure point was the encrypted data -- which meant good backups defeated the extortion. Double extortion adds a second pressure axis (public disclosure) that backups do not address. The pattern propagated industry-wide in 2020; &lt;strong&gt;exfil-then-encrypt is now the standard ransomware business model.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;9.6 The synthesis: a paradox of layers&lt;/h3&gt;
&lt;p&gt;Now the synthesis. The Enterprise laptop with Credential Guard enabled, in Scene A of Section 1, sat above the VBS architecture. The unpatched SMBv1 Windows 7 box on the NHS network, in Scene B, sat below it -- on a vintage of Windows that predated Credential Guard entirely and on a network nobody had segmented around the wormable SMBv1 protocol. Both ran &quot;Windows&quot; in the same five-year window. The difference between them was not architectural rigor. The difference was operational rigor: patches applied, segmentation configured, SMBv1 disabled, supported SKUs deployed, VBS enabled.&lt;/p&gt;
&lt;p&gt;VBS is a &lt;em&gt;structural defense&lt;/em&gt; for the credential store on a properly-configured Enterprise endpoint. Patching is an &lt;em&gt;operational defense&lt;/em&gt; for the network-edge attack surface. They protect orthogonal layers of the stack. A correct defense at one layer is consistent with a catastrophic miss at the other.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The paradox of simultaneity: Microsoft&apos;s largest structural defensive break in twenty years and the criminal and state-actor world&apos;s largest operational expansion in twenty years happened in the same five-year window because they live at different layers of the defense stack.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is one more axis, and it is orthogonal to both VBS and patch velocity. The CPU itself was the attacker&apos;s primitive.&lt;/p&gt;
&lt;h2&gt;10. The Third Axis: Meltdown, Spectre, KVA Shadow, Retpoline (2018-2019)&lt;/h2&gt;
&lt;p&gt;On January 3, 2018, the security industry&apos;s calendar acquired a new entry. Jann Horn at Google Project Zero, Moritz Lipp and colleagues at Graz University of Technology, Paul Kocher independent, and a coordination of six other institutions disclosed that out-of-order execution on every Intel CPU shipped since the mid-1990s could be turned against the kernel-user privilege boundary [@pz-meltdown-spectre]. None of the Windows defenses shipped in the prior thirty months touched the attack class. None could. The attacker&apos;s primitive was the CPU.&lt;/p&gt;
&lt;p&gt;The Google Project Zero blog post enumerates three variants. &lt;strong&gt;Variant 1&lt;/strong&gt;, bounds check bypass, became CVE-2017-5753. &lt;strong&gt;Variant 2&lt;/strong&gt;, branch target injection, became CVE-2017-5715. &lt;strong&gt;Variant 3&lt;/strong&gt;, rogue data cache load, became CVE-2017-5754 and was named Meltdown [@pz-meltdown-spectre] [@ms-myerson-meltdown]. Variants 1 and 2 together became the family named Spectre. The peer-reviewed papers landed later: Meltdown at USENIX Security 2018 with Lipp as lead author and an authorship list including Schwarz, Gruss, Prescher, Haas, Fogh, Horn, Mangard, Kocher, Genkin, Yarom, and Hamburg [@lipp-meltdown-usenix]; Spectre at IEEE S&amp;amp;P 2019 with Kocher as lead author [@kocher-spectre-ieee].The Meltdown paper&apos;s authorship list does not include &quot;Strackx&quot; -- that name belongs to the later Foreshadow / L1TF paper. The audit on this article&apos;s research stage flagged the attribution error; the corrected roster is the one cited above [@lipp-meltdown-usenix].&lt;/p&gt;
&lt;p&gt;Windows shipped three mitigations in response. &lt;strong&gt;KVA Shadow&lt;/strong&gt; is Microsoft&apos;s name for what Linux calls Kernel Page-Table Isolation -- the technique descended from Gruss et al.&apos;s 2017 KAISER paper. The mechanism is to maintain two page tables per process. The &quot;user&quot; page table maps only the user address space and a minimal kernel trampoline. The &quot;kernel&quot; page table maps the full kernel. Every user-mode-to-kernel-mode transition swaps the CR3 register to install the kernel page table; every return swaps it back. The kernel page-table entries that previously sat in the same virtual address space as the user, and that Meltdown exploited speculatively, are no longer mapped during user-mode execution.&lt;/p&gt;

sequenceDiagram
    participant U as User-mode process
    participant CPU as CPU
    participant K as Kernel
    U-&amp;gt;&amp;gt;CPU: syscall instruction
    CPU-&amp;gt;&amp;gt;CPU: swap CR3 to kernel page-table
    CPU-&amp;gt;&amp;gt;K: dispatch kernel handler
    K-&amp;gt;&amp;gt;K: execute handler logic
    K-&amp;gt;&amp;gt;CPU: prepare return
    CPU-&amp;gt;&amp;gt;CPU: swap CR3 to user shadow page-table
    CPU--&amp;gt;&amp;gt;U: return to user mode
&lt;p&gt;&lt;strong&gt;Retpoline&lt;/strong&gt; is the Spectre v2 mitigation. The technique, due to Paul Turner at Google in early 2018, replaces every indirect branch with a return-based thunk that the speculative-execution unit cannot mis-train into the attacker&apos;s chosen target. Microsoft backported Retpoline into Windows 10 1809 via the KB4482887 cumulative update on March 1, 2019, and enabled it by default via cloud configuration on May 14, 2019; the canonical write-up sits on the Windows Kernel team&apos;s TechCommunity blog (first posted December 6, 2018; updated through May 14, 2019) [@ms-retpoline]. The timing matters because Windows 10 1809 reached RTM on November 13, 2018: on supposedly-Retpoline-protected 1809 boxes there were roughly six months of unprotected Spectre v2 surface between the 1809 RTM and the May 14, 2019 cloud-enable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IBRS, IBPB, and STIBP&lt;/strong&gt; -- Indirect Branch Restricted Speculation, Indirect Branch Predictor Barrier, Single Thread Indirect Branch Predictor -- are the CPU-MSR-controlled mitigations delivered through Intel and AMD microcode updates that Windows manages via the kernel.&lt;/p&gt;
&lt;p&gt;The performance cost was not uniform. Terry Myerson&apos;s January 9, 2018 Microsoft Security Blog post tiers it: Skylake-and-newer client CPUs saw &quot;single-digit slowdowns&quot;; Haswell-era and older systems saw &quot;more significant slowdowns&quot;; Server 2016 and SQL workloads saw &quot;even more significant slowdowns&quot; [@ms-myerson-meltdown]. The MariaDB community published one of the most-cited empirical anchors: on Haswell-era hardware doing MyISAM table scans, KPTI cost 37 to 40 percent in the worst case [@mariadb-kpti]. A 40 percent regression for a SQL workload is an unmistakable signal that the page-table swap dominates short-syscall-heavy code paths.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Operators who use the &lt;code&gt;FeatureSettingsOverride&lt;/code&gt; and &lt;code&gt;FeatureSettingsOverrideMask&lt;/code&gt; registry knobs to disable KVA Shadow, Retpoline, or IBRS in pursuit of benchmark numbers are running an operationally unpatched Meltdown-vulnerable system. The performance numbers in benchmark blogs that &quot;disable mitigations&quot; are reporting the speed of a hardware configuration whose threat model is January 2018.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The lesson here is structural. &lt;em&gt;VBS does not help against microarchitectural attacks because VBS protects against software primitives; the CPU itself is the attacker&apos;s primitive.&lt;/em&gt; The only point at which the microarchitectural axis touches VBS is Spectre v2 cross-VTL leakage during secure-call dispatch, and the answer there is to set IBRS on secure-call entry -- the same MSR-level control that protects any indirect branch in privileged code.&lt;/p&gt;
&lt;p&gt;VBS, patch velocity, microarchitectural mitigations. Three axes of defense, each addressing a different attack primitive. Where does that leave the operator on December 31, 2019?&lt;/p&gt;
&lt;h2&gt;11. Operating Windows 10 in the 2017-2019 Threat Environment&lt;/h2&gt;
&lt;p&gt;A defender at the 2019 cutline who reads only the architecture papers will deploy VBS and feel safe. A defender who reads only the breach reports will assume nothing works. The truth is structurally bounded.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For enterprise administrators.&lt;/strong&gt; Enable Credential Guard plus HVCI on Enterprise SKUs from 1607 forward [@ms-credential-guard] [@ms-hvci]. Deploy WDAC with audit-mode-first rollout, then enforce [@ms-wdac]. Patch within 30 days of MSRC release -- the WannaCry lesson is fifty-nine days. Disable SMBv1 outright. Inventory unused signed kernel drivers and remove them. Stand up Defender for Endpoint or an equivalent EDR. Treat segmentation between user subnets and server subnets as a deployable security control, not an architectural aspiration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Production WDAC policies routinely run to thousands of rules. The canonical mitigation for XML-authoring complexity is reference-monitor-mode rollouts: ship the policy in audit mode, collect 7 to 14 days of &lt;code&gt;MicrosoftWindows-CodeIntegrity/Operational&lt;/code&gt; events from real users, refine the allow-list against the captured baseline, then move to enforce. Skipping audit mode reliably produces a Tuesday morning of broken business workflows [@ms-wdac].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;For application developers.&lt;/strong&gt; Compile with &lt;code&gt;/guard:cf&lt;/code&gt; to opt into CFG instrumentation [@ms-cfg]. Set per-app Process Mitigation Policies via &lt;code&gt;Set-ProcessMitigation&lt;/code&gt; [@ms-set-processmitigation], picking the subset (ACG, CIG, Strict Handle Checks, Disable Win32k System Calls) that fits your runtime. Sign your binaries with Authenticode using a hardware-backed key. If your application reads credentials, make sure they never touch LSASS; use the CredUI or Web Account Manager surface, which integrates with Credential Guard cleanly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For security researchers.&lt;/strong&gt; Read Ionescu&apos;s Black Hat USA 2015 deck plus the Weston-Ionescu OPCDE 2018 &quot;Inside the Octagon&quot; before claiming a &quot;VBS bypass&quot; [@ionescu-bh2015] [@opcde-inside-octagon]. Categorize any bypass you find into one of the six classes named in Section 8 -- BYOVD, hypervisor or secure-call bugs, hardware DMA, microarchitectural side channels, trustlet-signing-root compromise, or VTL0-agent surface. Cross-cite Microsoft Learn for any specification-level claim about VTL semantics. The Yosifovich, Ionescu, Russinovich, and Solomon &lt;em&gt;Windows Internals&lt;/em&gt; 7th edition, Part 1 (May 2017) remains the canonical textbook anchor for the 1507-to-1607 era architecture [@mspress-windows-internals-7e].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For SOC analysts.&lt;/strong&gt; EternalBlue and DoublePulsar signatures are still recurring in unmanaged-edge devices in 2024 and 2025 [@hunterstrategy-eternalblue]. Train detection rules on the SMB signal, not just the WannaCry payload signature.The DoublePulsar implant responds to a specific SMB Trans2 SESSION_SETUP subcommand with a non-zero Multiplex ID, which is the most-cited single-packet network signature for triage. The Emotet -&amp;gt; TrickBot -&amp;gt; Ryuk killchain pattern is the operational anchor for human-operated ransomware detection; the IOCs change every quarter, but the kill-chain stages do not. PrintNightmare, a 2021 Part-5 story, reuses the same SMB-style propagation pattern.&lt;/p&gt;

On a Windows 10 or 11 Enterprise host, run `msinfo32.exe`, find the &quot;Virtualization-based security Services Running&quot; row, and confirm it lists `Credential Guard`. From PowerShell, `Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard | Select SecurityServicesRunning` returns an array whose value `1` corresponds to Credential Guard and value `2` to HVCI. If the array is empty, VBS is configured but no isolated services have started, and the LSAISO trustlet is not actually protecting credentials on that machine.
&lt;p&gt;By the end of 2019, the architectural floor is named. The operational floor is named. Three axes are not yet closed.&lt;/p&gt;
&lt;h2&gt;12. What 2015-2019 Did Not Solve&lt;/h2&gt;
&lt;p&gt;Five problems leave this window open. Each is a chapter of Part 5 or Part 6, and each is open because the architectural gap and the deployment gap are at different sizes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Supply-chain integrity.&lt;/strong&gt; NotPetya proved that build-pipeline compromise is the dominant remaining attack class against well-defended estates [@talos-medoc] [@eset-telebots]. Microsoft&apos;s Security Development Lifecycle codifies pre-release secure-engineering practice [@ms-sdl], but SDL stops at the binary the build pipeline emits; it does not certify that the binary any verifier can rebuild matches that binary.&lt;/p&gt;
&lt;p&gt;The 2015-2019 window saw two structural answers begin to mature. Debian&apos;s reproducible-builds project, in continuous progress since 2013, reached approximately 94 percent reproducibility by mid-2017 [@lwn-debian-reproducible]; the Tor Project&apos;s deterministic-builds work in 2014 framed the watering-hole-attack defense the discipline existed to address [@tor-deterministic-builds]. The Linux Foundation&apos;s Sigstore project, announced March 9, 2021, finally shipped a free transparency-log signing infrastructure for software artifacts [@lf-sigstore], and the NIST SP 800-218 Secure Software Development Framework codified the practice into a federal expectation in February 2022 [@nist-ssdf]. SolarWinds in December 2020 -- the Part 5 chapter -- forced the industry to take this open problem seriously.&lt;/p&gt;
&lt;p&gt;The architectural distinction is between code-signing-as-supply-chain-integrity (signs whatever the build pipeline emits, regardless of pipeline compromise) and reproducible-build-as-supply-chain-integrity (signs only binaries any verifier can independently reproduce from source). At the 2019 cutline, reproducible builds are not the deployment norm; by the mid-2020s they are still not the norm for proprietary Windows-side software.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The hypervisor and secure-call interface.&lt;/strong&gt; Amar and King&apos;s 2020 work on &lt;code&gt;SkmmUnmapMdl&lt;/code&gt; and &lt;code&gt;SkmiReleaseUnknownPTEs&lt;/code&gt; disclosed two kernel-strong VTL1 bugs reachable from VTL0 -- CVE-2020-0917 and CVE-2020-0918 -- and set the public-disclosure baseline at roughly one to three secure-call interface bugs per year [@amar-king-bh2020] [@msrc-cve-2020-0917].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response posture is enforcement, not formal verification. The Hyper-V Bounty program pays up to $250,000 for a guest-to-host escape, with corresponding lower tiers for partial escapes and architectural vulnerabilities [@ms-hyperv-bounty]. The Microsoft Security Servicing Criteria treats secure-kernel and HVCI bypasses as Servicing Tier 1, meaning they are silently serviced through the normal patch cadence rather than coordinated as headline incidents [@ms-servicing-criteria]. The Saar-Amar-style Hyperseed fuzzer remains the internal-tooling baseline.&lt;/p&gt;
&lt;p&gt;The open question is whether a formally-verified secure-call interface is achievable for Microsoft&apos;s deployed codebase. seL4 establishes that verification is feasible at roughly nine thousand lines of C [@klein-sel4-sosp2009]; &lt;code&gt;securekernel.exe&lt;/code&gt; is approximately 150 kilobytes with substantial integration surface. The 2019 answer is &quot;not yet.&quot; The cadence of CVEs since suggests the answer through 2024 remains &quot;not yet.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The BYOVD pipeline.&lt;/strong&gt; Microsoft&apos;s October 2022 default-on Vulnerable Driver Blocklist (KB5020779) blocks known-bad signed drivers reactively, by hash [@ms-vuln-driver-kb] [@ms-vuln-driver-blockrules]. The blocklist is fed by Microsoft&apos;s IHV-partnership submission flow, and Windows Defender Application Control consumes the same policy at the system level. The LOLDrivers community catalog tracks several hundred vulnerable signed drivers as of 2024 [@loldrivers], far more than the curated subset KB5020779 covers.&lt;/p&gt;
&lt;p&gt;The structural distinction is between known-bad drivers blocked by hash -- the current approach -- and retroactive driver-signing revocation, which would block by certificate. Hash-based blocking handles the dominant in-the-wild surface; certificate-based revocation breaks legitimate deployments that rely on older signed drivers with Authenticode timestamps that pre-date the revocation. Microsoft has not solved that tradeoff at the 2019 cutline. KB5020779 (October 2022) is the partial answer. Full retroactive revocation remains open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microarchitectural side channels in cross-VTL boundaries.&lt;/strong&gt; Spectre v2 leakage across the VTL0 to VTL1 boundary invalidates Credential Guard&apos;s confidentiality invariant if VTL0 can poison the indirect branch predictor that VTL1 consumes during a secure-call handler return; IBRS on secure-call entry is the standing mitigation, but every new microarchitectural class re-prices the defense.&lt;/p&gt;
&lt;p&gt;LVI (Load Value Injection, CVE-2020-0551, March 2020), RIDL and ZombieLoad (May 2019, microarchitectural data sampling), and Inception (USENIX Security 2023, AMD-SB-7005 against Zen 3 and Zen 4 [@usenix-inception] [@amd-sb-7005]) each open a new variant. The structural answer the industry is moving toward is microarchitecturally-partitioned CPUs: Intel TDX [@intel-tdx] and AMD SEV-SNP [@amd-sev-snp] both ship hardware-isolated virtual machines with per-VM memory encryption that close the cross-VTL leakage class by construction. Both are datacenter-only at the 2019 cutline; neither lands on mainstream Windows endpoints until well after the article&apos;s window. The 2019 operational state is IBRS-plus-microcode mitigation, re-priced each time a new variant lands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Big Game Hunting defense when backups stop being a deterrent.&lt;/strong&gt; Maze&apos;s double-extortion playbook neutralized the backup-equipped defender&apos;s bargaining position [@krebs-maze]. Three research directions are open.&lt;/p&gt;
&lt;p&gt;Cryptographic data-at-rest segmentation -- file-level encryption keyed to per-team hardware security modules, so a single compromised account cannot exfiltrate the full data corpus -- is the most direct technical answer. Segmented backup storage, in which the backup network is operationally isolated from the production network and authenticates only out-of-band, is the operational pattern that the segmented-tier-zero Active Directory work in this window points toward. Zero-knowledge backup storage, in which the storage provider holds only customer-encrypted blobs and cannot itself be compelled into the leak chain, is the architectural backstop.&lt;/p&gt;
&lt;p&gt;Cyber-insurance market design is the fourth axis: after the Mondelez-versus-Zurich act-of-war dispute, the insurance industry restructured but did not solve the moral-hazard problem of ransom-coverage as a payment channel. Maze itself ceased operations in October 2020. The playbook persisted under Conti, LockBit, and successor groups through 2024.&lt;/p&gt;
&lt;p&gt;Part 5 picks up at December 2020 with SolarWinds. Part 6 closes with the &lt;a href=&quot;https://paragmali.com/blog/the-day-85-million-devices-couldnt-boot----and-how-microsoft/&quot; rel=&quot;noopener&quot;&gt;CrowdStrike Falcon outage&lt;/a&gt; and the post-Pluton trust topology. The next five years will not be quieter.&lt;/p&gt;
&lt;h2&gt;13. Frequently Asked Questions&lt;/h2&gt;

Mimikatz still works, but the attack family Credential Guard was engineered against returns empty. The LSASS-scrape modules -- `sekurlsa::logonpasswords`, `sekurlsa::tickets`, `lsadump::secrets` -- read the bytes Credential Guard relocates into LSAISO in VTL1 [@ms-credential-guard], so the data is no longer where Mimikatz scans. What still works against a CG-enabled host is anything outside that threat model: pass-the-ticket replay of a TGT captured before CG was enabled, sign-in-time keylogging, stolen-DC krbtgt forgery, or BYOVD-grade kernel primitives that take advantage of secure-kernel bugs.

Yes. Six classes, all enumerated in Section 8 -- BYOVD with a vulnerable signed driver, hypervisor or secure-kernel vulnerabilities such as the 2020 Amar-King work on `SkmmUnmapMdl` [@amar-king-bh2020], pre-IOMMU hardware DMA, microarchitectural side channels, trustlet-signing-root compromise, and bugs in the VTL0 agents that broker requests to VTL1. None of those undermines the architectural claim that classical kernel-mode code injection is closed by HVCI&apos;s enforcement of write-XOR-execute on VTL0 kernel pages [@ms-hvci]. The bypass classes shape deployment posture; they do not invalidate the model.

Yes, in PowerShell user space. The Matt Graeber reflection trick that sets `AmsiUtils.amsiInitFailed` to true short-circuits AMSI within the running PowerShell process. MDSec&apos;s June 2018 write-up walks the family [@mdsec-amsi-bypass]. AMSI is a hook, not a sandbox; the bypass surface is part of the design tradeoff. The defender&apos;s response is the Defender behavioral pipeline and cloud telemetry, plus Constrained Language Mode and PowerShell logging that capture the bypass attempt itself as a high-confidence signal.

Both are 2016+ Server features that build on the VBS substrate, but they were not the primary endpoint-security story in 2015-2019. The vTPM trustlet (Trustlet ID 2 in Ionescu&apos;s enumeration [@ionescu-bh2015]) supports Hyper-V Shielded VMs in the Server 2016 timeframe; that is a datacenter, not an endpoint, story. The Part 4 endpoint thesis is Credential Guard, HVCI, WDAC, AMSI, CFG, and Process Mitigation Policies.

No. WannaCry used EternalBlue, an NSA-developed exploit that the Shadow Brokers leaked in their April 14, 2017 &quot;Lost in Translation&quot; dump [@wiki-eternalblue]. The operators of WannaCry were the Lazarus Group, attributed to North Korea by the United States, the United Kingdom, Australia, Canada, New Zealand, and Japan in a coordinated December 19, 2017 statement [@wh-wannacry]. The architectural lesson -- that a leaked nation-state SMB worm hit unpatched estates fifty-nine days after Microsoft shipped MS17-010 [@ms-ms17-010] -- is independent of who fired the weapon.

No. Kaspersky and CrowdStrike independently confirmed that the Salsa20 key derivation in NotPetya made decryption impossible by design [@kaspersky-petya]. The ransom payment screen was a decoy; the malware was a wiper. US, UK, Canadian, and Australian governments attributed the operation to Russian military intelligence (GRU Sandworm / Unit 74455) on February 15, 2018 [@wh-notpetya] [@ncsc-russia-notpetya]. The October 19, 2020 US Department of Justice indictment named six GRU officers [@doj-gru-notpetya].

Control Flow Guard is forward-edge, software-only, compiler-instrumented Control-Flow Integrity per the Burow et al. ACM CSUR 2017 taxonomy [@burow-cfi-csur2017] [@ms-cfg]. It validates the targets of indirect calls and jumps against a compile-time-known bitmap. Intel Control-flow Enforcement Technology adds a hardware-enforced shadow stack -- a backward-edge defense that protects return addresses. CET on Windows is a Part 5 story; here it suffices to say that CFG and CET defend orthogonal edges of the control-flow graph.
&lt;h2&gt;14. Three Boxes, Three Outcomes&lt;/h2&gt;
&lt;p&gt;A 2017 red-team operator can dump LSASS on an unprotected Windows 7 box in less than a minute. The same operator, against a 1607 Enterprise laptop with Credential Guard enabled, sees an empty buffer where the NTLM hash should be. A 2017 NHS workstation, fifty-nine days behind on MS17-010, sees a ransom note. Three Windows boxes. Three outcomes. One five-year window.&lt;/p&gt;
&lt;p&gt;The structural defense -- VBS, the Secure Kernel, LSAISO -- did exactly what its designers said it would do, in a way that was independently verifiable from the empty Mimikatz output buffer. The operational defense -- patch within a month, segment SMBv1, disable legacy protocols -- did exactly what its proponents said it would do, on the boxes where it was applied. The paradox of simultaneity is just the shape of the same picture seen from both sides.&lt;/p&gt;
&lt;p&gt;Part 5 takes the story forward into supply-chain compromise, hardware-rooted attestation, and the Intel CET shadow stack. The next five years did not solve the six bypass classes named here. They named more of them.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;above-the-kernel-windows-security-wars-part-4&quot; keyTerms={[
  { term: &quot;Virtualization-Based Security (VBS)&quot;, definition: &quot;Windows security architecture that uses hardware virtualization extensions and Second-Level Address Translation to run the NT kernel and a Secure Kernel as separate Virtual Trust Levels on the same machine.&quot; },
  { term: &quot;Virtual Trust Level (VTL)&quot;, definition: &quot;Hyper-V hypervisor abstraction in which higher-numbered VTLs are strictly more privileged than lower-numbered ones. Shipped Windows uses VTL0 for the NT kernel and VTL1 for the Secure Kernel.&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A Microsoft-signed process that runs in VTL1 Isolated User Mode and is protected from VTL0 inspection. Trustlets are gated at creation by five mechanical checks including two specific Enhanced Key Usage OIDs.&quot; },
  { term: &quot;LSAISO&quot;, definition: &quot;Trustlet ID 1; the Credential Guard secret-keeper. Holds NTLM hashes, Kerberos TGTs, and other credential material in VTL1 while LSA in VTL0 retains the API surface.&quot; },
  { term: &quot;HVCI&quot;, definition: &quot;Hypervisor-Protected Code Integrity. Uses the Hyper-V hypervisor to enforce write-XOR-execute on VTL0 kernel pages via Extended Page Tables, closing the classical kernel code-injection attack class.&quot; },
  { term: &quot;Same-privilege paradox&quot;, definition: &quot;The structural observation that any defense at the same CPU privilege level as the attacker can be disabled by the attacker. The only structural escape is to relocate the defender.&quot; },
  { term: &quot;BYOVD&quot;, definition: &quot;Bring Your Own Vulnerable Driver. An attack class in which the adversary loads a legitimately Microsoft-co-signed third-party driver with an exploitable bug to obtain kernel-mode primitives.&quot; },
  { term: &quot;Big Game Hunting&quot;, definition: &quot;Targeted ransomware business model in which a human operator performs hands-on-keyboard reconnaissance and deploys ransomware enterprise-wide at high ransom demand. Named by CrowdStrike in 2018.&quot; },
  { term: &quot;Double extortion&quot;, definition: &quot;Ransomware business model that exfiltrates victim data before encrypting, then threatens public disclosure as a second pressure axis. Maze&apos;s November 2019 Allied Universal case is the canonical first systematic deployment.&quot; },
  { term: &quot;KVA Shadow&quot;, definition: &quot;Microsoft&apos;s Meltdown mitigation. Maintains two page tables per process and swaps CR3 at every user/kernel transition, so the kernel page-table entries that Meltdown exploited speculatively are not mapped during user-mode execution.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>virtualization-based-security</category><category>credential-guard</category><category>hvci</category><category>ransomware</category><category>wannacry</category><category>notpetya</category><category>meltdown-spectre</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Protected Process Light: When the Administrator Isn&apos;t Enough</title><link>https://paragmali.com/blog/protected-process-light-when-the-administrator-isnt-enough/</link><guid isPermaLink="true">https://paragmali.com/blog/protected-process-light-when-the-administrator-isnt-enough/</guid><description>How a single byte in EPROCESS encodes a signer lattice that denies SYSTEM-integrity admins the right to read LSASS -- and why every public bypass since 2018 attacks the same structural seam.</description><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Windows Protected Process Light (PPL) re-asks the question of who can touch whom one level below the token model.** A single byte in `EPROCESS` packs a process&apos;s protection type, audit bit, and signer rung; the kernel&apos;s lattice check inside `NtOpenProcess` rejects memory-read attempts from below the target&apos;s rung even when the caller is SYSTEM with `SeDebugPrivilege` enabled. Every public bypass since 2018 lives in one structural class -- the kernel verifies the channel by which code enters a PPL, not the behaviour of that code once mapped -- which is why Microsoft classifies PPL as defense in depth rather than a security boundary, and why Credential Guard / `LsaIso.exe` is its necessary VBS-anchored companion.
&lt;h2&gt;1. Mimikatz on a Protected Box&lt;/h2&gt;
&lt;p&gt;A red team operator has done everything right. The shell is SYSTEM-integrity. &lt;code&gt;SeDebugPrivilege&lt;/code&gt; is enabled in the token. &lt;code&gt;whoami /priv&lt;/code&gt; shows every privilege Windows defines. The operator types &lt;code&gt;mimikatz.exe&lt;/code&gt;, then &lt;code&gt;privilege::debug&lt;/code&gt; -- &lt;em&gt;OK&lt;/em&gt;. Then &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; -- and Mimikatz answers:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR kuhl_m_sekurlsa_acquireLSA ; Handle on memory : (0x00000005) Access is denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mechanism that just denied them is not a privilege check at all. It is not an ACL decision. It is not the integrity-level mediator. itm4n recreated exactly this failure in 2021 against a vanilla Windows install with one registry value set [@itm4n-runasppl]. The error code &lt;code&gt;0x00000005&lt;/code&gt; is &lt;code&gt;ERROR_ACCESS_DENIED&lt;/code&gt; -- the Win32 surface that &lt;code&gt;GetLastError&lt;/code&gt; exposes for the kernel&apos;s NTSTATUS &lt;code&gt;STATUS_ACCESS_DENIED = 0xC0000022&lt;/code&gt;. The kernel returns the NTSTATUS out of &lt;code&gt;NtOpenProcess&lt;/code&gt; before the security descriptor of &lt;code&gt;lsass.exe&lt;/code&gt; has been consulted; &lt;code&gt;RtlNtStatusToDosError&lt;/code&gt; then maps it to the Win32 &lt;code&gt;0x5&lt;/code&gt; that surfaces in &lt;code&gt;kuhl_m_sekurlsa.c&lt;/code&gt;.&lt;/p&gt;

A kernel-enforced gating model that decorates a process with a *protection level* -- a structured byte combining a type field, an audit bit, and a signer rung -- and rejects `OpenProcess` requests from callers whose protection level is below the target&apos;s, regardless of token privileges or security-descriptor ACLs.
&lt;p&gt;Picture the scenario concretely. A 2026 red-team engagement against a hardened Windows 11 24H2 endpoint. &lt;code&gt;RunAsPPL&lt;/code&gt; audit-mode is on by default after the Windows 11 22H2 rollout extended audit-default to consumer SKUs [@learn-runasppl]. A third-party EDR daemon is already running, signed at the Antimalware rung via the vendor&apos;s Microsoft Virus Initiative enrollment. The operator owns local administrator. The operator has SYSTEM. The operator holds every privilege Windows defines. They still cannot read a single byte of LSASS memory.&lt;/p&gt;
&lt;p&gt;The denial trace, walked carefully, looks like this. Mimikatz calls &lt;code&gt;OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, lsass_pid)&lt;/code&gt;. The Win32 thunk lands on &lt;code&gt;NtOpenProcess&lt;/code&gt;, which dispatches to the object-manager callback &lt;code&gt;PspProcessOpen&lt;/code&gt;. That callback calls &lt;code&gt;PspCheckForInvalidAccessByProtection&lt;/code&gt;, which calls &lt;code&gt;RtlTestProtectedAccess&lt;/code&gt; against the caller&apos;s &lt;code&gt;EPROCESS.Protection&lt;/code&gt; byte and the target&apos;s &lt;code&gt;EPROCESS.Protection&lt;/code&gt; byte. The lattice test fails. The kernel strips &lt;code&gt;PROCESS_VM_READ&lt;/code&gt; from the requested mask. With the surviving limited mask, the request continues into &lt;code&gt;SeAccessCheck&lt;/code&gt;, but Mimikatz never wanted the limited mask; it wanted to read memory. The handle returned (or the failure path taken) gives Mimikatz exactly the path that produces &lt;code&gt;0x00000005&lt;/code&gt; in &lt;code&gt;kuhl_m_sekurlsa.c&lt;/code&gt;The relevant commit is &lt;code&gt;fe4e98405589e96ed6de5e05ce3c872f8108c0a0&lt;/code&gt;, cited by itm4n as the source for the exact failure path that yields &lt;code&gt;0x00000005&lt;/code&gt; [@mimikatz-sekurlsa]..&lt;/p&gt;

sequenceDiagram
    participant Mim as Mimikatz (SYSTEM, SeDebugPrivilege)
    participant K32 as kernel32 / OpenProcess
    participant NtOP as NtOpenProcess
    participant PsPO as PspProcessOpen
    participant CHK as PspCheckForInvalidAccessByProtection
    participant Lat as RtlTestProtectedAccess
    participant SAC as SeAccessCheck&lt;pre&gt;&lt;code&gt;Mim-&amp;gt;&amp;gt;K32: OpenProcess(PROCESS_VM_READ, lsass)
K32-&amp;gt;&amp;gt;NtOP: syscall NtOpenProcess
NtOP-&amp;gt;&amp;gt;PsPO: object-manager callback
PsPO-&amp;gt;&amp;gt;CHK: check caller.Protection vs target.Protection
CHK-&amp;gt;&amp;gt;Lat: lattice rule (signer rungs)
Lat--&amp;gt;&amp;gt;CHK: full mask denied
CHK--&amp;gt;&amp;gt;PsPO: strip PROCESS_VM_READ
PsPO-&amp;gt;&amp;gt;SAC: residual mask (limited only)
SAC--&amp;gt;&amp;gt;NtOP: limited handle (read denied)
NtOP--&amp;gt;&amp;gt;Mim: STATUS_ACCESS_DENIED (NTSTATUS 0xC0000022, Win32 GetLastError = 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If every privilege Windows defines is held by the caller, what is doing the denying? The answer is a kernel structure that the token model does not see and the security descriptor does not influence -- a byte in &lt;code&gt;EPROCESS&lt;/code&gt; named &lt;code&gt;Protection&lt;/code&gt;, mediating a lattice the access check consults &lt;em&gt;before&lt;/em&gt; it ever asks &lt;code&gt;SeAccessCheck&lt;/code&gt; about privileges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not a workaround pattern. It is a new dimension. The token model is unchanged. The integrity level is unchanged. The security descriptor on &lt;code&gt;lsass.exe&lt;/code&gt; is unchanged. What changed is that the kernel now answers a question it did not ask before: &lt;em&gt;what kind of trust does the caller have to manipulate the address space of the callee?&lt;/em&gt;&lt;/p&gt;

PPL re-asks the question of who can touch whom one level below the token model.
&lt;p&gt;That mechanism has a name (Protected Process Light), an encoding (a single &lt;code&gt;UCHAR&lt;/code&gt;), and a history that does not begin where you would expect. To understand the byte, we have to understand why Microsoft built it in the first place. The next section starts where the history starts: a 2006 Microsoft whitepaper about Hollywood.&lt;/p&gt;
&lt;h2&gt;2. Historical Origins -- Vista, DRM, and the First Protected Process&lt;/h2&gt;
&lt;p&gt;The kernel mechanism that today denies admins access to LSASS was invented in 2006 to keep Hollywood happy. The cover page of Microsoft&apos;s &lt;code&gt;process_vista.doc&lt;/code&gt; whitepaper opens with a sentence almost no one quotes today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Microsoft Windows Vista operating system introduces a new type of process known as a protected process to enhance support for Digital Rights Management functionality in Windows Vista.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The whitepaper was published November 27, 2006, two months before Vista&apos;s GA, and it is the architectural seed of the byte we will be staring at for the rest of this article [@vista-process-doc]. The motivation was not credential theft. It was HD-DVD and Blu-ray content protection. Studio licensing agreements required that even an administrator on the local machine could not read the audio device graph isolation host&apos;s memory while protected content was playing. The Protected Media Path required a kernel-enforced barrier between admin user-mode and the media pipeline.&lt;/p&gt;

The Vista-era set of components that decrypt and render high-definition video and audio content under DRM. PMP requires kernel-enforced isolation of `audiodg.exe` and a small set of related processes so that local administrators cannot dump intermediate content keys from process memory.
&lt;p&gt;The Vista design was minimal. A single bit in &lt;code&gt;EPROCESS&lt;/code&gt; marks a process as protected. At &lt;code&gt;NtCreateUserProcess&lt;/code&gt;, the kernel parses the main image&apos;s Authenticode signature and looks for a specific Microsoft EKU OID that only the PMP signing root can issue [@forshaw-2018-10]. If the EKU is present and the chain resolves to that root, the kernel flips the bit. On every subsequent &lt;code&gt;NtOpenProcess&lt;/code&gt; against that process, the kernel strips a fixed set of access rights from the mask, no matter who is asking.&lt;/p&gt;
&lt;p&gt;Alex Ionescu, then a Windows internals researcher and now CrowdStrike&apos;s Chief Technology Innovation Officer, enumerated the denials in 2007 [@ionescu-pp-bad-idea]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A typical process cannot perform operations such as the following on a protected process: Inject a thread into a protected process; Access the virtual memory of a protected process; Debug an active protected process; Duplicate a handle from a protected process; Change the quota or working set of a protected process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Five denials. One bit. One certificate root. Ionescu&apos;s same essay, titled &quot;Why Protected Processes Are A Bad Idea,&quot; made a structural argument that aged well: putting a DRM mechanism in the kernel is a category error. The mechanism is too narrow for non-DRM use because the only certificate accepted is Microsoft&apos;s PMP signing root, and the only operations gated are the ones Hollywood cared about. Third parties cannot opt in, and Microsoft itself cannot graduate the level of trust.Ionescu&apos;s 2007 critique remains worth reading on its own merits. The argument that DRM-shaped kernel features tend to be reused for security mitigations and that this reuse changes their threat-model semantics is exactly what plays out over the next seven years [@ionescu-pp-bad-idea].&lt;/p&gt;
&lt;p&gt;The seven-year pause is its own story. Vista shipped, Vista was followed by Windows 7, and Windows 7 was followed by Windows 8 -- and through all of it, the access-check primitive that protects &lt;code&gt;audiodg.exe&lt;/code&gt; from administrators remained a DRM artefact. The primitive existed; the &lt;em&gt;graduated trust dimension&lt;/em&gt; did not. Two parallel failures pushed Microsoft toward widening the encoding.&lt;/p&gt;
&lt;p&gt;The first was Mimikatz. Benjamin Delpy&apos;s tool was first released in May 2011 and refined through 2013 [@mimikatz-wikipedia]; it made it trivial for an administrator to extract NTLM hashes and Kerberos session keys from &lt;code&gt;lsass.exe&lt;/code&gt;. The countermeasure of restricting &lt;code&gt;SeDebugPrivilege&lt;/code&gt; was useless; an attacker who has SYSTEM has every privilege. What Mimikatz exploited was a primitive gap: the kernel had no way to say &quot;lsass is protected against administrators but reachable from privileged Microsoft services.&quot;&lt;/p&gt;
&lt;p&gt;The second was Mateusz Jurczyk&apos;s CSRSS jailbreak of Windows 8 RT in 2013. Jurczyk (who writes as &lt;code&gt;j00ru&lt;/code&gt;) catalogued more than seventy Win32k system calls that the kernel guarded with the pattern &lt;code&gt;if (PsGetCurrentProcess() != gpepCsrss) return STATUS_ACCESS_DENIED;&lt;/code&gt; [@j00ru-1393]. That gating mechanism worked only as long as nobody could inject code into &lt;code&gt;csrss.exe&lt;/code&gt;. On Windows 8 RT, an attacker who could inject into &lt;code&gt;csrss.exe&lt;/code&gt; could bypass Microsoft&apos;s locked-down Surface RT shell. Ionescu later observed that &quot;In Windows 8.1 RT, this jailbreak is &apos;fixed&apos;, by virtue that code can no longer be injected into Csrss.exe for the attack&quot; [@ionescu-part2]. The fix made &lt;code&gt;csrss.exe&lt;/code&gt; a PPL at the &lt;code&gt;WinTcb&lt;/code&gt; rung, and the same machinery was generalised to &lt;code&gt;lsass.exe&lt;/code&gt; and the Antimalware tier.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Mimikatz proved Microsoft needed a graduated trust dimension for &lt;code&gt;lsass.exe&lt;/code&gt;. The j00ru CSRSS jailbreak proved Microsoft needed it for &lt;code&gt;csrss.exe&lt;/code&gt; too. The same widening of the encoding answered both.&lt;/p&gt;
&lt;/blockquote&gt;

flowchart LR
    subgraph Vista2006[Vista 2006 -- single bit]
        V1[EPROCESS protected = 0 or 1]
        V2[Certificate root: PMP only]
        V3[Access denials: hardcoded 5-tuple]
    end
    subgraph Win81[Windows 8.1 -- _PS_PROTECTION byte]
        W1[Type: 3 bits]
        W2[Audit: 1 bit]
        W3[Signer rung: 4 bits]
        W4[Certificate roots: per-EKU sub-OIDs]
        W5[Access denials: lattice over signer]
    end
    V1 --&amp;gt; W1
    V2 --&amp;gt; W4
    V3 --&amp;gt; W5

The DRM-to-credentials repurposing is not unique to PPL. The same pattern shows up in HVCI (originally a Hyper-V kernel-mode integrity feature, later repurposed for general code-integrity enforcement) and in Trustlets (originally an enterprise feature for Credential Guard, later generalised). Kernel mechanisms born in one threat model rarely stay confined to it.
&lt;p&gt;Microsoft already had the access-check primitive. What it didn&apos;t have, in 2007, was a way to ask &quot;how much trust does this process carry?&quot; The fix would not arrive until Windows 8.1 in October 2013, and when it arrived, it would fit in a single byte.&lt;/p&gt;
&lt;h2&gt;3. &lt;code&gt;_PS_PROTECTION&lt;/code&gt; -- The Single-Byte Encoding&lt;/h2&gt;
&lt;p&gt;The 8.1 fix is so compact it fits in a single byte. Ionescu&apos;s Part 1 of the &quot;Evolution of Protected Processes&quot; series, published November 22, 2013, gives the kernel structure verbatim [@ionescu-part1]:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct _PS_PROTECTION {
    union {
        UCHAR Level;
        struct {
            UCHAR Type   : 3;
            UCHAR Audit  : 1;
            UCHAR Signer : 4;
        };
    };
} PS_PROTECTION, *PPS_PROTECTION;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three fields. One byte. The union with &lt;code&gt;Level:UCHAR&lt;/code&gt; exists so that two &lt;code&gt;_PS_PROTECTION&lt;/code&gt; values can be compared with a single byte load and a single byte compare. The kernel does this on every &lt;code&gt;NtOpenProcess&lt;/code&gt;. Speed matters; this is the hot path of the security model.&lt;/p&gt;

The kernel structure that encodes a process&apos;s protection state in eight bits: three bits of Type (`None`, `ProtectedLight`, `Protected`), one bit of Audit (intended as a forensic side-channel hint, although the exact runtime semantics are not enumerated in the public sources cited here), and four bits of Signer rung. Stored as `EPROCESS.Protection`.
&lt;p&gt;The Type field has three values. &lt;code&gt;PsProtectedTypeNone = 0&lt;/code&gt; marks a regular process. &lt;code&gt;PsProtectedTypeProtectedLight = 1&lt;/code&gt; marks a PPL -- the graduated path introduced in 8.1. &lt;code&gt;PsProtectedTypeProtected = 2&lt;/code&gt; marks a &quot;heavy&quot; Vista-style PP. Heavy PPs still exist; they retain the original DRM semantics where almost nothing from below the protection level may touch them. PPLs are the new general-purpose path where the &lt;em&gt;signer rung&lt;/em&gt; mediates a graduated lattice.&lt;/p&gt;
&lt;p&gt;The Audit bit is the least documented of the three fields. Ionescu Part 1 lists it as &lt;code&gt;Audit : Pos 3, 1 Bit&lt;/code&gt; with no semantic gloss; itm4n&apos;s RunAsPPL header annotates it as &lt;code&gt;// Reserved&lt;/code&gt;; Microsoft Learn enumerates CodeIntegrity events &lt;code&gt;3033&lt;/code&gt;, &lt;code&gt;3063&lt;/code&gt;, &lt;code&gt;3065&lt;/code&gt;, and &lt;code&gt;3066&lt;/code&gt;, but those are triggered by the &lt;code&gt;AuditLevel&lt;/code&gt; configuration under &lt;code&gt;Image File Execution Options\LSASS.exe&lt;/code&gt; and concern DLL-load failures, not per-process &lt;code&gt;OpenProcess&lt;/code&gt; denials [@ionescu-part1] [@itm4n-runasppl] [@learn-runasppl]. The field&apos;s name implies a forensic side-channel, and the bit-position is reserved; the precise runtime emission shape is not enumerated in the public sources cited here.&lt;/p&gt;
&lt;p&gt;The Signer field is the structurally interesting one. Ionescu&apos;s 2013 enumeration names eight values [@ionescu-part1]:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signer constant&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Used for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerNone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Non-protected (no rung)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerAuthenticode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Generic third-party Authenticode (early PPL guests)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerCodeGen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;.NET native runtime code generators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerAntimalware&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;EDR / AV daemons admitted via ELAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerLsa&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsass.exe&lt;/code&gt; under &lt;code&gt;RunAsPPL&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerWindows&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Microsoft Windows components below TCB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerWinTcb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;csrss.exe&lt;/code&gt;, &lt;code&gt;smss.exe&lt;/code&gt;, &lt;code&gt;services.exe&lt;/code&gt; -- the inbox TCB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PsProtectedSignerMax&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Sentinel value (enumeration upper bound)&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; Ionescu&apos;s 2013 list is the authoritative &lt;em&gt;baseline&lt;/em&gt; enumeration. It is not a permanent enumeration. By 2018, James Forshaw&apos;s PowerShell tooling (&lt;code&gt;NtApiDotNet&lt;/code&gt;) was enumerating an additional &lt;code&gt;App = 8&lt;/code&gt; signer used for AppContainer / TruePlay scenarios [@forshaw-2018-10]. Newer builds of Windows extend the enumeration further. The article will name &lt;code&gt;WinTcb&lt;/code&gt; (Microsoft&apos;s documented inbox-TCB rung) and &lt;code&gt;Antimalware&lt;/code&gt; (the only non-Microsoft-admissible rung) repeatedly, because they are the load-bearing ones. The intermediate values evolve.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Adjacent to &lt;code&gt;EPROCESS.Protection&lt;/code&gt; are two related fields, &lt;code&gt;EPROCESS.SignatureLevel&lt;/code&gt; and &lt;code&gt;EPROCESS.SectionSignatureLevel&lt;/code&gt;, which Ionescu introduces in Part 3 [@ionescu-part3]. These fields encode the &lt;em&gt;binary integrity&lt;/em&gt; the kernel demands at process creation and at every subsequent section load, and they are filled in from a 16-entry Signing Level table that runs from &lt;code&gt;Unchecked = 0&lt;/code&gt; up to &lt;code&gt;Windows TCB = 14&lt;/code&gt;. The Signer rung in &lt;code&gt;Protection&lt;/code&gt; answers &quot;what kind of trust does this process hold?&quot; The SignatureLevel pair answers &quot;what binaries is this process allowed to map?&quot; They are not the same question.&lt;/p&gt;
&lt;p&gt;Now the worked decode. Given the byte value &lt;code&gt;0x41&lt;/code&gt;, the encoding falls out by hand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Low three bits (Type): &lt;code&gt;0x41 &amp;amp; 0x07 = 0x01&lt;/code&gt; -- &lt;code&gt;PsProtectedTypeProtectedLight&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bit 3 (Audit): &lt;code&gt;(0x41 &amp;gt;&amp;gt; 3) &amp;amp; 0x01 = 0&lt;/code&gt; -- Audit off.&lt;/li&gt;
&lt;li&gt;High four bits (Signer): &lt;code&gt;(0x41 &amp;gt;&amp;gt; 4) &amp;amp; 0x0F = 0x04&lt;/code&gt; -- &lt;code&gt;PsProtectedSignerLsa&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A process with &lt;code&gt;EPROCESS.Protection = 0x41&lt;/code&gt; is a PPL signed at the &lt;code&gt;Lsa&lt;/code&gt; rung. That is exactly what &lt;code&gt;lsass.exe&lt;/code&gt; looks like on a host with &lt;code&gt;RunAsPPL = 1&lt;/code&gt;. Ionescu&apos;s blog explicitly states: &quot;it&apos;s easy to read 0x41 as Lsa (0x4) + PPL (0x1)&quot; [@ionescu-part1]. The Defender service &lt;code&gt;MsMpEng.exe&lt;/code&gt;, signed at the Antimalware rung, has &lt;code&gt;Protection = 0x31&lt;/code&gt;. The session manager &lt;code&gt;csrss.exe&lt;/code&gt;, signed at WinTcb, has &lt;code&gt;Protection = 0x61&lt;/code&gt;.&lt;/p&gt;

flowchart TD
    B[byte: 8 bits]
    B --&amp;gt; F1[bits 0..2: Type]
    B --&amp;gt; F2[bit 3: Audit]
    B --&amp;gt; F3[bits 4..7: Signer]
    F1 --&amp;gt; T0[0 = None]
    F1 --&amp;gt; T1[1 = ProtectedLight PPL]
    F1 --&amp;gt; T2[2 = Protected PP]
    F3 --&amp;gt; S0[0 None]
    F3 --&amp;gt; S1[1 Authenticode]
    F3 --&amp;gt; S2[2 CodeGen]
    F3 --&amp;gt; S3[3 Antimalware]
    F3 --&amp;gt; S4[4 Lsa]
    F3 --&amp;gt; S5[5 Windows]
    F3 --&amp;gt; S6[6 WinTcb]
&lt;p&gt;{`
function decodeProtection(byteValue) {
  const type = byteValue &amp;amp; 0x07;
  const audit = (byteValue &amp;gt;&amp;gt; 3) &amp;amp; 0x01;
  const signer = (byteValue &amp;gt;&amp;gt; 4) &amp;amp; 0x0F;
  const typeNames = [&apos;None&apos;, &apos;ProtectedLight&apos;, &apos;Protected&apos;];
  const signerNames = [
    &apos;None&apos;, &apos;Authenticode&apos;, &apos;CodeGen&apos;, &apos;Antimalware&apos;,
    &apos;Lsa&apos;, &apos;Windows&apos;, &apos;WinTcb&apos;, &apos;Max&apos;
  ];
  return {
    raw: &apos;0x&apos; + byteValue.toString(16).padStart(2, &apos;0&apos;),
    type: typeNames[type] || &apos;unknown(&apos; + type + &apos;)&apos;,
    audit: audit ? &apos;on&apos; : &apos;off&apos;,
    signer: signerNames[signer] || &apos;unknown(&apos; + signer + &apos;)&apos;
  };
}&lt;/p&gt;
&lt;p&gt;// Worked examples from real Windows processes
console.log(&apos;MsMpEng.exe (Defender):&apos;, decodeProtection(0x31));
console.log(&apos;lsass.exe under RunAsPPL:&apos;, decodeProtection(0x41));
console.log(&apos;csrss.exe (WinTcb):&apos;, decodeProtection(0x61));
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; One byte, three fields, eight signer rungs. The kernel reads it on every &lt;code&gt;OpenProcess&lt;/code&gt;, before any token check, before any ACL evaluation. The encoding is the entire vocabulary the kernel has for asking &lt;em&gt;how trusted&lt;/em&gt; a process is.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The encoding tells the kernel &lt;em&gt;what kind&lt;/em&gt; of trust a process holds. It says nothing about &lt;em&gt;who can touch whom&lt;/em&gt; across rungs. That rule -- the lattice -- is the structure imposed on top of the bytes. The next section is the lattice.&lt;/p&gt;
&lt;h2&gt;4. The Signer Lattice -- Who Can Open Whom&lt;/h2&gt;
&lt;p&gt;itm4n&apos;s 2021 walkthrough states the three rules verbatim, and they have the rare quality of being short enough to memorise [@itm4n-scrt]:&lt;/p&gt;

A PP can open a PP or a PPL with full access if its signer type is greater or equal. A PPL can open a PPL with full access if its signer type is greater or equal. A PPL cannot open a PP with full access, regardless of its signer type.
&lt;p&gt;Three rules. They settle every cross-process access question PPL gates. Let us name them and then read off their consequences.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 1.&lt;/strong&gt; A PP at signer $S_c$ may open with full access a PP or PPL at signer $S_t$ if and only if $S_c \ge S_t$.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 2.&lt;/strong&gt; A PPL at signer $S_c$ may open with full access a PPL at signer $S_t$ if and only if $S_c \ge S_t$.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rule 3.&lt;/strong&gt; A PPL cannot open a PP with full access, regardless of signer.&lt;/p&gt;
&lt;p&gt;The qualifier &quot;with full access&quot; is load-bearing. PPL&apos;s lattice gates the &lt;em&gt;full&lt;/em&gt; mask -- &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;, &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, &lt;code&gt;PROCESS_CREATE_THREAD&lt;/code&gt;, &lt;code&gt;PROCESS_DUP_HANDLE&lt;/code&gt;, &lt;code&gt;PROCESS_ALL_ACCESS&lt;/code&gt;. A separate &lt;em&gt;limited&lt;/em&gt; mask (&lt;code&gt;SYNCHRONIZE&lt;/code&gt;, &lt;code&gt;PROCESS_QUERY_LIMITED_INFORMATION&lt;/code&gt;, &lt;code&gt;PROCESS_SET_LIMITED_INFORMATION&lt;/code&gt;, &lt;code&gt;PROCESS_SUSPEND_RESUME&lt;/code&gt;, and -- for callers below the &lt;code&gt;Authenticode&lt;/code&gt;/&lt;code&gt;CodeGen&lt;/code&gt;/&lt;code&gt;Windows&lt;/code&gt; tier -- &lt;code&gt;PROCESS_TERMINATE&lt;/code&gt;) is allowed when the security descriptor permits. The tier matters. Ionescu&apos;s verbatim &lt;code&gt;RtlProtectedAccess[]&lt;/code&gt; table widens the deny mask from &lt;code&gt;0xFC7FE&lt;/code&gt; to &lt;code&gt;0xFC7FF&lt;/code&gt; at the &lt;code&gt;Antimalware&lt;/code&gt;, &lt;code&gt;Lsa&lt;/code&gt;, and &lt;code&gt;WinTcb&lt;/code&gt; rungs -- one extra bit, bit 0, which is &lt;code&gt;PROCESS_TERMINATE&lt;/code&gt; [@ionescu-part2]. So an administrator can still call &lt;code&gt;OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, ...)&lt;/code&gt; against a protected &lt;code&gt;lsass.exe&lt;/code&gt; to enumerate threads, but cannot terminate a &lt;code&gt;PPL/Antimalware&lt;/code&gt;, &lt;code&gt;PPL/Lsa&lt;/code&gt;, or &lt;code&gt;PPL/WinTcb&lt;/code&gt; daemon via a direct kill. The lattice does not lock the process; it locks the &lt;em&gt;interesting&lt;/em&gt; access, and for the top-tier rungs it also locks the kill.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Caller signer \ Target signer&lt;/th&gt;
&lt;th&gt;None&lt;/th&gt;
&lt;th&gt;Authenticode (1)&lt;/th&gt;
&lt;th&gt;Antimalware (3)&lt;/th&gt;
&lt;th&gt;Lsa (4)&lt;/th&gt;
&lt;th&gt;Windows (5)&lt;/th&gt;
&lt;th&gt;WinTcb (6)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;None (admin, integrity SYSTEM)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/Authenticode (1)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/Antimalware (3)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/Lsa (4)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/Windows (5)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/WinTcb (6)&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;td&gt;full&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Where &quot;denied&quot; means the &lt;em&gt;full&lt;/em&gt; mask is rejected; the limited mask continues to apply per the target&apos;s security descriptor.&lt;/p&gt;

flowchart BT
    None[None / unprotected]
    Auth[Authenticode]
    CG[CodeGen]
    AM[Antimalware]
    Lsa[Lsa]
    Win[Windows]
    Tcb[WinTcb]
    None --&amp;gt; Auth
    Auth --&amp;gt; CG
    CG --&amp;gt; AM
    AM --&amp;gt; Lsa
    Lsa --&amp;gt; Win
    Win --&amp;gt; Tcb
&lt;p&gt;The Enhanced Key Usage side of the design holds the lattice together. Microsoft&apos;s EKU OID arc &lt;code&gt;1.3.6.1.4.1.311.10.3.*&lt;/code&gt; defines sub-OIDs per signer rung [@iana-pen311] [@oid-base-eku-arc], and at process creation the kernel parses the main image&apos;s Authenticode signature and walks its EKU extensions to determine which rung the binary is entitled to claim. If the certificate chain resolves cleanly to a Microsoft-issued root &lt;em&gt;and&lt;/em&gt; carries the rung&apos;s sub-OID, the kernel records the rung. Otherwise the process either starts unprotected or refuses to start at all.&lt;/p&gt;

An X.509 v3 certificate extension that asserts what specific purposes a certificate is allowed to certify. Microsoft uses sub-OIDs under `1.3.6.1.4.1.311.10.3.*` to encode protected-process signer rungs as EKU values [@iana-pen311] [@oid-base-eku-arc]. The kernel checks the EKU at process creation; the certificate chain anchors which Microsoft-issued sub-CA may issue at each rung.The IANA Private Enterprise Number `311` is registered to Microsoft under the PEN prefix `1.3.6.1.4.1.` [@iana-pen311], so `1.3.6.1.4.1.311.*` is the catch-all namespace for Microsoft-specific X.509 extensions; the `10.3.*` arc within it is the Microsoft Enhanced Key Usage (purpose) sub-tree [@oid-base-eku-arc], and `10.3.` slots map to specific signer purposes including protected-process rungs.
&lt;p&gt;The most important property of this design is the resolution point. The kernel parses the EKU exactly once, at &lt;code&gt;NtCreateUserProcess&lt;/code&gt;. It stores the resulting rung in &lt;code&gt;EPROCESS.Protection&lt;/code&gt;. On every subsequent &lt;code&gt;OpenProcess&lt;/code&gt; against that process, the kernel consults the byte, not the certificate. This makes the access check fast (one byte load, one byte compare) and decouples policy at runtime from policy at signing time. It also creates the structural seam that every public bypass since 2018 has exploited, because the kernel&apos;s confidence in the byte is exactly the confidence it had in the certificate at process-create time, projected forward indefinitely.&lt;/p&gt;
&lt;p&gt;Ionescu&apos;s Part 2 names the implementation directly. The lattice is not code; it is a data table named &lt;code&gt;RtlProtectedAccess[]&lt;/code&gt; baked into &lt;code&gt;ntoskrnl.exe&lt;/code&gt; [@ionescu-part2]. Each row of that table corresponds to a (signer, target-type) pair and encodes which access bits are allowed in the full mask. The relevant runtime routines are &lt;code&gt;PspProcessOpen&lt;/code&gt; and &lt;code&gt;PspThreadOpen&lt;/code&gt; (the object-manager open callbacks), &lt;code&gt;PspCheckForInvalidAccessByProtection&lt;/code&gt; (which performs the check), &lt;code&gt;RtlTestProtectedAccess&lt;/code&gt; (which applies the lattice row), and &lt;code&gt;RtlValidProtectionLevel&lt;/code&gt; (which sanity-checks the encoded byte for consistency).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The decision of who can touch whom is encoded in a table inside &lt;code&gt;ntoskrnl.exe&lt;/code&gt;. Changing the lattice means changing a table; widening or narrowing it does not require new code. This is why Microsoft can add &lt;code&gt;App = 8&lt;/code&gt; to the enumeration over time without touching the access-check routine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note one symmetry that becomes important later. &quot;Greater or equal&quot; means that within a rung, every PPL can read every other PPL. Two co-resident &lt;code&gt;PPL/Antimalware&lt;/code&gt; daemons -- Microsoft Defender&apos;s &lt;code&gt;MsMpEng.exe&lt;/code&gt; and a third-party EDR&apos;s agent -- can call &lt;code&gt;PROCESS_VM_READ&lt;/code&gt; on each other. Within-rung peers leak to each other by design. The lattice prevents &lt;em&gt;escalation&lt;/em&gt;, not &lt;em&gt;peer access&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The lattice settles the rule. The next question is admission: who decides which binaries are allowed to claim the Antimalware rung, and how does Microsoft admit third-party code into it at all? The answer is a driver.&lt;/p&gt;
&lt;h2&gt;5. The Antimalware Rung -- ELAM and Third-Party Code at PPL&lt;/h2&gt;
&lt;p&gt;PPL is interesting only if it admits non-Microsoft code at &lt;em&gt;some&lt;/em&gt; rung. The Vista PP design admitted nobody; it required a Microsoft PMP root certificate, full stop. PPL inherited that constraint at every rung except one. The Antimalware rung -- signer value &lt;code&gt;3&lt;/code&gt; -- is the only rung where third-party vendors can ship their own user-mode binaries as protected processes. The admission mechanism is the Early Launch Anti-Malware driver.&lt;/p&gt;

A specially signed Microsoft-certified kernel driver shipped by an anti-malware vendor that loads before any other boot-start driver. The ELAM driver participates in trusted-boot measurement, vouches for follow-on drivers, and -- critical to PPL -- carries an embedded resource section enumerating the vendor&apos;s user-mode signing certificate hashes. The kernel uses that resource section to admit the vendor&apos;s user-mode daemon binaries to `PPL/Antimalware` at service start.
&lt;p&gt;Microsoft Learn&apos;s &quot;Protecting Anti-Malware Services&quot; page describes the boot-time admission flow in two sentences [@learn-am-services]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The driver must have an embedded resource section containing the information of the certificates used to sign the user mode service binaries. During the boot process, this resource section will be extracted from the ELAM driver to validate the certificate information and register the anti-malware service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two consequences. First, the third-party signer set is bounded by a &lt;em&gt;kernel-readable resource section&lt;/em&gt;, not by an open EKU. Microsoft, not the vendor, controls which user-mode binaries are admissible. Second, the certificate hashes are baked into the driver at signing time and re-validated at every service start. A vendor cannot widen the admissible set after the fact; an attacker cannot drop in their own user-mode binary unless its hash is already listed.&lt;/p&gt;
&lt;p&gt;The gate that decides which vendors get ELAM drivers in the first place is the Microsoft Virus Initiative. Microsoft Learn&apos;s MVI criteria page enumerates the requirement explicitly [@learn-mvi]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your security solution must be certified within the last 12 months by at least one of the organizations listed below: AV-Comparatives, AVLab Cybersecurity Foundation, AV-Test, MRG Effitas, SE Labs, SKD Labs, VB 100, West Coast Labs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The same page requires &quot;use of Trusted Signing,&quot; Microsoft&apos;s cloud-managed code signing service. The implications are operational. To ship code at &lt;code&gt;PPL/Antimalware&lt;/code&gt;, a vendor must (a) hold MVI membership, (b) maintain independent-lab certification, (c) author an ELAM driver, (d) get the driver through Microsoft WHQL and have it Microsoft co-signed, and (e) embed the user-mode certificate hashes in the driver&apos;s resource section.&lt;/p&gt;

A Microsoft program for anti-malware vendors that gates access to ELAM driver signing and to specific Defender APIs. Membership requires independent-lab certification (renewed annually) and Trusted Signing usage; in practical terms, MVI membership is the entry ticket to deploying user-mode binaries at `PPL/Antimalware`.

The implication of MVI is that an indie security tool, however technically sound, cannot deploy as `PPL/Antimalware`. The gate is not technical but commercial: independent-lab certification fees, annual renewals, and the engineering investment of building a production-grade ELAM driver. The signer rung is *signed*; the signing program is *gated*.

sequenceDiagram
    participant BM as Boot manager
    participant K as Windows kernel
    participant ELAM as Vendor ELAM driver (.sys)
    participant SCM as Service Control Manager
    participant CI as ci.dll (CodeIntegrity)
    participant Svc as Vendor service (e.g. EDR daemon)
    BM-&amp;gt;&amp;gt;K: load boot drivers
    K-&amp;gt;&amp;gt;ELAM: load ELAM driver early
    K-&amp;gt;&amp;gt;ELAM: read embedded ELAM resource section
    K-&amp;gt;&amp;gt;K: cache vendor user-mode cert hashes
    Note over K,SCM: Boot continues, OS initialises
    SCM-&amp;gt;&amp;gt;Svc: start vendor service
    Svc-&amp;gt;&amp;gt;CI: validate service binary signature
    CI-&amp;gt;&amp;gt;K: lookup vendor cert against cached hashes
    K--&amp;gt;&amp;gt;CI: match -- admit at PPL/Antimalware
    CI--&amp;gt;&amp;gt;Svc: launch as PPL/Antimalware (Protection = 0x31)
&lt;p&gt;By 2024, every major commercial EDR ships through this path. Microsoft Defender&apos;s &lt;code&gt;MsMpEng.exe&lt;/code&gt; uses the inbox &lt;code&gt;WdBoot.sys&lt;/code&gt; ELAM driver&lt;code&gt;WdBoot.sys&lt;/code&gt; (&quot;Windows Defender Boot Driver&quot;) is Microsoft&apos;s inbox first-party ELAM driver; it ships in every Windows install and is loaded before any third-party ELAM driver. The canonical reference implementation of the ELAM resource-section pattern is Microsoft&apos;s &lt;code&gt;Windows-driver-samples/security/elam&lt;/code&gt; repository [@ms-elam-sample], which also documents the Early Launch EKU &lt;code&gt;1.3.6.1.4.1.311.61.4.1&lt;/code&gt; verbatim.. Third-party members of Microsoft&apos;s Virus Initiative -- the cohort gated by the MVI criteria quoted above [@learn-mvi] -- ship their own vendor ELAM drivers and run their main user-mode daemons at &lt;code&gt;PPL/Antimalware&lt;/code&gt;. Microsoft Learn&apos;s &quot;Early Launch Antimalware&quot; page is the canonical confirmation [@learn-elam]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because an ELAM service runs as a PPL (Protected Process Light), you need to debug using a kernel debugger.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One Microsoft-signed sentence and a billion endpoints. EDR vendors get protection against administrator-level tampering for free, on top of the kernel telemetry their drivers already collect. Microsoft gets a viable third-party security market without widening the EKU gates beyond a controllable set of vendors.&lt;/p&gt;
&lt;p&gt;ELAM admits the &lt;em&gt;daemon&lt;/em&gt;. The next operational question is what Microsoft does for &lt;code&gt;lsass.exe&lt;/code&gt; itself -- the canonical credential store, the original Mimikatz target. The mechanism is called &lt;code&gt;RunAsPPL&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;6. RunAsPPL -- Hardening LSASS&lt;/h2&gt;
&lt;p&gt;The registry value that produced the Mimikatz failure in Section 1 is a single DWORD. itm4n&apos;s walkthrough names it verbatim [@itm4n-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open the key &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa&lt;/code&gt;; add the DWORD value &lt;code&gt;RunAsPPL&lt;/code&gt; and set it to 1; reboot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After reboot, &lt;code&gt;lsass.exe&lt;/code&gt; launches at &lt;code&gt;PPL/Lsa&lt;/code&gt;, signer rung 4, protection byte &lt;code&gt;0x41&lt;/code&gt;. Mimikatz running with full SYSTEM-integrity and &lt;code&gt;SeDebugPrivilege&lt;/code&gt; then receives &lt;code&gt;0x00000005&lt;/code&gt; on &lt;code&gt;OpenProcess(PROCESS_VM_READ, lsass.exe)&lt;/code&gt;. The registry knob is one DWORD; the consequences are large.&lt;/p&gt;

The Windows user-mode process that holds NTLM password hashes, Kerberos Ticket Granting Tickets, MSV1_0 credential caches, DPAPI master keys, and (on legacy builds before Microsoft&apos;s 2014 KB2871997 update [@ms-kb2871997]) WDigest plaintext passwords. The canonical target of credential-theft tooling since 2011.
&lt;p&gt;The threat being mitigated is simple. Mimikatz reads LSASS memory via &lt;code&gt;OpenProcess(PROCESS_VM_READ, lsass.exe)&lt;/code&gt;, walks the internal key-store structures, and extracts NTLM hashes, Kerberos session keys, and (on older configurations) cached plaintext. Restricting &lt;code&gt;SeDebugPrivilege&lt;/code&gt; does not work, because an attacker with SYSTEM has every privilege. Restricting the security descriptor on &lt;code&gt;lsass.exe&lt;/code&gt; does not work either, because legitimate services need to interact with it. PPL is the right primitive: it gates the &lt;em&gt;full&lt;/em&gt; mask irrespective of token state, and the kernel admits only Microsoft-signed code into the &lt;code&gt;Lsa&lt;/code&gt; rung.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RunAsPPL = 1&lt;/code&gt; is the stronger form of the setting on Secure Boot-capable machines. On the next boot, the kernel automatically mirrors the policy into a Secure Boot-anchored UEFI variable; once set, the protection survives registry rollback. An attacker who removes the registry key finds that LSASS still launches as PPL on the next boot. The only path to remove the protection is to disable Secure Boot at the firmware level, which requires physical access and which trips other defences. Microsoft Learn&apos;s documentation describes it verbatim [@learn-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can achieve further protection when you use Unified Extensible Firmware Interface (UEFI) lock and Secure Boot. When these settings are enabled, disabling the &lt;code&gt;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa&lt;/code&gt; registry key has no effect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is &lt;code&gt;RunAsPPL = 1&lt;/code&gt;. For environments that need admin-removable protection without the UEFI lock, &lt;code&gt;RunAsPPL = 2&lt;/code&gt; (available on Win11 22H2 and later) omits the UEFI variable. The policy lives in the registry only and is removable by any administrator (or by malware running as administrator) who simply deletes the registry value before reboot.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;RunAsPPL&lt;/code&gt; value&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;th&gt;Removable by?&lt;/th&gt;
&lt;th&gt;Persistence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt; (or absent)&lt;/td&gt;
&lt;td&gt;LSASS runs unprotected&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LSASS runs as PPL/Lsa; policy mirrored to UEFI variable on Secure Boot machines&lt;/td&gt;
&lt;td&gt;Physical access + Secure Boot disable&lt;/td&gt;
&lt;td&gt;Firmware-anchored&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LSASS runs as PPL/Lsa; registry only (Win11 22H2+ only)&lt;/td&gt;
&lt;td&gt;Any admin who deletes the key&lt;/td&gt;
&lt;td&gt;Registry only&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; The &lt;code&gt;RunAsPPL = 1&lt;/code&gt; setting is the practical answer to &quot;what stops an attacker who is willing to reboot?&quot; Once the UEFI variable is set, neither registry rollback nor PE-based offline attacks on the registry hive can disable LSA protection on the next boot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The deployment cost of &lt;code&gt;RunAsPPL&lt;/code&gt; is compatibility with third-party authentication modules. LSASS hosts a set of plug-ins: smart-card middleware, third-party Cryptographic Service Providers (CSPs), password-filter DLLs, alternative authentication packages. Under &lt;code&gt;RunAsPPL&lt;/code&gt;, the kernel demands that every DLL loaded into LSASS be Microsoft-signed at the LSA level (signer rung 4). Vendor DLLs that lack the right EKU are rejected at section creation. The rejections surface as CodeIntegrity events in the system event log. Microsoft Learn enumerates the two relevant event IDs [@learn-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Event 3065 occurs when a code integrity check determines that a process, usually LSASS.exe, attempts to load a driver that doesn&apos;t meet the security requirements for shared sections.&lt;/p&gt;
&lt;p&gt;Event 3066 occurs when a code integrity check determines that a process, usually LSASS.exe, attempts to load a driver that doesn&apos;t meet the Microsoft signing level requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is why Microsoft recommends running the setting in &lt;em&gt;audit mode&lt;/em&gt; before enforcement. Audit mode is enabled by setting a separate &lt;code&gt;AuditLevel&lt;/code&gt; DWORD to &lt;code&gt;8&lt;/code&gt;, but -- critically -- under a &lt;em&gt;different&lt;/em&gt; registry key from the one that hosts &lt;code&gt;RunAsPPL&lt;/code&gt;. Microsoft Learn places &lt;code&gt;AuditLevel&lt;/code&gt; under the Image File Execution Options hive for &lt;code&gt;LSASS.exe&lt;/code&gt; and names the path verbatim [@learn-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open the Registry Editor, or enter RegEdit.exe in the Run dialog, and then go to the &lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LSASS.exe&lt;/code&gt; registry key. Open the &lt;code&gt;AuditLevel&lt;/code&gt; value. Set its data type to &lt;code&gt;dword&lt;/code&gt; and its data value to &lt;code&gt;00000008&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;RunAsPPL&lt;/code&gt; sits under &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa&lt;/code&gt;. &lt;code&gt;AuditLevel = 8&lt;/code&gt; sits under &lt;code&gt;HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LSASS.exe&lt;/code&gt;. A defender who edits &quot;the same key&quot; silently sets the wrong value and audit mode never engages. The deployment looks correct from the registry; the log surface is empty; the rollout breaks production on enforcement day. Two values. Two hives. Read this twice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In audit mode, the kernel emits the same 3065 / 3066 events for would-be load rejections but allows the loads to proceed. Two months of audit-mode telemetry typically surfaces every smart-card middleware DLL, every password-filter, every third-party CSP on a corporate fleet. Once the audit log is clean (every vendor&apos;s modules have been re-signed at the LSA level or replaced), enforcement mode can be turned on without breaking production logins.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Skipping audit mode is the most common cause of LSA protection rollouts being rolled back after a wave of authentication failures. See §11 Item 1 for the full audit-then-enforce-then-UEFI-lock recipe.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The deployment cadence has been deliberately glacial. &lt;code&gt;RunAsPPL&lt;/code&gt; shipped in Windows 8.1 in October 2013 -- &lt;em&gt;opt-in&lt;/em&gt;. It remained opt-in for nine years. Microsoft Learn records the inflection [@learn-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Audit mode for added LSA protection is enabled by default on devices running Windows 11 version 22H2 and later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Audit mode default-on. Not enforcement. The Windows 11 24H2 release expanded the audit-mode rollout further. Eleven years from opt-in to effective default. The pace reflects the compatibility risk: every domain with a single non-Microsoft-signed LSASS plug-in would have surfaced as a support call.&lt;/p&gt;
&lt;p&gt;The registry knob is simple. The &lt;em&gt;kernel&lt;/em&gt; check that enforces it is not. The next section walks the access-check pipeline in detail, because the structural reason &lt;code&gt;SeDebugPrivilege&lt;/code&gt; cannot help an attacker is the order in which the kernel asks its questions.&lt;/p&gt;
&lt;h2&gt;7. The Kernel Access Check -- What Happens Inside &lt;code&gt;NtOpenProcess&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Recall the trace from Section 1. The denial happens before &lt;code&gt;SeAccessCheck&lt;/code&gt; runs. The reason &lt;code&gt;SeDebugPrivilege&lt;/code&gt; does not help is not that the kernel decided to override the privilege; it is that the kernel never asked about the privilege. The order matters. Let us walk it.&lt;/p&gt;
&lt;p&gt;The Win32 caller invokes &lt;code&gt;OpenProcess&lt;/code&gt;, which thunks through &lt;code&gt;kernel32.dll&lt;/code&gt; to the syscall &lt;code&gt;NtOpenProcess&lt;/code&gt;. &lt;code&gt;NtOpenProcess&lt;/code&gt; does its handle-lookup and dispatches to the process-type object-manager open callback, &lt;code&gt;PspProcessOpen&lt;/code&gt;. Ionescu&apos;s Part 2 names the path verbatim [@ionescu-part2]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Access to protected processes (and their threads) is gated by the &lt;code&gt;PspProcessOpen&lt;/code&gt; and &lt;code&gt;PspThreadOpen&lt;/code&gt; object manager callback routines, which perform two checks. The first, done by calling &lt;code&gt;PspCheckForInvalidAccessByProtection&lt;/code&gt; (which in turn calls &lt;code&gt;RtlTestProtectedAccess&lt;/code&gt; and &lt;code&gt;RtlValidProtectionLevel&lt;/code&gt;) ...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;PspCheckForInvalidAccessByProtection&lt;/code&gt; does two things. First, it splits the caller&apos;s requested access mask into two subsets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;limited mask&lt;/strong&gt; -- a fixed set of bits (&lt;code&gt;SYNCHRONIZE&lt;/code&gt;, &lt;code&gt;PROCESS_QUERY_LIMITED_INFORMATION&lt;/code&gt;, and a small handful of others) that the lattice never forbids. The limited mask is subject only to the standard &lt;code&gt;SeAccessCheck&lt;/code&gt; against the target&apos;s DACL.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;full mask&lt;/strong&gt; -- everything else, including &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;, &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, &lt;code&gt;PROCESS_CREATE_THREAD&lt;/code&gt;, &lt;code&gt;PROCESS_DUP_HANDLE&lt;/code&gt;, and &lt;code&gt;PROCESS_ALL_ACCESS&lt;/code&gt;. The full mask is subject to the lattice rule.&lt;/li&gt;
&lt;/ul&gt;

The subset of `PROCESS_*` access rights that the PPL lattice always allows the standard `SeAccessCheck` to evaluate. Includes `SYNCHRONIZE`, `PROCESS_QUERY_LIMITED_INFORMATION`, `PROCESS_SET_LIMITED_INFORMATION`, and `PROCESS_SUSPEND_RESUME`. `PROCESS_TERMINATE` is included for callers below the Antimalware tier (deny mask `0xFC7FE`), but the kernel widens the deny mask to `0xFC7FF` at the `Antimalware`, `Lsa`, and `WinTcb` rungs -- bit 0, `PROCESS_TERMINATE` -- making those three rungs unkillable except from peers or higher.
&lt;p&gt;Second, it indexes into &lt;code&gt;RtlProtectedAccess[]&lt;/code&gt; using the caller&apos;s signer rung and the target&apos;s type, retrieves the row of permissible access bits, and ANDs the row with the full mask. If the result is non-empty, the access proceeds; if the result is zero, the kernel strips the full-mask bits from the request and returns either the limited subset (if the caller asked for any limited bits) or &lt;code&gt;STATUS_ACCESS_DENIED&lt;/code&gt;. &lt;code&gt;RtlValidProtectionLevel&lt;/code&gt; runs alongside as a sanity check on the encoded byte to catch malformed &lt;code&gt;EPROCESS.Protection&lt;/code&gt; values that would otherwise let the lattice walk off the end of the table.&lt;/p&gt;

sequenceDiagram
    participant App as Caller (any token)
    participant Nt as NtOpenProcess
    participant PsPO as PspProcessOpen
    participant Chk as PspCheckForInvalidAccessByProtection
    participant Rtl as RtlTestProtectedAccess + RtlValidProtectionLevel
    participant Tab as RtlProtectedAccess[] table
    participant SAC as SeAccessCheck
    App-&amp;gt;&amp;gt;Nt: NtOpenProcess(DesiredAccess)
    Nt-&amp;gt;&amp;gt;PsPO: dispatch
    PsPO-&amp;gt;&amp;gt;Chk: protection check
    Chk-&amp;gt;&amp;gt;Rtl: lookup caller / target rungs
    Rtl-&amp;gt;&amp;gt;Tab: index row, retrieve allowed bits
    Tab--&amp;gt;&amp;gt;Rtl: row of allowed access bits
    Rtl--&amp;gt;&amp;gt;Chk: full mask allowed or stripped
    Chk--&amp;gt;&amp;gt;PsPO: residual mask (full or limited)
    PsPO-&amp;gt;&amp;gt;SAC: residual mask vs DACL + token
    SAC--&amp;gt;&amp;gt;Nt: final mask
    Nt--&amp;gt;&amp;gt;App: handle or STATUS_ACCESS_DENIED
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The protection check runs &lt;em&gt;before&lt;/em&gt; &lt;code&gt;SeAccessCheck&lt;/code&gt;. Privileges are evaluated by &lt;code&gt;SeAccessCheck&lt;/code&gt;. The reason &lt;code&gt;SeDebugPrivilege&lt;/code&gt; does not help is structural -- it is not consulted at the moment of denial.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Four worked traces make this concrete.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case (a): admin -&amp;gt; lsass with &lt;code&gt;PROCESS_ALL_ACCESS&lt;/code&gt;.&lt;/strong&gt; The caller has no &lt;code&gt;EPROCESS.Protection.Type&lt;/code&gt; (it is &lt;code&gt;None&lt;/code&gt;). The target is &lt;code&gt;PPL/Lsa&lt;/code&gt;. The lattice forbids the full mask. The kernel strips every bit of &lt;code&gt;PROCESS_ALL_ACCESS&lt;/code&gt; except the limited subset. The caller wanted to write memory; the limited subset cannot write memory; the operation effectively fails. This is the Mimikatz scenario.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case (b): admin -&amp;gt; lsass with &lt;code&gt;PROCESS_QUERY_LIMITED_INFORMATION&lt;/code&gt;.&lt;/strong&gt; Same caller, same target, but the requested mask sits entirely in the limited subset. The lattice does not gate the limited mask. &lt;code&gt;SeAccessCheck&lt;/code&gt; evaluates the DACL on &lt;code&gt;lsass.exe&lt;/code&gt;, finds that administrators are permitted to query basic process information, and the call succeeds. This is why Process Explorer can still enumerate &lt;code&gt;lsass.exe&lt;/code&gt; and show its threads even when LSA protection is enabled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case (c): &lt;code&gt;MsMpEng.exe&lt;/code&gt; (PPL/Antimalware, rung 3) -&amp;gt; &lt;code&gt;lsass.exe&lt;/code&gt; (PPL/Lsa, rung 4) with &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;.&lt;/strong&gt; The lattice rule: caller rung 3 &amp;lt; target rung 4, so the full mask is denied. Defender cannot read LSASS memory. Defender does not need to; the cross-rung isolation prevents one Microsoft service from reading another Microsoft service&apos;s secrets even within the same trusted system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case (d): hypothetical &lt;code&gt;PPL/WinTcb&lt;/code&gt; (rung 6) -&amp;gt; &lt;code&gt;lsass.exe&lt;/code&gt; (PPL/Lsa, rung 4) with &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;.&lt;/strong&gt; The lattice rule: caller rung 6 &amp;gt;= target rung 4, so the full mask is allowed. A process signed at the WinTcb rung can read LSASS memory by design. This is how Service Control Manager and Windows Error Reporting can still interact with protected &lt;code&gt;lsass.exe&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Caller&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Mask&lt;/th&gt;
&lt;th&gt;Lattice rule&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Admin, no Protection&lt;/td&gt;
&lt;td&gt;PPL/Lsa&lt;/td&gt;
&lt;td&gt;PROCESS_ALL_ACCESS&lt;/td&gt;
&lt;td&gt;Caller has no rung&lt;/td&gt;
&lt;td&gt;Full mask stripped (denied)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin, no Protection&lt;/td&gt;
&lt;td&gt;PPL/Lsa&lt;/td&gt;
&lt;td&gt;PROCESS_QUERY_LIMITED_INFORMATION&lt;/td&gt;
&lt;td&gt;Limited mask&lt;/td&gt;
&lt;td&gt;Allowed (DACL permitting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/Antimalware (3)&lt;/td&gt;
&lt;td&gt;PPL/Lsa (4)&lt;/td&gt;
&lt;td&gt;PROCESS_VM_READ&lt;/td&gt;
&lt;td&gt;3 &amp;lt; 4&lt;/td&gt;
&lt;td&gt;Denied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPL/WinTcb (6)&lt;/td&gt;
&lt;td&gt;PPL/Lsa (4)&lt;/td&gt;
&lt;td&gt;PROCESS_VM_READ&lt;/td&gt;
&lt;td&gt;6 &amp;gt;= 4&lt;/td&gt;
&lt;td&gt;Allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Audit bit revisits the table from a different angle. The bit is annotated &lt;code&gt;Reserved&lt;/code&gt; in itm4n&apos;s public structure definition and named without semantic gloss in Ionescu Part 1; the precise runtime emission shape on an &lt;code&gt;OpenProcess&lt;/code&gt; denial is not enumerated in any of Ionescu Part 1, Forshaw 2018, itm4n&apos;s RunAsPPL writeup, or Microsoft Learn&apos;s RunAsPPL page (whose CodeIntegrity events 3033/3063/3065/3066 are scoped to &lt;code&gt;AuditLevel&lt;/code&gt; under &lt;code&gt;IFEO\LSASS.exe&lt;/code&gt; and to DLL-load failures, not per-process Audit-bit denials) [@ionescu-part1] [@itm4n-runasppl] [@learn-runasppl]. The field name and bit position imply a forensic side-channel; the exact event shape is not in the public record.Two adjacent kernel mechanisms exist in the same neighbourhood but mediate different threat models. &lt;code&gt;PROCESS_TRUST_LABEL_ACE&lt;/code&gt; (a Trust SID ACL entry, introduced in Windows 8.1 alongside PPL) is an ACL-side companion that runs &lt;em&gt;inside&lt;/em&gt; &lt;code&gt;SeAccessCheck&lt;/code&gt; -- it adds a token-style trust label that interacts with the security descriptor in the standard way. Code Integrity Guard (&lt;code&gt;ProcessSignaturePolicy&lt;/code&gt;) is a per-process &lt;em&gt;signed-image&lt;/em&gt; enforcer settable at &lt;code&gt;CreateProcess&lt;/code&gt; time via the &lt;code&gt;PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY&lt;/code&gt; attribute. Neither is part of PPL; both interact with the same problem space.&lt;/p&gt;
&lt;p&gt;The kernel verifies who is asking, what they are asking for, and at what rung the target sits. What the kernel &lt;em&gt;cannot&lt;/em&gt; verify is the behaviour of code that arrives through a signed channel and then executes against attacker-controlled data. That structural seam is the entire premise of the bypass arms race, and it is the next section.&lt;/p&gt;
&lt;h2&gt;8. The Bypass Arms Race -- Forshaw, itm4n, Landau&lt;/h2&gt;
&lt;p&gt;If the kernel only verifies the channel by which code enters a PPL, every bypass should attack the seam between channel and behaviour. Test that prediction against the public record. Since 2018, four named bypass acts have hit major Microsoft research blogs. All four sit in the same structural class.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The kernel verifies the channel. It does not verify the behaviour. Every public PPL bypass since 2018 attacks the seam between what the channel proves (a signature, an EKU, a section identity) and what the code does once mapped.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Act I (2018) -- Forshaw and JScript-into-PPL&lt;/h3&gt;
&lt;p&gt;James Forshaw, then at Google Project Zero, published &quot;Injecting Code into Windows Protected Processes Using COM&quot; in October 2018 [@forshaw-2018-10]. The mechanism: a PPL can be made to instantiate a COM object whose CLSID resolves to &lt;code&gt;scrobj.dll&lt;/code&gt;, the Microsoft-signed Windows Script Component scripting host. Once loaded into the PPL, the script object accepts attacker-supplied source code and executes it inside the protected process. The DLL is signed. The kernel admits it. The kernel cannot reason about the JScript source it then runs.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s fix in Windows 10 1803 (April 2018, deployed broadly through that year) was a hardcoded deny-list in &lt;code&gt;CI.DLL&lt;/code&gt;. Forshaw&apos;s own writeup gives the source verbatim [@forshaw-2018-10]:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;UNICODE_STRING g_BlockedDllsForPPL[] = {
    DECLARE_USTR(&quot;scrobj.dll&quot;),
    DECLARE_USTR(&quot;scrrun.dll&quot;),
    DECLARE_USTR(&quot;jscript.dll&quot;),
    DECLARE_USTR(&quot;jscript9.dll&quot;),
    DECLARE_USTR(&quot;vbscript.dll&quot;)
};

NTSTATUS CipMitigatePPLBypassThroughInterpreters(
    PEPROCESS Process, LPBYTE Image, SIZE_T ImageSize)
{
    if (!PsIsProtectedProcess(Process)) return STATUS_SUCCESS;
    // walk g_BlockedDllsForPPL; if any match, return STATUS_DYNAMIC_CODE_BLOCKED
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Five DLLs, hardcoded. Microsoft Learn corroborates the policy on the user-facing side [@learn-am-services]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The following scripting DLLs are forbidden by CodeIntegrity inside a protected process: scrobj.dll, scrrun.dll, jscript.dll, jscript9.dll, and vbscript.dll.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Channel: a Microsoft-signed DLL. Behaviour: arbitrary attacker script. The fix narrows the channel by name-listing the five DLLs known to admit attacker behaviour. The class survives.The mechanism was previewed at Recon Montreal 2018 in the joint Forshaw-Ionescu talk &quot;Unknown Known DLLs and other Code Integrity Trust Violations&quot; (June 15-17, 2018) [@recon-mtl-2018]. Forshaw&apos;s August 2017 &quot;Bypassing VirtualBox Process Hardening&quot; essay [@forshaw-2017-vbox] is the structural precursor -- it makes the same channel-vs-behaviour argument against a different kernel-supported process-hardening regime.&lt;/p&gt;
&lt;h3&gt;Act II (2018-2021) -- DefineDosDevice and PPLdump&lt;/h3&gt;
&lt;p&gt;In his August 2018 post on object-directory exploits [@forshaw-2018-08], Forshaw added a single throwaway sentence that the security community would spend three years productising. itm4n quotes it verbatim in his 2021 SCRT walkthrough [@itm4n-scrt]:&lt;/p&gt;

Abusing the DefineDosDevice API actually has a second use, it&apos;s an Administrator to Protected Process Light (PPL) bypass.
&lt;p&gt;The mechanism, fully worked out by itm4n in April 2021, is structural and uses that same primitive. As an administrator, call &lt;code&gt;DefineDosDevice&lt;/code&gt; to create a symbolic link in &lt;code&gt;\KnownDlls\&lt;/code&gt; (the object-directory subkey that the loader uses for fast known-DLL lookups). The call is dispatched via RPC to &lt;code&gt;csrss.exe&lt;/code&gt;, which runs at PPL/WinTcb (rung 6) and so has the lattice authority to write into protected directories. The administrator gets a &lt;code&gt;\KnownDlls\&lt;/code&gt; entry pointing at an attacker-controlled section. Now start a PPL. The PPL&apos;s loader resolves DLL names through &lt;code&gt;\KnownDlls\&lt;/code&gt; and finds the administrator&apos;s entry. The PPL maps the attacker&apos;s section without re-validating its on-disk signature, because &lt;code&gt;\KnownDlls\&lt;/code&gt; is the kernel&apos;s vouched-for fast path.&lt;/p&gt;
&lt;p&gt;itm4n&apos;s PPLdump tool, published April 2021, automated the attack. The README test matrix lists every Windows version it ran against [@ppldump-repo]. For fifteen months, an administrator could dump any PPL&apos;s memory, including &lt;code&gt;lsass.exe&lt;/code&gt;, despite &lt;code&gt;RunAsPPL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s fix arrived in build 19044.1826 (the July 2022 update to Windows 10 21H2). itm4n&apos;s &quot;End of PPLdump&quot; writeup describes the patch and the BinDiff diff verbatim [@itm4n-end-of-ppldump]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The conclusion is that PPLs now appear to be behaving just like PPs and therefore no longer rely on Known DLLs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix patched &lt;code&gt;LdrpInitializeProcess&lt;/code&gt; in NTDLL to skip &lt;code&gt;\KnownDlls\&lt;/code&gt; for PPL processes, behind a Velocity feature flag (&lt;code&gt;Feature_Servicing_2206c_38427506__private_IsEnabled&lt;/code&gt;). PPLdump&apos;s repository README now opens with [@ppldump-repo]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2022-07-24 - As of Windows 10 21H2 10.0.19044.1826 (July 2022 update), the exploit implemented in PPLdump no longer works. A patch in NTDLL now prevents PPLs from loading Known DLLs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;itm4n&apos;s structural finding -- that *PPLs honoured &lt;code&gt;\KnownDlls\&lt;/code&gt; while PPs did not* -- is the most interesting failure in the eight-year run, because the asymmetry sat in plain sight from 2013 to 2022 and nobody had asked &quot;why are PPs and PPLs loading sections differently?&quot; The fix closes one asymmetry. The structural class survives.PPLdump&apos;s substitution chain uses NTFS transactions and Forrest Orr&apos;s &quot;phantom DLL hollowing&quot; technique to materialise the attacker-controlled section on disk in a way the kernel section creator will accept [@forrest-orr-hollow]. Orr&apos;s writeup is the original publication of the hollowing primitive; PPLdump composes it with the &lt;code&gt;\KnownDlls\&lt;/code&gt; redirection trick.&lt;/p&gt;
&lt;h3&gt;Act III (2022-2024) -- Landau&apos;s PPLFault CI TOCTOU&lt;/h3&gt;
&lt;p&gt;Gabriel Landau, then at Elastic, presented &quot;PPLdump Is Dead. Long Live PPLdump!&quot; at Black Hat Asia 2023 [@bh-asia-2023-pdf]. The mechanism is a Time-Of-Check / Time-Of-Use bug at the section-creation layer.&lt;/p&gt;

A class of bug in which a security property is verified at one point in time but the underlying object is mutable between the check and the use. The protected resource passes its check, then changes between check and access, and the operation proceeds against the changed state without re-verification.
&lt;p&gt;The TOCTOU here is subtle. When a PPL calls &lt;code&gt;NtCreateSection&lt;/code&gt; on a Microsoft-signed DLL, the kernel&apos;s memory manager calls &lt;code&gt;MiValidateSectionCreate&lt;/code&gt;, which calls into &lt;code&gt;ci.dll&lt;/code&gt; to verify the file&apos;s Authenticode signature. The check succeeds. The section is created. But the memory manager does not page in the file contents at section-create time; it pages them in lazily, on demand, when threads first touch the mapped pages. If an attacker can keep the section&apos;s backing file &lt;em&gt;unsubstituted&lt;/em&gt; during the signature check and substituted during the lazy page-in, the kernel will execute attacker bytes through a section whose signature it already verified.&lt;/p&gt;
&lt;p&gt;Landau&apos;s exploit uses Windows&apos; CloudFilter API. An attacker holds an exclusive oplock on a Microsoft-signed DLL during the section-create signature check. After the check passes, the attacker&apos;s CloudFilter &lt;code&gt;FetchDataCallback&lt;/code&gt; provides different bytes (the payload) when the kernel pages in the section. The PPL maps and executes the payload. Landau&apos;s Elastic post documents the chain verbatim [@elastic-pplfault]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The internal memory manager function &lt;code&gt;MiValidateSectionCreate&lt;/code&gt; relies on the Code Integrity module &lt;code&gt;ci.dll&lt;/code&gt; to handle the requisite cryptography and PKI policy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft&apos;s fix shipped in Windows Insider Canary build 25941 on September 1, 2023 [@elastic-pplfault]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On September 1, 2023, Microsoft released a new build of Windows Insider Canary, version 25941 ... Build 25941 includes improvements to the Code Integrity (CI) subsystem that mitigate a long-standing issue that enables attackers to load unsigned code into Protected Process Light (PPL) processes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fix narrows the immediate channel by extending page-hash validation to PPL-loaded images that reside on &lt;em&gt;remote&lt;/em&gt; (SMB redirector) paths -- the precise surface that PPLFault required to drive its CloudFilter &lt;code&gt;FetchDataCallback&lt;/code&gt; substitution [@elastic-pplfault]. Locally-cached PPL DLL loads continue to rely on the section-create signature check, so the structural seam survives. The GA patch shipped on February 13, 2024 [@pplfault-repo]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2024-02 UPDATE: Microsoft patched PPLFault on 2024-02-13.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Channel: a signed Microsoft DLL whose hash matched at section create. Behaviour: attacker payload mapped via the lazy page-in. The fix narrows the channel by widening the verification surface from &quot;the file at section-create time&quot; to &quot;every page at fault time.&quot; The class survives.&lt;/p&gt;
&lt;h3&gt;Act IV (2022-2024) -- BYOVDLL and itm4n&apos;s KeyIso chain&lt;/h3&gt;
&lt;p&gt;Bring Your Own Vulnerable DLL. Coined by Gabriel Landau on Twitter in October 2022 (itm4n screenshots the original tweet [@itm4n-ghost-part1]; tweet status 1580067594568364032). Productised by itm4n in August 2024 in &quot;Ghost in the PPL Part 1.&quot;&lt;/p&gt;

A bypass class against any signature-gated security mechanism in which the attacker loads a *legitimately signed but historically vulnerable* binary and exploits the known vulnerability inside it. The signature check passes; the vulnerability does the work. The structural property that makes the class hard to fix is that the kernel cannot deny-list legitimately signed older Microsoft DLLs without breaking the deployments that still depend on them.
&lt;p&gt;itm4n&apos;s specific chain targets the CNG Key Isolation service (&quot;KeyIso&quot;), which runs in &lt;code&gt;lsass.exe&lt;/code&gt; and so inherits its PPL/Lsa protection. The chain is precise [@itm4n-ghost-part1]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;As administrator, stop the KeyIso service.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Services\KeyIso\Parameters\ServiceDll&lt;/code&gt; to point at an older &lt;code&gt;keyiso.dll&lt;/code&gt; extracted from Microsoft update KB5023778. This DLL is Microsoft-signed; the kernel admits it.&lt;/li&gt;
&lt;li&gt;Restart the KeyIso service. The older &lt;code&gt;keyiso.dll&lt;/code&gt; loads into LSASS at PPL/Lsa.&lt;/li&gt;
&lt;li&gt;Trigger CVE-2023-36906, an out-of-bounds read information disclosure in the older &lt;code&gt;keyiso.dll&lt;/code&gt;, to leak an address.&lt;/li&gt;
&lt;li&gt;Trigger CVE-2023-28229, one of six use-after-frees in the same DLL, to obtain control of a &lt;code&gt;CALL&lt;/code&gt; target via the &lt;code&gt;RAX&lt;/code&gt; register.&lt;/li&gt;
&lt;li&gt;Execute attacker code at PPL/Lsa.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The CVEs are real and tracked. k0shl&apos;s writeup is the primary root-cause analysis [@k0shl-keyiso]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Microsoft patched vulnerabilities I reported in CNG Key Isolation service, assigned CVE-2023-28229 and CVE-2023-36906, the CVE-2023-28229 included 6 use after free vulenrabilities with similar root cause and the CVE-2023-36906 is a out of bound read information disclosure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;NVD records both [@nvd-2023-28229] [@nvd-2023-36906]. Y3A&apos;s GitHub repository [@y3a-cve-poc] provides a public PoC for CVE-2023-28229 that itm4n&apos;s chain composes.&lt;/p&gt;
&lt;p&gt;Channel: an actually-Microsoft-signed DLL. Behaviour: the memory-safety vulnerability inside it. There is no general fix announced. Microsoft fixed the specific CVEs by shipping a newer &lt;code&gt;keyiso.dll&lt;/code&gt;, but the older DLL remains in circulation (it ships inside every patched cumulative update bundle), and a kernel that has to admit every legitimately signed older Microsoft DLL has no general defense against the next CVE-of-the-month.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; BYOVDLL has no general patch. Microsoft fixes each underlying CVE on the standard cumulative-update cadence. The class persists for as long as the kernel admits older signed Microsoft DLLs into PPLs, which is for as long as legitimately deployed software depends on the older DLLs.&lt;/p&gt;
&lt;/blockquote&gt;

timeline
    title PPL Bypass Arms Race (2018-2024)
    2018-10 : Forshaw JScript-into-PPL : Fix 1803 Apr 2018 : g_BlockedDllsForPPL deny-list
    2021-04 : itm4n PPLdump (KnownDlls) : Fix Jul 2022 build 19044.1826 : LdrpInitializeProcess patch
    2022-09 : Landau PPLFault (TOCTOU) : Fix Feb 2024 13 GA : CI page-hash for PPLs
    2024-08 : itm4n BYOVDLL KeyIso chain : No general fix : CVEs patched piecewise
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Act&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Channel verified&lt;/th&gt;
&lt;th&gt;Behaviour exploited&lt;/th&gt;
&lt;th&gt;Microsoft fix&lt;/th&gt;
&lt;th&gt;Fix date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;Microsoft-signed &lt;code&gt;scrobj.dll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JScript source executed by COM object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;g_BlockedDllsForPPL&lt;/code&gt; deny-list of 5 DLLs&lt;/td&gt;
&lt;td&gt;Apr 2018 (1803)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;II&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\KnownDlls\&lt;/code&gt; symlink (CSRSS-blessed)&lt;/td&gt;
&lt;td&gt;Attacker section mapped without re-validation&lt;/td&gt;
&lt;td&gt;NTDLL &lt;code&gt;LdrpInitializeProcess&lt;/code&gt; patch&lt;/td&gt;
&lt;td&gt;Jul 2022 (19044.1826)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;III&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;Signed DLL passed &lt;code&gt;MiValidateSectionCreate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CloudFilter substitutes bytes on lazy page-in&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/INTEGRITYCHECK&lt;/code&gt; page hashes for PPLs&lt;/td&gt;
&lt;td&gt;Feb 2024 (GA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IV&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;Legitimately-signed older &lt;code&gt;keyiso.dll&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use-after-free + OOB read (CVE-2023-28229, CVE-2023-36906)&lt;/td&gt;
&lt;td&gt;None (CVE-by-CVE)&lt;/td&gt;
&lt;td&gt;open&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart TD
    A[Admin stops KeyIso service]
    B[Repoint ServiceDll to older keyiso.dll&lt;br /&gt;from KB5023778]
    C[Restart KeyIso service]
    D[Older keyiso.dll loads&lt;br /&gt;into lsass.exe PPL/Lsa]
    E[Trigger CVE-2023-36906&lt;br /&gt;OOB read for info leak]
    F[Trigger CVE-2023-28229&lt;br /&gt;UAF for RAX control]
    G[Code execution at PPL/Lsa]
    A --&amp;gt; B --&amp;gt; C --&amp;gt; D --&amp;gt; E --&amp;gt; F --&amp;gt; G

itm4n explicitly attributes the BYOVDLL framing to Landau&apos;s October 2022 tweet, even though itm4n&apos;s KeyIso chain is the first public productisation. The attribution chain matters because it documents how a one-line research observation (Twitter status 1580067594568364032, screenshot preserved in [@itm4n-ghost-part1]) became a working exploit two years later. The pattern repeats in this domain: Forshaw&apos;s one-sentence DefineDosDevice comment to PPLdump (3 years); Landau&apos;s BYOVDLL tweet to itm4n&apos;s KeyIso chain (2 years). The structural class outlives its discoverer.
&lt;p&gt;Four acts, one class. Every public bypass since 2018 has lived in the same narrow shape: code that becomes part of a PPL through a signed channel and executes attacker-influenced data once mapped. Each generation of fix narrows what the channel admits -- name-list five DLLs; ignore &lt;code&gt;\KnownDlls\&lt;/code&gt;; page-hash every section; CVE-patch every vulnerable older DLL. The class survives because the kernel cannot reason about behaviour. By Rice&apos;s theorem it cannot reason about behaviour in general; in practice, it has nowhere even to start.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;lsass.exe&lt;/code&gt; code execution is reachable through BYOVDLL, where are the actual &lt;em&gt;secrets&lt;/em&gt;? Not in &lt;code&gt;lsass.exe&lt;/code&gt;. Not anywhere the kernel can read at all. The next section is the companion boundary.&lt;/p&gt;
&lt;h2&gt;9. The Companion Boundary -- Credential Guard, VBS, and &lt;code&gt;LsaIso.exe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;itm4n opens his RunAsPPL walkthrough with a warning [@itm4n-runasppl]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I noticed that this protection tends to be confused with Credential Guard, which is completely different.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The confusion is understandable. Both run on Windows. Both protect LSASS. Both are configured by domain administrators. Both yield &quot;ACCESS_DENIED&quot; to Mimikatz when working correctly. They are nonetheless answering different questions, and they stack rather than replace each other.&lt;/p&gt;
&lt;p&gt;PPL stops an &lt;em&gt;administrator&lt;/em&gt; from reading kernel-trusted user-mode memory. It does nothing against a kernel-mode attacker who can simply zero the &lt;code&gt;Protection&lt;/code&gt; byte in the target &lt;code&gt;EPROCESS&lt;/code&gt;. The kernel-mode attacker is the next threat-model rung up, and the kernel-mode attacker is the threat that Credential Guard answers, by moving the credentials themselves out of &lt;code&gt;lsass.exe&lt;/code&gt; entirely.&lt;/p&gt;

A Hyper-V-based isolation regime in which the Windows hypervisor partitions the system into Virtual Trust Levels (VTLs). VTL0 contains the normal Windows kernel and user-mode processes. VTL1 contains the Secure Kernel and a small set of user-mode trustlets. Memory in VTL1 is inaccessible to VTL0, even from VTL0 kernel-mode code.

A user-mode process running inside VTL1. Trustlets are Microsoft-signed at a specific protected-process equivalent rung within VTL1 and serve as the user-mode hosts for VBS-isolated functionality. `LsaIso.exe` is the trustlet that holds the actual credential material on Credential Guard-enabled hosts.
&lt;p&gt;The architecture is, at the highest level, three layers: VTL0 user-mode, VTL0 kernel, and VTL1 (Secure Kernel plus trustlets). On a Credential Guard-enabled host, &lt;code&gt;lsass.exe&lt;/code&gt; still exists in VTL0 user-mode, still protects itself with PPL/Lsa, and still answers authentication requests. But it no longer holds the NTLM hashes, Kerberos TGT keys, or Cred Manager domain credentials. Those secrets live in &lt;code&gt;LsaIso.exe&lt;/code&gt;, a trustlet in VTL1. When LSASS needs to authenticate a credential, it makes a hypercall into VTL1, and &lt;code&gt;LsaIso.exe&lt;/code&gt; performs the cryptographic operation entirely within VTL1 memory, returning only the result. The keys never leave VTL1.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s documentation states the threat model directly [@learn-cg]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Credential Guard prevents credential theft attacks by protecting NTLM password hashes, Kerberos Ticket Granting Tickets (TGTs), and credentials stored by applications as domain credentials.&lt;/p&gt;
&lt;p&gt;Credential Guard uses Virtualization-based security (VBS) to isolate secrets so that only privileged system software can access them.&lt;/p&gt;
&lt;p&gt;Malware running in the operating system with administrative privileges can&apos;t extract secrets that are protected by VBS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The third sentence is the load-bearing one. &lt;em&gt;Malware running with administrative privileges&lt;/em&gt; maps cleanly to a PPL bypass that achieves code execution at PPL/Lsa. Even from inside &lt;code&gt;lsass.exe&lt;/code&gt;, the secrets are not there.&lt;/p&gt;

flowchart TD
    subgraph VTL0[VTL0 normal world]
        Admin[Admin / SYSTEM token]
        Lsass[lsass.exe at PPL/Lsa]
        Kern0[VTL0 kernel]
    end
    subgraph VTL1[VTL1 secure world]
        SK[Secure Kernel]
        Iso[LsaIso.exe trustlet]
        Secrets[NTLM hashes, Kerberos TGT keys]
    end
    Admin -- &quot;PPL barrier (lattice)&quot; --x Lsass
    Lsass -- hypercall --&amp;gt; Iso
    Kern0 -- &quot;VBS barrier (VTL boundary)&quot; --x Iso
    Iso --&amp;gt; Secrets
&lt;p&gt;The two mechanisms stack rather than overlap. PPL prevents an admin from &lt;code&gt;OpenProcess(PROCESS_VM_READ, lsass)&lt;/code&gt; at the user-mode lattice level. Credential Guard prevents a kernel-mode attacker who &lt;em&gt;succeeds&lt;/em&gt; against PPL from finding the keys, because the keys are in VTL1 memory that the VTL0 kernel cannot read at all. itm4n&apos;s &quot;complementary&quot; framing in the RunAsPPL writeup is the right operational summary [@itm4n-runasppl]: deploy both, always both.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PPL gates user-mode admins out of LSASS code memory. Credential Guard gates everything else (kernel-mode attackers, BYOVDLL execution-at-PPL/Lsa) out of the secrets themselves by moving the secrets to VTL1. Each mechanism answers a layer of the threat model the other does not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;PPL (LSA protection)&lt;/th&gt;
&lt;th&gt;Credential Guard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Threat model&lt;/td&gt;
&lt;td&gt;Administrator -&amp;gt; user-mode LSASS&lt;/td&gt;
&lt;td&gt;VTL0 kernel + admin -&amp;gt; credential material&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layer&lt;/td&gt;
&lt;td&gt;VTL0 user-mode lattice&lt;/td&gt;
&lt;td&gt;VTL0 / VTL1 VBS boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel-mode attacker&lt;/td&gt;
&lt;td&gt;Cannot stop them&lt;/td&gt;
&lt;td&gt;Stops them (VBS-isolated memory)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MSRC classification&lt;/td&gt;
&lt;td&gt;Defense in depth&lt;/td&gt;
&lt;td&gt;Security boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default-on (consumer)&lt;/td&gt;
&lt;td&gt;Audit mode, Win11 22H2&lt;/td&gt;
&lt;td&gt;n/a (enterprise)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default-on (enterprise)&lt;/td&gt;
&lt;td&gt;Audit mode, Win11 22H2&lt;/td&gt;
&lt;td&gt;Enabled, Win11 22H2 / Win Server 2025 (domain-joined non-DC)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The architecture of `LsaIso.exe`, its trustlet ID, its IUM EKU, and the hypercall plumbing between LSASS and the trustlet are the subject of a separate article in this series (&quot;VBS Trustlets: What Actually Runs in the Secure Kernel&quot;). The cross-link is deliberate: PPL and Credential Guard are paired in practice, but the architectural depth of VTL1 is its own subject.
&lt;p&gt;Credential Guard&apos;s default-on rollout, recorded in Microsoft Learn [@learn-cg]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Starting in Windows 11, 22H2 and Windows Server 2025, Credential Guard is enabled by default on domain-joined, non-DC systems that meet hardware requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two stacked mechanisms; one classified as a security boundary, one not. The next section asks what the classification means.&lt;/p&gt;
&lt;h2&gt;10. Where PPL Isn&apos;t a Security Boundary -- Microsoft&apos;s Servicing Criteria&lt;/h2&gt;
&lt;p&gt;Gabriel Landau&apos;s &quot;Inside Microsoft&apos;s Plan to Kill PPLFault&quot; essay states the classification in one sentence [@elastic-pplfault]:&lt;/p&gt;

Microsoft does not consider PPL to be a security boundary, meaning they won&apos;t prioritize security patches for code-execution vulnerabilities discovered therein, but they have historically addressed some such vulnerabilities on a less-urgent basis.
&lt;p&gt;Microsoft&apos;s &quot;Windows Security Servicing Criteria&quot; defines the term &lt;em&gt;security boundary&lt;/em&gt; directly [@msrc-servicing]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A security boundary provides a logical separation between the code and data of security domains with different levels of trust. For example, the separation between kernel mode and user mode is a classic [...] security boundary.&lt;/p&gt;
&lt;/blockquote&gt;

A logical separation between code and data of security domains with different levels of trust. Microsoft commits to servicing security boundary violations with out-of-band patches when the severity bar is met. The kernel-mode / user-mode separation is the canonical example. Per Microsoft&apos;s published servicing criteria, PPL is *not* on the security-boundary list.

A security feature that raises the cost of an attack without guaranteeing prevention. Microsoft treats defense-in-depth features as servicing targets on the standard cumulative-update cadence, not as out-of-band patch priorities. PPL falls into this category per Microsoft&apos;s published classification.
&lt;p&gt;The relevant excerpts of the criteria page enumerate which surfaces are and are not boundaries. The live MSRC page renders that enumeration table client-side via JavaScript; the raw HTML returned by automated fetchers contains only the React shell. The text of the enumeration is preserved in the Wayback Machine capture at archive date 2023-05-06 [@msrc-criteria-archive], and Landau&apos;s follow-on Elastic post quotes the relevant administrative-process row verbatim [@elastic-byovd-admin]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Administrative processes and users are considered part of the Trusted Computing Base (TCB) for Windows and are therefore not strong[ly] isolated from the kernel boundary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The corresponding row for PPL is the same shape: administrative-process-to-PPL is not isolated as a security boundary. Landau filed VULN-074311 with MSRC in September 2022 disclosing both an admin-to-PPL and a PPL-to-kernel zero-day. The Elastic post records MSRC&apos;s classification of the disclosure verbatim [@elastic-byovd-admin]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MSRC similarly does not consider admin-to-PPL a security boundary, instead classifying it as a defense-in-depth security feature.&lt;/p&gt;
&lt;/blockquote&gt;

The MSRC servicing-criteria page&apos;s *definition* of &quot;security boundary&quot; is retrievable from raw HTML and verified against the live page. The *enumeration* of which Windows surfaces are or are not boundaries lives in a client-side rendered table and is not present in the raw HTML payload. The verifiable trail for &quot;PPL is excluded from the boundary list&quot; is the Wayback Machine capture combined with Elastic&apos;s verbatim quotation of MSRC&apos;s classification.
&lt;p&gt;The operational consequence is direct. A published PPL bypass does not trigger an out-of-band patch. It is fixed on the next major-release cadence, sometimes faster if Microsoft has internal motivation. The disclosure-to-fix half-lives are public record:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bypass&lt;/th&gt;
&lt;th&gt;Disclosed&lt;/th&gt;
&lt;th&gt;Microsoft fix&lt;/th&gt;
&lt;th&gt;Disclosure-to-fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Forshaw 2018 JScript-into-PPL&lt;/td&gt;
&lt;td&gt;Oct 2018&lt;/td&gt;
&lt;td&gt;Apr 2018 (1803, pre-disclosure)&lt;/td&gt;
&lt;td&gt;~0 months (Microsoft fixed first)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;itm4n 2021 PPLdump (KnownDlls)&lt;/td&gt;
&lt;td&gt;Apr 2021&lt;/td&gt;
&lt;td&gt;Jul 2022 (build 19044.1826)&lt;/td&gt;
&lt;td&gt;~15 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Landau 2023 PPLFault (CI TOCTOU)&lt;/td&gt;
&lt;td&gt;Apr-Sep 2023&lt;/td&gt;
&lt;td&gt;Feb 2024 (GA)&lt;/td&gt;
&lt;td&gt;~5-11 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;itm4n 2024 BYOVDLL (KeyIso chain)&lt;/td&gt;
&lt;td&gt;Aug 2024&lt;/td&gt;
&lt;td&gt;none (open, CVE-by-CVE)&lt;/td&gt;
&lt;td&gt;open&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; A correctly classified PPL bypass is fixed on the standard cumulative-update cadence, not out-of-band. The implication for defenders is operational: PPL is exactly as strong as the engineering velocity Microsoft chooses to invest in it. Treat detection (Section 11) and the Credential Guard companion (Section 9) as load-bearing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reader takeaway is the third Aha moment of the article. PPL is real, kernel-enforced, structurally elegant, and demonstrably effective against the threat it was designed for (administrator-from-user-mode reads of LSASS). It is also explicitly &lt;em&gt;not&lt;/em&gt; a security boundary per Microsoft&apos;s own published servicing policy, and that classification is the most important fact about it. Plan for bypasses. Stack with Credential Guard. Treat detection as primary, not secondary.&lt;/p&gt;
&lt;h2&gt;11. Practical Guide -- Configuring, Verifying, and Monitoring PPL&lt;/h2&gt;
&lt;p&gt;If you are deploying PPL on a corporate fleet, run this checklist. The order is deliberate: audit before enforce, verify before trust the verifier, and detect because no static control survives unmotivated.&lt;/p&gt;
&lt;h3&gt;Deploy&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Enable &lt;code&gt;AuditLevel = 8&lt;/code&gt; under &lt;code&gt;HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\LSASS.exe&lt;/code&gt; for two months [@learn-runasppl]. This is a &lt;em&gt;different&lt;/em&gt; registry hive from &lt;code&gt;RunAsPPL&lt;/code&gt; (which lives under &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa&lt;/code&gt;); mixing the two values up is the most common Stage 0 deployment error (see §6). Collect CodeIntegrity events 3065 and 3066 to enumerate every LSASS plug-in that would fail enforcement (smart-card middleware, third-party CSPs, password-filter DLLs). Re-sign or replace the failing modules. Set &lt;code&gt;RunAsPPL = 1&lt;/code&gt; on Secure Boot-capable machines; the kernel automatically stores the policy in a UEFI variable. &lt;code&gt;RunAsPPL = 2&lt;/code&gt; (Win11 22H2+) is the softer option that omits the UEFI variable for environments requiring admin-removable protection.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For third-party EDR, confirm the agent daemon runs at &lt;code&gt;PPL/Antimalware&lt;/code&gt; (signer rung 3, byte &lt;code&gt;0x31&lt;/code&gt;). Process Explorer exposes this via View -&amp;gt; Select Columns -&amp;gt; Protection. System Informer (the modern Process Hacker fork that itm4n recommends in his BYOVDLL writeup [@itm4n-ghost-part1]) shows the same field in its process list. If your EDR is &lt;em&gt;not&lt;/em&gt; running at &lt;code&gt;PPL/Antimalware&lt;/code&gt;, it does not have the kernel&apos;s protection against admin tampering even when its vendor claims &quot;protected&quot; in marketing material. Process Explorer&apos;s &quot;Protection&quot; column ships in the canonical Sysinternals distribution [@sysinternals-procexp]; it reads &lt;code&gt;EPROCESS.Protection&lt;/code&gt; via the &lt;code&gt;NtQueryInformationProcess&lt;/code&gt; entry point [@learn-ntqueryinfoproc], although the specific &lt;code&gt;ProcessProtectionInformation&lt;/code&gt; information-class value is not enumerated in the public Learn &lt;code&gt;PROCESSINFOCLASS&lt;/code&gt; table -- the value is community-documented from Windows headers and reverse engineering rather than from a Microsoft Learn API reference.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Verify&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On a host you suspect of misconfiguration, attach WinDbg to the kernel and run &lt;code&gt;!process 0 7 lsass.exe&lt;/code&gt;. The output includes the &lt;code&gt;_PS_PROTECTION&lt;/code&gt; byte. Decode it with the formula from §3 above: &lt;code&gt;((value &amp;amp; 0xF0) &amp;gt;&amp;gt; 4)&lt;/code&gt; is the signer rung; &lt;code&gt;value &amp;amp; 0x07&lt;/code&gt; is the type; &lt;code&gt;(value &amp;gt;&amp;gt; 3) &amp;amp; 1&lt;/code&gt; is the audit bit. A &lt;code&gt;RunAsPPL = 1&lt;/code&gt; host yields &lt;code&gt;0x41&lt;/code&gt; (PPL + Lsa). The Defender service yields &lt;code&gt;0x31&lt;/code&gt; (PPL + Antimalware). &lt;code&gt;csrss.exe&lt;/code&gt; yields &lt;code&gt;0x61&lt;/code&gt; (PPL + WinTcb). If &lt;code&gt;lsass.exe&lt;/code&gt; shows &lt;code&gt;0x00&lt;/code&gt;, the registry policy did not take effect on this boot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{&lt;code&gt;function decode(b) {   const t = b &amp;amp; 0x07, a = (b &amp;gt;&amp;gt; 3) &amp;amp; 0x01, s = (b &amp;gt;&amp;gt; 4) &amp;amp; 0x0F;   const tn = [&apos;None&apos;, &apos;ProtectedLight&apos;, &apos;Protected&apos;];   const sn = [&apos;None&apos;,&apos;Authenticode&apos;,&apos;CodeGen&apos;,&apos;Antimalware&apos;,               &apos;Lsa&apos;,&apos;Windows&apos;,&apos;WinTcb&apos;,&apos;Max&apos;];   return &apos;0x&apos; + b.toString(16).padStart(2,&apos;0&apos;) + &apos; = &apos; +          (sn[s] || s) + &apos;-&apos; + (tn[t] || t) +          (a ? &apos; (Audit on)&apos; : &apos;&apos;); } // Three benchmark values you should be able to recognise by sight console.log(decode(0x31)); // MsMpEng.exe (Defender at PPL/Antimalware) console.log(decode(0x41)); // lsass.exe under RunAsPPL=1 console.log(decode(0x61)); // csrss.exe (PPL/WinTcb)&lt;/code&gt;}&lt;/p&gt;
&lt;h3&gt;Monitor&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The CodeIntegrity provider emits three event IDs that matter for PPL monitoring [@learn-runasppl]: | Event ID | Provider | What it tells you | |---|---|---| | 3033 | Microsoft-Windows-CodeIntegrity | A DLL load was blocked by CI (PPL or otherwise) | | 3063 | Microsoft-Windows-CodeIntegrity | Enforcement-mode: LSASS plug-in failed the shared-section security requirement (complement of audit-mode event 3065) | | 3065 | Microsoft-Windows-CodeIntegrity | LSASS plug-in failed the shared-section requirement | | 3066 | Microsoft-Windows-CodeIntegrity | LSASS plug-in failed the Microsoft signing level requirement | Sysmon Event 10 (ProcessAccess) captures &lt;code&gt;OpenProcess&lt;/code&gt; denials with the requested access mask and is the cheapest detection for a Mimikatz-shaped attempt against an RunAsPPL-protected &lt;code&gt;lsass.exe&lt;/code&gt;. A burst of 3033 events from a non-Microsoft process targeting &lt;code&gt;lsass.exe&lt;/code&gt; is the canonical signal that a PPL bypass attempt is under way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PPL prevents admin-from-user-mode reads of LSASS. Credential Guard prevents kernel-mode reads of the credentials themselves (and BYOVDLL-style execution at PPL/Lsa). Deploy both. itm4n&apos;s &quot;complementary&quot; framing in his RunAsPPL writeup [@itm4n-runasppl] is the right operational model. On Win11 22H2 and Windows Server 2025, Credential Guard is default-on for domain-joined non-DC systems with VBS-capable hardware [@learn-cg]; on older fleets, enable it explicitly via Group Policy or the Device Guard / Credential Guard configuration script. Always both -- either alone leaves a layer of the threat model uncovered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are an EDR vendor wanting your daemon to run at &lt;code&gt;PPL/Antimalware&lt;/code&gt;, the path is fixed [@learn-mvi] [@learn-am-services]: 1. Hold Microsoft Virus Initiative membership; maintain independent-lab certification (AV-Comparatives, AV-Test, SE Labs, MRG Effitas, SKD Labs, VB 100, West Coast Labs, AVLab Cybersecurity Foundation). 2. Author an ELAM driver with an embedded &lt;code&gt;&amp;lt;ELAM&amp;gt;&lt;/code&gt; resource section enumerating your user-mode binary signing-certificate hashes. 3. Submit the driver through WHQL for Microsoft co-signing. 4. Use Trusted Signing for your user-mode binaries. 5. Verify with Process Explorer that the service launches at &lt;code&gt;PPL/Antimalware&lt;/code&gt; after install.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Practitioners who follow the checklist still need to know the common misconceptions. The next section catalogues them.&lt;/p&gt;
&lt;h2&gt;12. FAQ -- Common Misconceptions&lt;/h2&gt;
&lt;p&gt;Seven questions practitioners ask after their first PPL deployment.&lt;/p&gt;

Yes for full-access termination via `OpenProcess(PROCESS_TERMINATE, ...)`; an admin without a higher signer rung cannot terminate a `PPL/Antimalware` daemon by a direct kill. No for legitimate uninstall: the vendor&apos;s MSI installer (or equivalent) typically signals the daemon to shut itself down through its own service-control path, which is gated by ACL and not by the PPL lattice. Operationally, expect administrators to be able to uninstall your EDR but not to terminate its main process from outside the vendor toolchain.

No. itm4n&apos;s verbatim warning is worth repeating [@itm4n-runasppl]: &quot;I noticed that this protection tends to be confused with Credential Guard, which is completely different.&quot; PPL protects `lsass.exe` *as a process* from admin-from-user-mode reads. Credential Guard moves the *credentials themselves* into VTL1 memory via VBS. PPL is a VTL0 user-mode lattice control. Credential Guard is a VTL0 / VTL1 hypervisor boundary. They stack; see Section 9 for the layering and Section 11 Item 5 for the deployment recommendation.

Because Microsoft has not classified PPL as a security boundary. The Windows Security Servicing Criteria define a security boundary as a logical separation between security domains at different levels of trust, and Microsoft&apos;s published enumeration excludes administrative-process-to-PPL from that list [@msrc-servicing] [@elastic-byovd-admin]. PPL is treated as a defense-in-depth feature. The operational implication is that PPL bypasses are fixed on the next major release cadence rather than out-of-band, with disclosure-to-fix half-lives ranging from approximately five to fifteen months historically (see Section 10 for the data).

Practically no for non-AV applications. The protected-process EKU OIDs are gated by Microsoft&apos;s certificate authorities; only the Antimalware rung admits third-party certificates, and admission is mediated by ELAM driver + Microsoft Virus Initiative membership [@learn-mvi]. Hobbyist tooling cannot opt in. There is no public path for a non-AV third-party application to claim a PPL rung. If your application requires PPL-style anti-tampering, the realistic options are (a) become an MVI member if your application is an AV/EDR, (b) use Process Mitigation Policies such as Code Integrity Guard for code-injection resistance, or (c) deploy your sensitive operations inside a separate Microsoft-signed service.

&quot;Protected service&quot; is informal terminology for a Windows service whose host process runs as a PPL, with the Service Control Manager configured to launch it at a specific signer rung. The deployment plumbing (SCM service configuration, service-DLL packaging, the signing of the host binary) is what makes a service &quot;protected.&quot; The PPL machinery is what makes the host process actually resistant to tampering. The two terms describe the same thing from different angles -- one from the SCM-management view, one from the kernel-access-check view.

Only if the smart-card middleware DLL is not signed at the LSA level (signer rung 4). Most major smart-card vendors have updated their middleware to be Microsoft-signed at the required level, but legacy or in-house middleware frequently fails enforcement. The recommended workflow is to run `AuditLevel = 8` for two months [@learn-runasppl], collect CodeIntegrity 3065 / 3066 events, enumerate the failing modules, re-sign or replace them, and only then switch to `RunAsPPL = 1`. Skipping the audit period is the single most common cause of authentication outages during LSA protection rollouts.

Because the threat model PPL answers is *administrator-from-user-mode*, not *administrator-from-kernel-mode*. PPL is a kernel-enforced gate in the access-check pipeline, but a kernel-mode driver that can write to `EPROCESS.Protection` can zero the byte and disable the gate for any process. The defense against the kernel-mode attacker is a different mechanism: VBS-isolated credentials in VTL1 (Credential Guard), with HVCI / kernel-mode integrity controls preventing arbitrary kernel-mode code from running in the first place. PPL stops one threat; Credential Guard stops the threat one rung up; and the two are intended to be deployed together (Section 9, Section 11 Item 5).
&lt;p&gt;The arc has run from a single Mimikatz error code to a kernel-enforced lattice, a third-party admission path mediated by ELAM and MVI, an arms race shaped by a single structural insight that the kernel verifies the channel and not the behaviour, and a stacked companion boundary that lives in VTL1 because VTL0 has run out of places to hide a key. PPL is not a security boundary. That classification is not a footnote; it is the most important fact about it, because it tells defenders that the mechanism is exactly as strong as the engineering velocity Microsoft chooses to invest. Deploy it. Stack it with Credential Guard. Monitor for the next bypass.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The kernel verifies the channel. It does not verify the behaviour. Every PPL bypass since 2018 has lived in that seam, every fix has narrowed the channel, and the seam survives because behaviour is, by Rice&apos;s theorem, structurally outside what static signature verification can reason about.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;protected-process-light-the-ppl-signer-hierarchy-from-wintcb-to-antimalware&quot; keyTerms={[
  { term: &quot;Protected Process Light (PPL)&quot;, definition: &quot;A kernel-enforced gating model decorating a process with a structured protection level (Type, Audit, Signer) and rejecting OpenProcess requests from callers below the target&apos;s signer rung.&quot; },
  { term: &quot;_PS_PROTECTION byte&quot;, definition: &quot;The EPROCESS field encoding Type (3 bits), Audit (1 bit), Signer (4 bits) in a single UCHAR; read on every NtOpenProcess.&quot; },
  { term: &quot;Signer rung&quot;, definition: &quot;The four-bit Signer field of _PS_PROTECTION naming the trust tier of a protected process; values include Authenticode, Antimalware, Lsa, Windows, and WinTcb.&quot; },
  { term: &quot;RunAsPPL&quot;, definition: &quot;The HKLM\SYSTEM\CurrentControlSet\Control\Lsa registry knob that launches lsass.exe at PPL/Lsa on the next boot; value 1 anchors the policy in a UEFI variable on Secure Boot machines.&quot; },
  { term: &quot;ELAM&quot;, definition: &quot;Early Launch Anti-Malware driver -- a Microsoft-certified kernel driver that enrolls a vendor&apos;s user-mode signing certificates at PPL/Antimalware via an embedded resource section.&quot; },
  { term: &quot;BYOVDLL&quot;, definition: &quot;Bring Your Own Vulnerable DLL -- a bypass class against signature-gated security mechanisms in which the attacker loads a legitimately signed but historically vulnerable binary and exploits the known vulnerability inside it.&quot; },
  { term: &quot;Credential Guard&quot;, definition: &quot;A VBS-based isolation mechanism that moves NTLM hashes, Kerberos TGT keys, and Cred Manager credentials out of lsass.exe and into LsaIso.exe in VTL1.&quot; },
  { term: &quot;Security boundary (MSRC)&quot;, definition: &quot;Per Microsoft&apos;s published servicing criteria, a logical separation between code and data of security domains at different trust levels; PPL is excluded from this list and treated as defense in depth.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows</category><category>protected-process-light</category><category>lsass</category><category>credential-guard</category><category>kernel-security</category><category>edr</category><category>mimikatz</category><category>security-boundary</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>DPAPI and DPAPI-NG: The Credential Vault Under Everything</title><link>https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/</link><guid isPermaLink="true">https://paragmali.com/blog/dpapi-and-dpapi-ng-the-credential-vault-under-everything/</guid><description>A 25-year tour of Windows Data Protection API: the four-stage classic chain, the 2012 DPAPI-NG redesign, the KDS root key, and the five structural ceilings the design cannot close.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Classic DPAPI (Windows 2000, February 17, 2000 [@wikipedia-windows2000]) wraps every per-user Windows secret -- browser cookies, WiFi keys, EFS file keys, Outlook passwords, Credential Manager entries -- in a four-stage chain rooted at the user&apos;s password.** DPAPI-NG (Windows 8 / Server 2012) [@wikipedia-winserver2012] replaces the (user, machine) decryption boundary with a protection descriptor [@ms-protection-descriptors] and rides the Microsoft Key Distribution Service [@ms-gmsa-overview] to give every domain controller in the forest the same per-(group, period) key without inter-DC sync. Group Managed Service Accounts, delegated Managed Service Accounts [@ms-dmsa-overview], Windows Hello for Business on TPM-less devices, and Credential Guard&apos;s isolated-secret persistence all sit on top. The 2022-2025 Golden gMSA [@semperis-golden-gmsa], Golden dMSA [@semperis-golden-dmsa], and Chromium app-bound encryption [@thn-app-bound] disclosures all admit the same thing: DPAPI&apos;s structural ceilings (user-context binding, single-password derivation, KDS-root-key irrotability, hibernation, domain-backup-key concentration) are the design, not bugs.
&lt;h2&gt;1. A Thumb Drive, a Profile Directory, and Three Mimikatz Commands&lt;/h2&gt;
&lt;p&gt;A DFIR analyst slides a stolen laptop&apos;s drive into a write-blocker. The volume mounts because BitLocker&apos;s recovery key was already in the corporate KMS. Six files in &lt;code&gt;C:\Users\alice\AppData\Roaming\Microsoft\Protect\S-1-5-21-...&lt;/code&gt; -- five GUIDs and a &lt;code&gt;Preferred&lt;/code&gt; pointer -- are the only thing standing between the analyst and a decade of Alice&apos;s saved Windows secrets.&lt;/p&gt;
&lt;p&gt;Three Mimikatz [@mimikatz-dpapi-wiki] commands later (&lt;code&gt;dpapi::masterkey /in:&amp;amp;lt;GUID&amp;amp;gt; /sid:S-1-5-21-... /password:&amp;lt;known&amp;gt;&lt;/code&gt;, then &lt;code&gt;dpapi::cred /in:&amp;lt;credfile&amp;gt; /masterkey:&amp;lt;unwrapped&amp;gt;&lt;/code&gt;, then &lt;code&gt;dpapi::chrome /in:&quot;Login Data&quot;&lt;/code&gt;) the analyst has Alice&apos;s saved RDP password to the production jump host, her Microsoft 365 session cookie, the home WiFi PSK, the KeePass &quot;Windows User Account&quot; master password, and the EFS keys for her protected documents (each item is itemised with primary citations in §5&apos;s eleven-row credential-vault inventory). No kernel exploit. No live login. Just one (account-password, SID) pair recovered offline from last week&apos;s NTDS.dit backup.&lt;/p&gt;
&lt;p&gt;The trick that makes that scene possible is older than most working engineers. It shipped in Windows 2000 GA on February 17, 2000 [@wikipedia-windows2000], it has been the same shape for 25 years, and its single-secret design assumption has been public and tractable since February 3, 2010 [@bursztein-talk-page]. The trick has a name: the &lt;strong&gt;Data Protection API&lt;/strong&gt;, or DPAPI.&lt;/p&gt;
&lt;p&gt;This article walks the API end-to-end at the level of detail an academic survey would, but with the working-engineer&apos;s framing the topic deserves. We open the four-stage classic-DPAPI chain at the SHA-1-of-NT-hash-into-PBKDF2-with-the-SID-as-UTF-16LE-salt level. We open the 2012 DPAPI-NG redesign [@ms-cng-dpapi] and the Microsoft Key Distribution Service&apos;s L0/L1/L2 derivation chain [@ms-gkdi-landing] at the same level of precision.&lt;/p&gt;
&lt;p&gt;We name the four production consumers that ride the new chain in 2026: gMSAs, dMSAs, Windows Hello for Business [@ms-whfb-howitworks] software-KSP credentials, and Credential Guard [@paragmali-com-the-en]&apos;s isolated-secret persistence. We name the five structural ceilings the 2022 Golden gMSA [@semperis-golden-gmsa], 2024 Chromium app-bound encryption [@google-security-blog-app-bound], and 2025 Golden dMSA [@semperis-golden-dmsa] disclosures all admit out loud. And we close with what a 2026 practitioner -- developer, defender, red-teamer, platform engineer -- actually does with all of it.&lt;/p&gt;
&lt;p&gt;A note on adjacent topics: the companion &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers the LSAISO trustlet&apos;s isolation boundary; the companion &lt;em&gt;VBS Trustlets&lt;/em&gt; [@paragmali-com-secure-kernel] article covers the trustlet model itself; the &lt;em&gt;TPM in Windows&lt;/em&gt; [@paragmali-com-the-c] article covers TPM-bound key storage providers; the &lt;em&gt;BitLocker on Windows&lt;/em&gt; [@paragmali-com-limits-of] article covers full-volume encryption; the &lt;em&gt;NTLMless&lt;/em&gt; [@paragmali-com-in-windows] article covers Kerberoasting and Golden Ticket disambiguation. Where we touch those topics, we touch them briefly and refer out -- the goal here is to make DPAPI&apos;s chain legible from &lt;code&gt;CryptProtectData&lt;/code&gt; all the way to the four-phase &lt;code&gt;GoldenDMSA&lt;/code&gt; pipeline.&lt;/p&gt;
&lt;p&gt;If you can read those six files in Alice&apos;s &lt;code&gt;Protect&lt;/code&gt; directory and you have her password&apos;s SHA-1 hash, you have everything Windows ever encrypted for her. The next eleven sections explain why -- and why the 2012 redesign that was supposed to fix it produced a new ceiling that, by 2022, turned out to be even harder to live with.&lt;/p&gt;
&lt;h2&gt;2. Why Windows 2000 Needed a Credential Vault: Generation 0 and Generation 1&lt;/h2&gt;
&lt;p&gt;Three years before DPAPI shipped, an attacker with a logged-in user&apos;s session could read every Internet Explorer auto-complete password, every Outlook Express account password, every saved-FTP credential, and every dial-up RAS phonebook entry on the machine -- without breaking any cryptography. The late-1990s reversing tradition (the original &lt;code&gt;pwdump&lt;/code&gt;, &lt;em&gt;L0phtCrack&lt;/em&gt;, Cain &amp;amp; Abel&apos;s &quot;Protected Storage PassView,&quot; the ad-hoc Outlook Express and IE 4 form-fill stealers documented across Bugtraq and ntbugtraq mailing lists at the time) defeated all of it uniformly. The &quot;encryption&quot; applications used was honoured by the OS, faithfully, for the attacker&apos;s process as for the legitimate one -- because there was no system primitive that distinguished one from the other. Each application baked its own key into the binary; every reverser who pulled the binary apart pulled the key out with it.&lt;/p&gt;

The system-provided per-user and per-machine secret-storage primitive that ships in every Windows release from Windows 2000 onward [@wikipedia-dpapi]. The classic API surface is two flat-C functions -- `CryptProtectData` [@ms-cryptprotectdata] and `CryptUnprotectData` -- that take a plaintext, an optional caller entropy parameter, and return a self-contained opaque BLOB. The cryptographic chain inside those two functions is rooted at the user&apos;s login password and is what every &quot;encrypted&quot; Windows secret of the next 25 years sits on top of.
&lt;p&gt;If the attacker is the user&apos;s session, what does &quot;encrypt this for the user&quot; even mean? That is the question every Generation 0 design dodged and every modern credential-vault design has to answer head-on. The 1990s answer (XOR-with-a-baked-in-key) and Microsoft&apos;s first attempt at a real system primitive (Protected Storage / PStore) both missed the same point in different ways.&lt;/p&gt;
&lt;h3&gt;Generation 1: Protected Storage&lt;/h3&gt;
&lt;p&gt;Protected Storage shipped with Internet Explorer 4 and stayed in the OS until Microsoft formally deprecated it. The &lt;code&gt;pstore.dll&lt;/code&gt; [@ms-pstore] item taxonomy is a four-tuple &lt;code&gt;(Key, Type, Subtype, Name)&lt;/code&gt; -- a folder hierarchy of named secret entries. The API was the first system-level secret store on Windows that any application could use without writing its own key derivation; the conceptual contribution survived even after the implementation was abandoned.&lt;/p&gt;
&lt;p&gt;PStore had two ideas the post-Vista world kept and one it dropped. The two it kept: secrets live in a &lt;em&gt;system primitive&lt;/em&gt;, not in each application; secrets are addressed by &lt;em&gt;name&lt;/em&gt;, not by raw key handle. The one it dropped: an &lt;em&gt;Authenticode access-rule&lt;/em&gt; clause that would have bound a stored item to the signing identity of the application that created it. No application ever used the access-rule clause in production. Microsoft&apos;s developer notes are blunt about how the story ended: &lt;em&gt;&quot;Pstore uses an older implementation of data protection. Developers are strongly encouraged to take advantage of the stronger data protection provided by the &lt;code&gt;CryptProtectData&lt;/code&gt; [@ms-cryptprotectdata] and &lt;code&gt;CryptUnprotectData&lt;/code&gt; functions&quot;&lt;/em&gt;; PStore is &lt;em&gt;&quot;only available for read-only operations in Windows Server 2008 and Windows Vista, but may be unavailable in subsequent versions.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The PStore code-identity-pinning idea (Authenticode access rules) was abandoned in 2000 and re-invented twenty-six years later by Chromium 2024 app-bound encryption, which we will reach in §10.3.&lt;/p&gt;
&lt;h3&gt;What survived into DPAPI&lt;/h3&gt;
&lt;p&gt;The Generation 2 design that shipped with Windows 2000 in February 2000 made four moves at once. It kept the two PStore ideas worth keeping (&quot;system-level, not per-application&quot; and &quot;secret addressed by structured name&quot;). It dropped the unused Authenticode access-rule clause. It pushed the cryptographic chain down to a key derived directly from the user&apos;s login password. And it added a domain-recovery sidecar (the BackupKey Remote Protocol [@ms-bkrp-landing], which we open in §5) so managed enterprises would adopt it.&lt;/p&gt;
&lt;p&gt;The canonical first public design document [@learn-microsoft-com-versions-ms995355vmsdn10]) -- NAI Labs / Network Associates&apos; &lt;em&gt;&quot;Windows Data Protection&quot;&lt;/em&gt; whitepaper, MSDN ms995355, October 2001 -- is unambiguous about the layering: &lt;em&gt;&quot;DPAPI initially generates a strong key called a MasterKey, which is protected by the user&apos;s password. DPAPI uses a standard cryptographic process called Password-Based Key Derivation, described in PKCS #5, to generate a key from the password.&quot;&lt;/em&gt; And: &lt;em&gt;&quot;DPAPI is a password-based data protection service. It requires a password to provide protection.&quot;&lt;/em&gt;Some secondary sources attribute a &quot;Microsoft Windows Data Protection API&quot; whitepaper to Niels Ferguson at &lt;code&gt;niels.ferguson.com/research/dpapi.html&lt;/code&gt;. That URL has been TCP-unreachable for years, has zero Wayback captures across four candidate variants, and the Wikipedia &lt;em&gt;Niels Ferguson&lt;/em&gt; article [@wikipedia-niels-ferguson] lists no DPAPI publication for him -- his named Microsoft paper is the 2006 BitLocker / Elephant-diffuser paper, not anything DPAPI-related. The verifiable Microsoft-blessed first design document is the NAI Labs ms995355 whitepaper [@learn-microsoft-com-versions-ms995355vmsdn10]).&lt;/p&gt;
&lt;p&gt;The two-function flat-C API Microsoft shipped with Windows 2000 in February 2000 is what every Windows secret of the next 25 years has been encrypted with. The four-stage chain it hides behind those two function names is what we open up next.&lt;/p&gt;
&lt;h2&gt;3. The Four-Stage Chain: How &lt;code&gt;CryptProtectData&lt;/code&gt; Actually Encrypts&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;CryptProtectData&lt;/code&gt; [@ms-cryptprotectdata] call goes in with a plaintext buffer and an optional entropy parameter; out comes a self-contained opaque BLOB whose header adds roughly 100-150 bytes to the plaintext (the exact size depends on the algorithm choice and the master-key GUID encoding; the field-by-field BLOB layout is documented in the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] and parsed by the Mimikatz &lt;code&gt;dpapi::blob&lt;/code&gt; [@mimikatz-dpapi-wiki] module). There is no &lt;code&gt;pszProvider&lt;/code&gt; argument, no &lt;code&gt;hKey&lt;/code&gt;, no algorithm choice exposed to the caller. Behind those two parameters is a four-stage cryptographic chain that has been the same shape for a quarter-century. Each stage takes the previous stage&apos;s output and one new input; the &lt;em&gt;only&lt;/em&gt; secret in the entire chain that an offline attacker has to guess is the user&apos;s password.&lt;/p&gt;

flowchart TD
    Password[&quot;User password&quot;] --&amp;gt; NTHash[&quot;NT hash&lt;br /&gt;(MD4 of UTF-16LE password)&quot;]
    NTHash --&amp;gt; Sha1NT[&quot;SHA-1(NT hash)&quot;]
    SID[&quot;User SID&lt;br /&gt;(UTF-16LE)&quot;] --&amp;gt; PBKDF2
    Sha1NT --&amp;gt; PBKDF2[&quot;Stage 1: PBKDF2&lt;br /&gt;(HMAC-SHA1 / HMAC-SHA512)&quot;]
    PBKDF2 --&amp;gt; PreKey[&quot;Pre-key&quot;]
    MK[&quot;Stage 2: Master key&lt;br /&gt;(64 random bytes)&quot;] --&amp;gt;|encrypted under| AESCBC[&quot;version-cipher wrap (AES-CBC on Win7+)&quot;]
    PreKey --&amp;gt; AESCBC
    AESCBC --&amp;gt; MKFile[&quot;%APPDATA%/Microsoft/Protect/&amp;lt;SID&amp;gt;/&amp;lt;GUID&amp;gt;&quot;]
    MK --&amp;gt; SessionKey[&quot;Stage 3: Session key&lt;br /&gt;HMAC(MK, salt || entropy)&quot;]
    SessionKey --&amp;gt; Wrap[&quot;Stage 4: BLOB wrap&lt;br /&gt;(3DES or AES-256, salt, HMAC)&quot;]
    Plaintext[&quot;Plaintext&quot;] --&amp;gt; Wrap
    Wrap --&amp;gt; Blob[&quot;DPAPI BLOB&quot;]
&lt;h3&gt;Stage 1: Pre-key derivation&lt;/h3&gt;
&lt;p&gt;The pre-key is a function of three values. The user-account password (or its NT-hash equivalent, supplied by &lt;code&gt;LSASS&lt;/code&gt; to the local DPAPI provider) is hashed with SHA-1; the SHA-1 result is fed into PBKDF2 as the input keying material; the user&apos;s security identifier (SID) [@learn-microsoft-com-versions-ms995355vmsdn10]) UTF-16LE-encoded is the salt; and a Windows-version-dependent iteration count completes the call. The output is a fixed-width pre-key that Stage 2 will use to wrap the master key.&lt;/p&gt;
&lt;p&gt;The chain has changed &lt;em&gt;parameters&lt;/em&gt; across Windows versions but has kept the four-stage &lt;em&gt;shape&lt;/em&gt; since 2000. The Passcape master-key analysis table [@passcape-master-key-analysis] records the migration verbatim:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Windows version&lt;/th&gt;
&lt;th&gt;Symmetric cipher&lt;/th&gt;
&lt;th&gt;HMAC&lt;/th&gt;
&lt;th&gt;PBKDF2 iterations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Windows 2000&lt;/td&gt;
&lt;td&gt;RC4&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows XP&lt;/td&gt;
&lt;td&gt;3DES&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;4 000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Vista&lt;/td&gt;
&lt;td&gt;3DES&lt;/td&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;24 000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 7&lt;/td&gt;
&lt;td&gt;AES-256&lt;/td&gt;
&lt;td&gt;SHA-512&lt;/td&gt;
&lt;td&gt;5 600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10 / 11&lt;/td&gt;
&lt;td&gt;AES-256&lt;/td&gt;
&lt;td&gt;SHA-512&lt;/td&gt;
&lt;td&gt;8 000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The shift from PBKDF2-HMAC-SHA1 / 3DES (Windows 2000 -- Vista) to PBKDF2-HMAC-SHA512 / AES-256 (Windows 7 onward) happened at Windows 7, not Windows 10; Bursztein and Picod&apos;s 2010 USENIX WOOT paper [@usenix-woot10] documented the SHA-1/3DES era through Windows 7 (the Black Hat DC 2010 talk and WOOT paper covered XP&apos;s 4,000-iteration regime and Vista&apos;s 24,000-iteration regime; Windows 7&apos;s PBKDF2-SHA512/AES-256 shift had only recently shipped when the research was finalised).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 8 000 iterations of HMAC-SHA-512 is not strong against a modern wordlist attack on a leaked NT hash. Cumulative updates can raise the iteration count further; the actual count is recorded in the master-key file&apos;s header and is not implicit. When you read someone&apos;s master key, read the iteration count from the file -- do not assume.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Stage 2: The master key&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;master key&lt;/em&gt; is a 64-byte cryptographically random secret; one is generated per user, on first use of DPAPI, and a fresh one is generated every 90 days by default. Master keys live as files inside &lt;code&gt;%APPDATA%\Microsoft\Protect\&amp;amp;lt;SID&amp;amp;gt;\&amp;amp;lt;GUID&amp;amp;gt;&lt;/code&gt;, where the GUID is the master-key identifier embedded in every BLOB that uses it. The file begins with a service header (containing the iteration count and algorithm IDs) followed by four distinct slots: (1) the user-master-key blob (encrypted under the Stage 1 pre-key with the version-dependent cipher -- RC4 on Windows 2000, 3DES on XP through Vista, AES-256-CBC on Windows 7 and later); (2) the local-encryption-key slot; (3) the local-backup-key (Windows 2000) or CREDHIST GUID (Windows XP and later); and (4) the domain-backup-key blob [@ms-bkrp-landing] (encrypted to the DC&apos;s backup public key, see §5).&lt;/p&gt;

A 64-byte random secret per user, persisted as a file under `%APPDATA%\Microsoft\Protect\&amp;lt;SID&amp;gt;\&amp;lt;GUID&amp;gt;`, encrypted under a pre-key derived from the user&apos;s password and SID. Every DPAPI BLOB the user ever creates is wrapped under a session key derived from one of these master keys. Master keys rotate every 90 days by default per the NAI Labs design document [@learn-microsoft-com-versions-ms995355vmsdn10]) and the Passcape master-key analysis [@passcape-master-key-analysis], but old master keys remain on disk so old BLOBs can still be decrypted.
&lt;h3&gt;Stage 3: The per-call session key&lt;/h3&gt;
&lt;p&gt;For every call to &lt;code&gt;CryptProtectData&lt;/code&gt;, DPAPI generates a fresh per-blob salt, computes an HMAC of the master key with the salt and the optional caller entropy, and uses that HMAC as the session key for the actual symmetric encryption. The session key is never stored; it is derivable from (master key, salt, entropy) at unwrap time per the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] §3.3 and the Mimikatz &lt;code&gt;dpapi::blob&lt;/code&gt; parser [@mimikatz-dpapi-wiki]. The salt is in the BLOB header; the entropy, if any, must be supplied by the caller at unwrap time.&lt;/p&gt;
&lt;h3&gt;Stage 4: The BLOB wrap&lt;/h3&gt;
&lt;p&gt;The output BLOB is a self-describing structure with a fixed header. The provider GUID &lt;code&gt;{df9d8cd0-1501-11d1-8c7a-00c04fc297eb}&lt;/code&gt; identifies it as a classic-DPAPI blob; the master-key GUID names the master key under which it was wrapped; an &lt;code&gt;algCrypt&lt;/code&gt; algorithm identifier records which symmetric cipher was used (&lt;code&gt;0x6603&lt;/code&gt; for &lt;code&gt;CALG_3DES&lt;/code&gt; on legacy builds, &lt;code&gt;0x6610&lt;/code&gt; for &lt;code&gt;CALG_AES_256&lt;/code&gt; on later builds); the salt, ciphertext, and HMAC fill the rest. The Mimikatz &lt;code&gt;dpapi&lt;/code&gt; module wiki [@mimikatz-dpapi-wiki] documents the verbatim field layout that every offline DPAPI tool parses to this day.&lt;/p&gt;

The `algCrypt` field in the DPAPI BLOB header is a CryptoAPI algorithm identifier from `wincrypt.h`: `0x6603` is `CALG_3DES` (the historical default, encoded as `ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES`); `0x6610` is `CALG_AES_256` (used on Windows 7 and later, encoded as `ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256`). The provider GUID `{df9d8cd0-1501-11d1-8c7a-00c04fc297eb}` is the magic constant that marks every classic-DPAPI BLOB and is the same value the Mimikatz `dpapi::blob` module [@mimikatz-dpapi-wiki] and the Bursztein-Picod 2010 paper [@bursztein-paper-pdf] §3.3.1 print when they parse one.
&lt;p&gt;{`&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Parse --&amp;gt; Cert&amp;amp;#123;&quot;CERTIFICATE=&quot;&amp;amp;#125;
Parse --&amp;gt; Local&amp;amp;#123;&quot;LOCAL=&quot;&amp;amp;#125;
Parse --&amp;gt; Web&amp;amp;#123;&quot;WEBCREDENTIALS=&quot;&amp;amp;#125;
Sid --&amp;gt; KSP[&quot;Microsoft Key Protection Provider&amp;lt;br/&amp;gt;+ kdssvc.dll [MS-GKDI]&quot;]
Cert --&amp;gt; CertKSP[&quot;Cert&apos;s KSP&amp;lt;br/&amp;gt;(TPM-backed possible)&quot;]
Local --&amp;gt; LocalProv[&quot;Microsoft Key Protection Provider&amp;lt;br/&amp;gt;(LOCAL=user / LOCAL=machine)&quot;]
Web --&amp;gt; Broker[&quot;Microsoft Client Key Protection Provider&amp;lt;br/&amp;gt;(credential broker)&quot;]
KSP --&amp;gt; Wrap
CertKSP --&amp;gt; Wrap
LocalProv --&amp;gt; Wrap
Broker --&amp;gt; Wrap
Wrap[&quot;Derive wrapping key,&amp;lt;br/&amp;gt;encrypt content&quot;] --&amp;gt; Blob[&quot;Self-describing blob&amp;lt;br/&amp;gt;(descriptor + provider info&amp;lt;br/&amp;gt;+ key id + ciphertext + HMAC)&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output blob is self-describing per the protected-data-format reference [@ms-protected-data-format]: descriptor, provider info, key identifier, ciphertext, HMAC. Any device with a CNG implementation that can satisfy the descriptor decrypts. There is no out-of-band key shipping. There is no &quot;encrypt the blob and ship the key separately.&quot; The descriptor &lt;em&gt;is&lt;/em&gt; the key-distribution policy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; DPAPI-NG separates &lt;em&gt;who can decrypt&lt;/em&gt; (the descriptor) from &lt;em&gt;where the key material lives&lt;/em&gt; (the provider). The descriptor is the contract; the provider is the implementation. This is the structural innovation that lets a blob protected on one machine be decrypted on another without any application-layer key-management code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The CNG DPAPI overview page lists only &lt;em&gt;two&lt;/em&gt; principal classes -- AD group and web credentials -- whereas the protection-descriptors page enumerates three (adding the certificate-store class). Both are correct: the certificate descriptor maps to a different provider, hence the two-principal framing on the higher-level overview page and the three-keyword framing on the descriptors-grammar page.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;LOCAL=user&lt;/code&gt; and &lt;code&gt;CERTIFICATE=&lt;/code&gt; cases are interesting but mostly variations on themes that classic DPAPI or the Windows certificate store could already do. The case that required Microsoft to ship a new DC-side daemon -- the case that turned DPAPI-NG into the substrate for gMSAs [@ms-gmsa-overview], dMSAs [@ms-dmsa-overview], Hello for Business, and Credential Guard&apos;s persistence layer -- is the &lt;code&gt;SID=&lt;/code&gt; AD-group descriptor. The next section opens its substrate: the Microsoft Key Distribution Service and the &lt;code&gt;[MS-GKDI]&lt;/code&gt; protocol.&lt;/p&gt;
&lt;h2&gt;7. The Microsoft Key Distribution Service: How &lt;code&gt;[MS-GKDI]&lt;/code&gt; Computes the Same Group Key on Every DC Without Talking to Any of Them&lt;/h2&gt;
&lt;p&gt;Imagine a forest with seven writable domain controllers. A laptop in Singapore protects a DPAPI-NG blob with &lt;code&gt;SID=S-1-5-21-...XYZ&lt;/code&gt; (some AD group). Three months later, a phone in Seoul -- a member of the same group, on a different DC -- needs to decrypt it. Neither DC has ever heard of the blob. Both DCs derive &lt;em&gt;exactly the same group key&lt;/em&gt; and hand it to the requesting member. No inter-DC synchronisation. No key-distribution code in either application. The mechanism is one forest-wide root key plus a deterministic key-derivation function.&lt;/p&gt;

The DC-side daemon that ships in every writable domain controller from Windows Server 2012 onward [@wikipedia-winserver2012]. Implements the [`[MS-GKDI]` Group Key Distribution Protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a) (current revision class 10.0, April 2024) and is the substrate for every DPAPI-NG `SID=` blob, every gMSA password, every dMSA password, and the TPM-less software-KSP path of Windows Hello for Business. The service has one job: given a (group, time-period) request from a member computer, derive and return the per-(group, period) key from a single forest-wide root key.
&lt;h3&gt;Provisioning the root key&lt;/h3&gt;
&lt;p&gt;Every forest needs exactly one KDS root key before any DPAPI-NG &lt;code&gt;SID=&lt;/code&gt; consumer can use it. The PowerShell cmdlet &lt;code&gt;Add-KdsRootKey&lt;/code&gt; [@ms-add-kdsrootkey] is the provisioning entry point. The Microsoft Learn page is verbatim about the constraints: &lt;em&gt;&quot;The Add-KdsRootKey cmdlet generates a new root key for the Microsoft Group Key Distribution Service (KdsSvc) within Active Directory... It is required to run this only once per forest.&quot;&lt;/em&gt; The default &lt;code&gt;EffectiveTime&lt;/code&gt; is &lt;em&gt;&quot;10 days after the current date&quot;&lt;/em&gt; to allow Active Directory replication to converge across all writable DCs before any consumer tries to derive against the new key.The &lt;code&gt;Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10))&lt;/code&gt; override is for &lt;em&gt;single-DC test forests only&lt;/em&gt;. Production forests should let the 10-day default replicate; using the back-dated override means the first consumer to call into the KDS may target a DC that has not yet received the new root key from replication.&lt;/p&gt;
&lt;p&gt;The root key lives at &lt;code&gt;CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,&amp;lt;forest-DN&amp;gt;&lt;/code&gt; and carries four attributes that downstream offensive-research tools enumerate: &lt;code&gt;msKds-RootKeyData&lt;/code&gt; (the actual key bytes), &lt;code&gt;msKds-KDFAlgorithmID&lt;/code&gt; (the KDF identifier, currently SP800-108 HMAC-SHA512), &lt;code&gt;msKds-KDFParam&lt;/code&gt; (the KDF parameter block), and &lt;code&gt;msKds-PrivateKeyLength&lt;/code&gt;. These four attributes, together, are everything a deterministic-KDF derivation needs to recompute every group key the forest will ever produce.&lt;/p&gt;

The single forest-wide secret that anchors every per-(group, period) key the Microsoft Key Distribution Service will ever derive, for every DPAPI-NG `SID=` blob, every gMSA, every dMSA, every Hello-for-Business software-KSP container, and every Credential-Guard isolated-secret persistence wrap. Provisioned with `Add-KdsRootKey` [@ms-add-kdsrootkey], exactly once per forest. Stored as four attributes (`msKds-RootKeyData`, `msKds-KDFAlgorithmID`, `msKds-KDFParam`, `msKds-PrivateKeyLength`) under `CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,`. Currently, Microsoft documents no rotation procedure [@ms-cng-dpapi-backup-keys]; see §9.3.
&lt;h3&gt;The L0 / L1 / L2 derivation chain&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt; specification&lt;/a&gt; (current revision class 10.0, April 23 2024) describes the protocol. Internally, the KDS computes a three-level derivation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;L0 seed key&lt;/strong&gt;: derived from the root key and a label that includes the period-in-hours-thousands tier and the group-related input, via a NIST SP 800-108 KDF in counter mode using HMAC-SHA-512 (see NIST SP 800-108r1 [@nist-sp-800-108r1], August 2022).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L1 seed key&lt;/strong&gt;: derived from L0 with a second-tier label.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;L2 seed key&lt;/strong&gt;: derived from L1 with the third-tier label. This is the actual symmetric key the DPAPI-NG blob&apos;s content key wraps under (or the seed for a per-period group ECDH key pair, in the public-key DPAPI-NG mode).&lt;/li&gt;
&lt;/ul&gt;

The first level of the [`[MS-GKDI]`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a) three-tier derivation chain. Computed deterministically from the KDS root key and a label that combines the time-period tier (in units of `period-in-hours / 1000`) and a group-related input. The whole point of the chain is that any DC that holds the same root key, given the same label, derives the same L0 seed key without coordination with any other DC -- which is also the whole reason a single root-key compromise compromises every key the forest will ever derive.

flowchart TD
    Root[&quot;KDS root key&lt;br /&gt;(forest-wide secret)&quot;] --&amp;gt; L0[&quot;L0 seed key&lt;br /&gt;(period_hours / 1000 + group input)&quot;]
    L0 --&amp;gt; L1[&quot;L1 seed key&lt;br /&gt;(second-tier label)&quot;]
    L1 --&amp;gt; L2[&quot;L2 seed key&lt;br /&gt;(third-tier label)&quot;]
    L2 --&amp;gt; Symmetric[&quot;Per-(group, period)&lt;br /&gt;symmetric key OR&lt;br /&gt;ECDH key-pair seed&quot;]
    KDF[&quot;SP800-108 counter-mode&lt;br /&gt;KDF, HMAC-SHA-512&quot;] -.derives.-&amp;gt; L0
    KDF -.derives.-&amp;gt; L1
    KDF -.derives.-&amp;gt; L2
&lt;h3&gt;The &lt;code&gt;GetKey&lt;/code&gt; round trip&lt;/h3&gt;
&lt;p&gt;A member computer&apos;s local KDS-NG provider calls the &lt;code&gt;GetKey&lt;/code&gt; RPC (the primary opnum of &lt;code&gt;[MS-GKDI]&lt;/code&gt;) against any reachable writable DC. The DC computes the L0/L1/L2 chain on demand and returns the per-(group, period) key material. No inter-DC synchronisation is needed because the KDF is deterministic.&lt;/p&gt;

sequenceDiagram
    participant Member as &quot;Member computer (Microsoft Key Protection Provider)&quot;
    participant DC as &quot;Nearest writable DC (kdssvc.dll)&quot;
    participant Root as Root key (AD-replicated)
    Member-&amp;gt;&amp;gt;DC: GetKey(group_sid, period_id)
    DC-&amp;gt;&amp;gt;Root: Read msKds-RootKeyData + KDF params
    Root--&amp;gt;&amp;gt;DC: Root-key material
    DC-&amp;gt;&amp;gt;DC: Compute L0(period, group) -&amp;gt; L1 -&amp;gt; L2
    DC--&amp;gt;&amp;gt;Member: Per-(group, period) key material
    Member-&amp;gt;&amp;gt;Member: Wrap (or unwrap) DPAPI-NG blob

Because the KDF is deterministic by design -- this is exactly the security property NIST SP 800-108r1 [@nist-sp-800-108r1] §5 establishes -- an attacker who reads the four root-key attributes once can derive every per-(group, period) key the KDS will ever produce, *for that root key*, without further DC interaction. The same property that lets a Singapore laptop and a Seoul phone derive the same key without talking to each other lets an attacker who reads the root key derive every gMSA password the forest will ever issue. This is the same property that makes Golden gMSA [@semperis-golden-gmsa] work in §10.
&lt;p&gt;Every DC in the forest runs the same &lt;code&gt;kdssvc.dll&lt;/code&gt; over the same root key with the same KDF; every authorised member of the named group can ask any DC for the per-(group, period) key and receive the same answer. The architecture is elegant. It is also, by structural necessity, the architecture that makes a one-shot read of the root key into a one-shot compromise of every key the forest will ever derive. Hold that thought; it is what §10 is built on. First we look at what actually rides on this substrate today.&lt;/p&gt;
&lt;h2&gt;8. The Four Things That Ride DPAPI-NG in 2026&lt;/h2&gt;
&lt;p&gt;One protocol, four production consumers. The same KDS root key that protects a &lt;code&gt;SID=&lt;/code&gt; DPAPI-NG blob is also the root from which every gMSA password, every dMSA password, every TPM-less Windows Hello private key, and every Credential Guard isolated NT-hash is derived.&lt;/p&gt;

A Windows-Server-2012-introduced Active Directory account class whose password is computed automatically by the Microsoft Key Distribution Service [@ms-gmsa-overview] on the DC, rotated every 30 days, 256 bytes long, and shared across multiple service hosts via the `msDS-GroupMSAMembership` SDDL gate. From the Microsoft Learn overview verbatim: *&quot;For a gMSA, the domain controller computes the password on the key that the Key Distribution Services provides, along with other attributes of the gMSA.&quot;* `Install-ADServiceAccount` on each member computer caches the derivation locally so the service can boot under the account.

flowchart TD
    Root[&quot;KDS root key&quot;] --&amp;gt; Chain[&quot;[MS-GKDI] L0/L1/L2 chain&quot;]
    Chain --&amp;gt; GMSA[&quot;gMSA password&lt;br /&gt;(30-day rotation,&lt;br /&gt;256 bytes)&quot;]
    Chain --&amp;gt; DMSA[&quot;dMSA password&lt;br /&gt;(machine-bound,&lt;br /&gt;Server 2025)&quot;]
    Chain --&amp;gt; WHfB[&quot;WHfB software-KSP&lt;br /&gt;(TPM-less devices,&lt;br /&gt;SID + device descriptor)&quot;]
    Chain --&amp;gt; CG[&quot;Credential Guard&lt;br /&gt;LsaIso-isolated secret&lt;br /&gt;(trustlet identity descriptor)&quot;]
&lt;h3&gt;8.1 Group Managed Service Accounts&lt;/h3&gt;
&lt;p&gt;gMSAs shipped in Windows Server 2012 (GA September 2012). The model: one AD account, multiple service hosts, no admin-managed password rotation, no per-service password file. The Microsoft Learn overview [@ms-gmsa-overview] is verbatim about the chain: &lt;em&gt;&quot;The Microsoft Key Distribution Service (kdssvc.dll) lets you securely obtain the latest key or a specific key with a key identifier for an Active Directory account... For a gMSA, the domain controller computes the password on the key that the Key Distribution Services provides, along with other attributes of the gMSA.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The constructed attribute that surfaces the password to authorised member computers is &lt;code&gt;msDS-ManagedPassword&lt;/code&gt; [@ms-ms-adts-managedpassword]; it is computed on demand by the DC from the KDS chain when an authorised member queries it. The authorisation gate is the &lt;code&gt;msDS-GroupMSAMembership&lt;/code&gt; security descriptor on the gMSA object: only principals whose SIDs satisfy that SDDL get the password back. Rotation is every 30 days. The password length is 256 bytes -- &lt;em&gt;&quot;a randomly generated password of 256 bytes, making it infeasible to crack&quot;&lt;/em&gt; per the Semperis Golden gMSA write-up [@semperis-golden-gmsa], which is true &lt;em&gt;if and only if&lt;/em&gt; the KDS root key is intact. We come back to that &lt;em&gt;if and only if&lt;/em&gt; in §10.&lt;/p&gt;
&lt;h3&gt;8.2 Delegated Managed Service Accounts&lt;/h3&gt;
&lt;p&gt;dMSAs shipped in Windows Server 2025 (GA November 1, 2024 [@wikipedia-winserver2025]). The same KDS chain; a different authorisation gate. Rather than binding to AD group membership, dMSA authentication binds to &lt;em&gt;machine identity&lt;/em&gt;: the Microsoft Learn overview [@ms-dmsa-overview] describes dMSAs as &lt;em&gt;&quot;a machine account with managed and fully randomized keys, while disabling original service account passwords. Authentication for dMSA is linked to the device identity, which means that only specified machine identities mapped in Active Directory (AD) can access the account.&quot;&lt;/em&gt; The &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; attribute carries a machine-binding component. Microsoft&apos;s marketing framing positions dMSA as the &quot;Kerberoast-immune&quot; replacement for static service accounts.&lt;/p&gt;
&lt;p&gt;The Server 2025 dMSA design has its own §10 footnote: the July 2025 Semperis Golden dMSA disclosure [@semperis-golden-dmsa] found that the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; time-component has predictable structure with only ~1 024 plausible values, making offline brute-forcing tractable once the KDS root key is in hand.&lt;/p&gt;
&lt;h3&gt;8.3 Windows Hello for Business software-KSP credentials&lt;/h3&gt;
&lt;p&gt;The Hello for Business &lt;em&gt;how it works&lt;/em&gt; page [@ms-whfb-howitworks] describes the credential as a per-user per-device asymmetric key pair. On TPM-equipped devices the private key lives in the TPM and DPAPI-NG is not in the wrap path. On TPM-less devices (the structural worst case) the WHfB private key sits in a CNG software Key Storage Provider container persisted as a DPAPI-NG-protected file [@ms-whfb-howitworks] whose protection descriptor binds it to the user SID + device. The &lt;em&gt;TPM in Windows&lt;/em&gt; article in this series covers the TPM-bound case; here we record only that the software-KSP fallback rides on DPAPI-NG and inherits the KDS root-key dependency for the SID-bound branch.&lt;/p&gt;

A non-hardware-bound CNG key-storage provider that persists key material in DPAPI-NG-protected files in the user profile. Used by Windows Hello for Business on TPM-less devices [@ms-whfb-howitworks] and as the fallback when no hardware-bound KSP (TPM, smart card, Secure Enclave equivalent) is available. The structural worst case for the WHfB credential, because the private key lives in a file the OS can read in any user-context process, wrapped under a DPAPI-NG blob whose protection descriptor reduces back to the KDS root key for SID-anchored bindings.
&lt;h3&gt;8.4 Credential Guard isolated-secret persistence&lt;/h3&gt;
&lt;p&gt;The companion &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers &lt;code&gt;LsaIso.exe&lt;/code&gt; and the LSAISO trustlet&apos;s isolation boundary in depth; what matters here is that the trustlet&apos;s persistence layer is DPAPI-NG. &lt;code&gt;LsaIso.exe&lt;/code&gt;, running in VTL1 IUM, stores the isolated NT one-way function outputs and Kerberos session keys in DPAPI-NG blobs whose protection descriptor binds them to the trustlet&apos;s own identity. The VSM master key (TPM-bound on TPM-2.0 systems per Microsoft Learn&apos;s Credential Guard [@ms-credential-guard] overview, which describes how Credential Guard &quot;uses Virtualization-based security (VBS) [@ms-vbs] to isolate secrets&quot;) is what the trustlet seals its DPAPI-NG protection state under across reboots. The end result is that even though the Credential Guard model puts the credential outside &lt;code&gt;lsass.exe&lt;/code&gt;, the &lt;em&gt;persistence&lt;/em&gt; of that isolated secret rides on the same KDS-rooted DPAPI-NG chain every other consumer in this section uses.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Consumer&lt;/th&gt;
&lt;th&gt;Rotation&lt;/th&gt;
&lt;th&gt;Authorisation gate&lt;/th&gt;
&lt;th&gt;On-disk artefact&lt;/th&gt;
&lt;th&gt;Recovery story&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;gMSA&lt;/td&gt;
&lt;td&gt;30 days&lt;/td&gt;
&lt;td&gt;&lt;code&gt;msDS-GroupMSAMembership&lt;/code&gt; SDDL&lt;/td&gt;
&lt;td&gt;Cached on member via &lt;code&gt;Install-ADServiceAccount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recompute via KDS at any time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dMSA&lt;/td&gt;
&lt;td&gt;Managed by KDS&lt;/td&gt;
&lt;td&gt;Machine identity in AD&lt;/td&gt;
&lt;td&gt;Cached on member; &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; carries machine binding&lt;/td&gt;
&lt;td&gt;Recompute via KDS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WHfB software-KSP&lt;/td&gt;
&lt;td&gt;Per-credential lifetime&lt;/td&gt;
&lt;td&gt;User SID + device&lt;/td&gt;
&lt;td&gt;DPAPI-NG-wrapped key container in user profile&lt;/td&gt;
&lt;td&gt;New enrollment if lost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LsaIso DPAPI-NG persistence&lt;/td&gt;
&lt;td&gt;Boot-cycle bound&lt;/td&gt;
&lt;td&gt;Trustlet identity&lt;/td&gt;
&lt;td&gt;Trustlet-managed VTL1 store, sealed under VSM master key&lt;/td&gt;
&lt;td&gt;Re-derive on next logon&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Every shipping Windows credential primitive that &lt;em&gt;just works&lt;/em&gt; across multiple devices, multiple service hosts, or multiple cold-boot cycles -- without per-application key-management code -- is sitting on the same KDS root key. The architectural bet is that the root key never leaks. The next two sections are about what happens when it does.&lt;/p&gt;
&lt;h2&gt;9. The Five Structural Ceilings DPAPI Cannot Close&lt;/h2&gt;
&lt;p&gt;A reader who has followed the chain through §§3-8 has earned the right to a sharp question: where does this whole architecture &lt;em&gt;fail&lt;/em&gt;? Not where does it have bugs (it has very few cryptographic ones); where does the &lt;em&gt;design&lt;/em&gt; draw a line that no implementation patch can move? There are exactly five such lines.&lt;/p&gt;
&lt;h3&gt;9.1 The user-context ceiling&lt;/h3&gt;
&lt;p&gt;Any process running as the user can call &lt;code&gt;CryptUnprotectData&lt;/code&gt; [@ms-cryptprotectdata] or &lt;code&gt;NCryptUnprotectSecret&lt;/code&gt; [@ms-ncryptprotectsecret] against any blob the user could decrypt. The chain binds the secret to the &lt;em&gt;user identity&lt;/em&gt;, not the &lt;em&gt;consuming process identity&lt;/em&gt;. This is the structural reason every modern browser-cookie-stealer family (Lokibot, Vidar, RedLine, Lumma, StealC) works against DPAPI-protected Chrome state keys; it is also the reason Google introduced Chrome app-bound encryption [@thn-app-bound] in July 2024 &lt;em&gt;outside&lt;/em&gt; DPAPI. Will Harris of the Chrome security team is verbatim about why the patch had to live outside DPAPI rather than inside it: &lt;em&gt;&quot;On Windows, Chrome uses the Data Protection API (...). However, the DPAPI does not protect against malicious applications able to execute code as the logged in user -- which info-stealers take advantage of.&quot;&lt;/em&gt;&lt;/p&gt;

On Windows, Chrome uses the Data Protection API (DPAPI). However, the DPAPI does not protect against malicious applications able to execute code as the logged in user -- which info-stealers take advantage of.
-- Will Harris, Chrome security team, July 2024
&lt;h3&gt;9.2 The single-password-derivation ceiling&lt;/h3&gt;
&lt;p&gt;The classic-DPAPI master-key wrap is &lt;code&gt;PBKDF2-HMAC-SHA512(SHA1(NT-hash), SID-as-UTF16LE, ~8000 iterations)&lt;/code&gt; in the modern (Windows 10/11) era per the Passcape table [@passcape-master-key-analysis]. 8 000 iterations of HMAC-SHA-512 is not strong against a modern wordlist attack on a leaked NT hash. The structural limit is &lt;em&gt;the user&apos;s password&lt;/em&gt;, not the cryptographic primitive. The KDF parameter is tunable; the &lt;em&gt;single secret in the chain&lt;/em&gt; is not -- a strong password makes the chain strong, a weak password makes the chain weak, and there is no architectural way to recover from a weak password short of re-deriving every user&apos;s master key under a stronger one.&lt;/p&gt;
&lt;h3&gt;9.3 The KDS-root-key irrotability ceiling&lt;/h3&gt;
&lt;p&gt;Once a KDS root key is in production use, rotating it would invalidate every gMSA &lt;code&gt;msDS-ManagedPassword&lt;/code&gt;, every dMSA password, every &lt;code&gt;SID=&lt;/code&gt; blob, every Hello-for-Business software-KSP container, and every Credential-Guard isolated-secret blob ever produced under it. Microsoft&apos;s documented mitigation is &lt;em&gt;preventative&lt;/em&gt; (a system access control list on &lt;code&gt;msKds-RootKeyData&lt;/code&gt;), not recoverable. This is the same structural ceiling that the Microsoft Learn DPAPI-backup-keys page [@ms-cng-dpapi-backup-keys] admits for the older &lt;code&gt;[MS-BKRP]&lt;/code&gt; keys, in identical language: &lt;em&gt;&quot;There currently is no officially supported way of changing or rotating these DPAPI backup keys on the domain controllers.&quot;&lt;/em&gt; Burn-the-forest-and-rebuild for &lt;code&gt;[MS-BKRP]&lt;/code&gt;; SACL-the-attribute-and-hope for KDS root keys.&lt;/p&gt;
&lt;h3&gt;9.4 The hibernation / S4 ceiling&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CryptProtectMemory&lt;/code&gt; / &lt;code&gt;CryptUnprotectMemory&lt;/code&gt; [@ms-cryptprotectmemory] provide an in-memory scrub primitive that scopes a secret across same-process / cross-process / cross-session lifetimes. They cannot scrub RAM written to &lt;code&gt;hiberfil.sys&lt;/code&gt; on suspend-to-disk. On resume the master key is in plaintext in the page cache. The structural defence is BitLocker on the system volume (the &lt;em&gt;BitLocker on Windows&lt;/em&gt; article in this series covers full-volume encryption end-to-end); within DPAPI itself the ceiling cannot move because the OS has to be able to resume.&lt;/p&gt;
&lt;h3&gt;9.5 The domain-backup-key concentration ceiling&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; backup key is the recoverability story for the password-reset case -- and it is &lt;em&gt;also&lt;/em&gt; the structural reason any DA who can dump LSASS on a writable DC has every user&apos;s master key in the forest. &lt;code&gt;mimikatz &quot;lsadump::backupkeys /system:dc.contoso.local /export&quot;&lt;/code&gt; is the canonical primitive, documented in the Mimikatz DPAPI wiki [@mimikatz-dpapi-wiki]. The architectural answer (HSM-backing the DC&apos;s RSA private key) is not in Microsoft&apos;s mainline guidance; the recommendation when these keys are compromised [@ms-cng-dpapi-backup-keys] is the burn-the-forest-and-rebuild line we just quoted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; These five ceilings are not bugs. They are the design&apos;s price for the design&apos;s other guarantees. The user-context ceiling buys ubiquitous adoption. The single-password ceiling buys a usable recovery path. The KDS-root-key ceiling buys cross-DC determinism. The hibernation ceiling buys process performance and resumability. The domain-backup-key ceiling buys enterprise recovery. Every one of the next five years&apos; DPAPI incidents will hit one of these five ceilings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The 2022-2025 disclosures are not five surprises. They are five different attackers naming five different ceilings out loud. The next section walks the named incidents one ceiling at a time.&lt;/p&gt;
&lt;h2&gt;10. The 2022-2025 Residual Class: Golden gMSA, Golden dMSA, and Chromium App-Bound Encryption&lt;/h2&gt;
&lt;p&gt;In March 2022, Yuval Gordon (Microsoft Security Researcher, via Semperis blog) published &lt;em&gt;Introducing the Golden GMSA Attack&lt;/em&gt; [@semperis-golden-gmsa] and the &lt;code&gt;GoldenGMSA&lt;/code&gt; [@goldengmsa-repo] C# tool. In July 2024, Google announced Chrome&apos;s app-bound encryption [@google-security-blog-app-bound]. In July 2025, Adi Malyanker (also Semperis) published &lt;em&gt;Golden dMSA: What Is dMSA Authentication Bypass?&lt;/em&gt; [@semperis-golden-dmsa] and the &lt;code&gt;GoldenDMSA&lt;/code&gt; [@goldendmsa-repo] tool, mirrored on PR Newswire with a July 16, 2025 dateline [@prnewswire-semperis-dmsa]. Three disclosures in three years, three different ceilings -- but the same underlying pattern: each one is an admission that the structural ceiling cannot be patched inside DPAPI.&lt;/p&gt;

flowchart LR
    C1[&quot;§9.1 user-context&quot;] --&amp;gt; Chromium[&quot;Chromium app-bound encryption&lt;br /&gt;(July 2024, Will Harris)&quot;]
    C2[&quot;§9.3 KDS-root-key irrotability&quot;] --&amp;gt; GGMSA[&quot;Golden gMSA&lt;br /&gt;(March 2022, Y. Gordon)&quot;]
    C2 --&amp;gt; GDMSA[&quot;Golden dMSA&lt;br /&gt;(July 2025, A. Malyanker)&quot;]
    C3[&quot;§9.5 domain-backup-key&quot;] --&amp;gt; MimikatzBKK[&quot;mimikatz lsadump::backupkeys&quot;]
    C4[&quot;§9.4 hibernation / S4&quot;] --&amp;gt; BL[&quot;BitLocker article cross-link&quot;]
&lt;h3&gt;10.1 Golden gMSA (Yuval Gordon, Microsoft / Semperis blog, March 2022)&lt;/h3&gt;
&lt;p&gt;Targets the §9.3 KDS-root-key irrotability ceiling. Gordon is verbatim about the two-step nature of the attack: &lt;em&gt;&quot;An attacker with high privileges can obtain all the ingredients for generating the password of any gMSA in the domain at any time with two steps: Retrieve several attributes from the KDS root key in the domain... Use the GoldenGMSA tool to generate the password of any gMSA associated with the key, without a privileged account.&quot;&lt;/em&gt; Step 1 is a one-shot read of the KDS root key attributes. Step 2 is offline derivation. There is no further DC interaction, ever, because the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt; chain is deterministic&lt;/a&gt; by NIST SP 800-108r1 design.&lt;/p&gt;
&lt;p&gt;The defensive answer is in the GoldenGMSA repository [@goldengmsa-repo]: &lt;em&gt;&quot;configure a SACL on the KDS root key objects for everyone reading the msKds-RootKeyData attribute. Once the system access control list (SACL) is configured, any attempt to dump the key data of a KDS root key will generate security event 4662 on the DC where the object type is msKds-ProvRootKey and the account name is not a DC.&quot;&lt;/em&gt; Plus the cross-trust SACL on &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; with property GUID &lt;code&gt;{0e78295a-c6d3-0a40-b491-d62251ffa0a6}&lt;/code&gt;. This is a &lt;em&gt;detective&lt;/em&gt; control, not a &lt;em&gt;recovery&lt;/em&gt; control. Once the root key has been read, every gMSA password the forest has ever issued or will ever issue under that root key is offline-derivable.&lt;/p&gt;

An attacker with high privileges can obtain all the ingredients for generating the password of any gMSA in the domain at any time with two steps.
-- Yuval Gordon, Microsoft / Semperis blog, March 2022
&lt;p&gt;The Golden gMSA SACL detects same-trust reads only. Cross-trust reads of &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; from a forest the auditing forest does not control are the documented detection blind-spot. If your gMSA-using forest has a one-way trust from a forest you do not own, you cannot see its reads.&lt;/p&gt;
&lt;h3&gt;10.2 Golden dMSA (Adi Malyanker, Semperis, July 2025)&lt;/h3&gt;
&lt;p&gt;Targets the §9.3 ceiling, plus a fresh dMSA-specific surface. Malyanker is verbatim about the structural flaw: &lt;em&gt;&quot;a critical design flaw: a structure that&apos;s used for the password-generation computation contains predictable time-based components with only 1,024 possible combinations, making brute-force password generation computationally trivial.&quot;&lt;/em&gt; The four-phase pipeline is enumerated in the GoldenDMSA repository [@goldendmsa-repo]: &lt;em&gt;&quot;Phase 1: Key Material Extraction (pre requirement of the attack) -- Dump the KDS Root Key from the DC. Phase 2: Enumerate dMSA accounts ... Phase 3: ManagedPasswordID guessing ... Phase 4: Password Generation.&quot;&lt;/em&gt; The tool exposes commands &lt;code&gt;wordlist&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;kds&lt;/code&gt;, &lt;code&gt;bruteforce&lt;/code&gt;, &lt;code&gt;compute&lt;/code&gt;, and &lt;code&gt;convert&lt;/code&gt; -- the operational vocabulary the four-phase pipeline needs.&lt;/p&gt;
&lt;p&gt;Semperis&apos; own rating is MODERATE with the explicit caveat &lt;em&gt;&quot;to exploit it, attackers must possess a KDS root key available only to only the most privileged accounts: root Domain Admins, Enterprise Admins, and SYSTEM.&quot;&lt;/em&gt; That is exactly the §9.3 ceiling re-stated. The novelty in dMSA is the 1 024-combination time-component flaw -- a design weakness on top of the structural ceiling, not a substitute for it.&lt;/p&gt;
&lt;h3&gt;10.3 Chromium app-bound encryption (Will Harris, Google Chrome, July 30, 2024)&lt;/h3&gt;
&lt;p&gt;Targets the §9.1 user-context ceiling. The Google Security Blog announcement [@google-security-blog-app-bound] describes a COM-elevation service that wraps the Chrome state key with both DPAPI &lt;em&gt;and&lt;/em&gt; a per-binary identity check the COM service enforces. The verbatim quote, mirrored via The Hacker News [@thn-app-bound]: &lt;em&gt;&quot;Because the app-bound service is running with system privileges, attackers need to do more than just coax a user into running a malicious app. Now, the malware has to gain system privileges, or inject code into Chrome, something that legitimate software shouldn&apos;t be doing.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The architecturally important word is &lt;em&gt;&quot;app-bound.&quot;&lt;/em&gt; Chromium&apos;s response &lt;em&gt;to the user-context ceiling&lt;/em&gt; lives outside DPAPI. DPAPI itself is unchanged. The 2024 patch is application-layer code-identity pinning -- exactly what Generation-1 Protected Storage&apos;s abandoned Authenticode-access-rule clause was supposed to be in 2000, exactly what Apple Keychain [@apple-platform-security-keychain] has shipped on macOS for over two decades, exactly what the §11 wishlist asks for.&lt;/p&gt;
&lt;h3&gt;10.4 The recurring pattern&lt;/h3&gt;
&lt;p&gt;Each disclosure does &lt;em&gt;not&lt;/em&gt; break a cryptographic primitive. Each is a re-statement of &quot;the design&apos;s ceiling is the design&apos;s ceiling.&quot; The defensive answers are &lt;em&gt;detection&lt;/em&gt; (SACL audit; cross-trust read alerting; binary-identity check) and &lt;em&gt;workaround at a higher layer&lt;/em&gt; (the COM-elevation service Chrome wraps DPAPI in), never &lt;em&gt;cryptographic strengthening of DPAPI itself&lt;/em&gt;. The 2026 reader&apos;s job is to recognise which ceiling each new incident hits.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Disclosure&lt;/th&gt;
&lt;th&gt;Ceiling hit&lt;/th&gt;
&lt;th&gt;Tool reference&lt;/th&gt;
&lt;th&gt;Defensive answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;Golden gMSA (Y. Gordon, Microsoft / Semperis blog)&lt;/td&gt;
&lt;td&gt;§9.3 KDS irrotability&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GoldenGMSA&lt;/code&gt; [@goldengmsa-repo]&lt;/td&gt;
&lt;td&gt;SACL on &lt;code&gt;msKds-RootKeyData&lt;/code&gt;; Event 4662&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;Chromium app-bound encryption (W. Harris, Google)&lt;/td&gt;
&lt;td&gt;§9.1 user-context&lt;/td&gt;
&lt;td&gt;Chrome 127 release notes [@chromereleases-127-stable]&lt;/td&gt;
&lt;td&gt;COM-elevation per-binary identity check, outside DPAPI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025&lt;/td&gt;
&lt;td&gt;Golden dMSA (A. Malyanker, Semperis)&lt;/td&gt;
&lt;td&gt;§9.3 + dMSA &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; predictability&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GoldenDMSA&lt;/code&gt; [@goldendmsa-repo]&lt;/td&gt;
&lt;td&gt;SACL plus monitoring &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; brute-force&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;By 2026 the pattern is clear: DPAPI&apos;s structural ceilings produce a steady drip of disclosures, each defensively answerable but none cryptographically fixable inside DPAPI itself. The open question is what the &lt;em&gt;successor&lt;/em&gt; would even look like -- and that is the next section.&lt;/p&gt;
&lt;h2&gt;11. Open Problems&lt;/h2&gt;
&lt;p&gt;A few sharp open problems remain at the design layer -- problems that a future Generation 4 of the credential-vault tradition would have to solve. None of them is in Microsoft&apos;s published roadmap as of 2026.&lt;/p&gt;
&lt;h3&gt;KDS root-key rotation&lt;/h3&gt;
&lt;p&gt;A hybrid wrap-then-re-wrap-on-first-decrypt-under-new-root scheme could in principle restore rotation without invalidating existing blobs: every consumer would carry a tag indicating which root-key generation last unwrapped it; on first unwrap under a generation-N+1 root the system would re-wrap the consumer-side cache. No standard or product implements this today; no public proposal revises &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-gkdi/943dd4f6-6b80-4a66-8594-80df6d2aad0a&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-GKDI]&lt;/code&gt;&lt;/a&gt; to add it.&lt;/p&gt;
&lt;h3&gt;Code-identity pinning&lt;/h3&gt;
&lt;p&gt;Apple Keychain [@apple-platform-security-keychain] enforces &lt;em&gt;&quot;keychain items can be shared only between apps from the same developer ... enforced through code signing, provisioning profiles, and the Apple Developer Program.&quot;&lt;/em&gt; DPAPI / DPAPI-NG have no equivalent. A &lt;code&gt;CALLER_ATTRIBUTION=Publisher:&amp;lt;wdac-rule-hash&amp;gt;&lt;/code&gt; descriptor would, in principle, give Windows the same property -- the SHA-256 hash of the WDAC rule [@paragmali-com-app-ide] that authorises the calling binary, baked into the descriptor, checked at unwrap time. No one is shipping it. The 2024 Chromium app-bound encryption response [@thn-app-bound] is the application-layer workaround that proves the design gap is real.&lt;/p&gt;
&lt;h3&gt;Post-quantum migration&lt;/h3&gt;
&lt;p&gt;DPAPI-NG today uses RSA or ECDH key transport via CMS enveloped-content format (&lt;code&gt;CERTIFICATE=&lt;/code&gt; with RSA private keys, &lt;code&gt;SID=&lt;/code&gt; for group descriptors) per the protected-data-format [@ms-protected-data-format] reference. Both wrap algorithms are vulnerable to Shor&apos;s algorithm on a sufficiently large quantum computer, and the persistent on-disk blob format is the harvest-now-decrypt-later target -- a framing surfaced across NIST&apos;s broader post-quantum migration corpus, including the NIST PQC project page [@nist-pqc-project] and the linked NIST IR 8547 migration-timeline document. The migration story for the symmetric chain is comparatively easy (the SP800-108 KDF is parameterised; HMAC-SHA-512 has no quantum-cliff weakness for the relevant key sizes). The migration story for the public-key wrap is the hard part. NIST published FIPS 203 (ML-KEM) [@nist-fips-203] and FIPS 204 (ML-DSA) [@nist-fips-204] in August 2024; OpenSSH 9.9 [@openssh-9-9-release] (September 2024) and TLS deployments shipped hybrid post-quantum key exchange. Windows added experimental post-quantum TLS support in 2024 but has not yet announced ML-KEM CNG-DPAPI providers; see the companion &lt;em&gt;Post-Quantum Cryptography on Windows&lt;/em&gt; [@paragmali-com-year-migrati] article in this series for the broader Windows migration story. The shape that fits DPAPI&apos;s ceiling-laden design is hybrid wrap-then-re-wrap-on-first-decrypt: a hybrid wrap (&lt;code&gt;RSA-OAEP || ML-KEM&lt;/code&gt; or &lt;code&gt;ECDH || ML-KEM&lt;/code&gt;) -- protect under (RSA+ML-KEM) or (ECDH+ML-KEM) today; let consumers re-wrap to the new combiner on first unwrap; phase out the classical half on a long horizon -- is the only forward-compatible answer; Microsoft&apos;s published DPAPI-NG protection-providers [@ms-protection-providers] have not yet announced one.&lt;/p&gt;
&lt;h3&gt;Credential roaming for Entra-joined-only / unmanaged-device estates&lt;/h3&gt;
&lt;p&gt;Classic DPAPI&apos;s cross-device story has always been &quot;use roaming profiles&quot; (deprecated) or &quot;use the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; backup key&quot; (admin-recovery, not user-driven). DPAPI-NG&apos;s &lt;code&gt;SID=&lt;/code&gt; solves it cleanly for AD-joined estates but the modern Entra-only estate has no native equivalent -- the &lt;code&gt;LOCAL=user&lt;/code&gt; descriptor is per-machine. An &lt;code&gt;ENTRAGROUP=&amp;lt;object-id&amp;gt;&lt;/code&gt; descriptor that resolved through Entra ID Token Service the way &lt;code&gt;SID=&lt;/code&gt; resolves through KDS would close the gap. No public roadmap announces this.&lt;/p&gt;
&lt;h3&gt;Hibernation / S4&lt;/h3&gt;
&lt;p&gt;BitLocker [@wikipedia-bitlocker] on the system volume defends the disk; suspending fully to ROM (or refusing S4 entirely) defends the in-RAM master key. Hardware-bound key derivation (TPM-released-only-while-PCRs-stable) would close more of the gap; the &lt;em&gt;TPM in Windows&lt;/em&gt; article in this series covers TPM-bound primitives that approximate this property.&lt;/p&gt;
&lt;p&gt;Every one of these is a &lt;em&gt;design&lt;/em&gt; gap -- a property the architecture would need a new primitive to satisfy. None is on Microsoft&apos;s announced roadmap. The architecture we have is the architecture we will have for at least the next five years; the practitioner&apos;s job is to know which ceilings their estate is exposed to and how to detect each of them.&lt;/p&gt;
&lt;h2&gt;12. Practical Guide and Closing&lt;/h2&gt;
&lt;p&gt;The four-audience guide for the 2026 practitioner.&lt;/p&gt;
&lt;h3&gt;12.1 For a developer&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;CryptProtectData&lt;/code&gt; / &lt;code&gt;CryptUnprotectData&lt;/code&gt; [@ms-cryptprotectdata] for per-user-on-this-device secrets. Pass &lt;code&gt;pOptionalEntropy&lt;/code&gt; to &lt;em&gt;bind&lt;/em&gt; the blob to a per-application secret -- but understand it is security-by-obscurity, not a code-identity check; any reader of the SharpDPAPI source [@sharpdpapi-readme] who knows your constant entropy can reproduce the unprotect call as the user.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;NCryptProtectSecret&lt;/code&gt; [@ms-ncryptprotectsecret] with the appropriate descriptor for cross-device or multi-principal cases. &lt;code&gt;LOCAL=user&lt;/code&gt; mirrors classic DPAPI on a single machine. &lt;code&gt;SID=&amp;lt;group-sid&amp;gt;&lt;/code&gt; reaches AD groups via KDS. &lt;code&gt;CERTIFICATE=HashID:&amp;lt;sha1&amp;gt;&lt;/code&gt; reaches a named certificate (TPM-backed for the high-security case). Use the WebAuthn / FIDO2 path for &lt;em&gt;authentication&lt;/em&gt; secrets; do not store passwords in DPAPI when WHfB / passkey paths are available.&lt;/p&gt;
&lt;p&gt;{`
// Returns the appropriate DPAPI-NG protection-descriptor string for a use case.
// Reference: learn.microsoft.com windows win32 seccng protection-descriptors
function descriptorFor(useCase, ctx) {
  switch (useCase) {
    case &quot;single-device-single-user&quot;:
      return &quot;LOCAL=user&quot;;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;case &quot;ad-group&quot;:
  // Multiple machines, AD-authorized group members can decrypt.
  return &quot;SID=&quot; + ctx.groupSid;

case &quot;tpm-backed-cert&quot;:
  // Decrypter must hold the named certificate&apos;s private key (TPM-bound KSP).
  return &quot;CERTIFICATE=HashID:&quot; + ctx.certThumbprintSha1;

case &quot;web-credential&quot;:
  // Resolves through the Windows credential broker.
  return &quot;WEBCREDENTIALS=&quot; + ctx.credName;

default:
  throw new Error(&quot;Unknown use case: &quot; + useCase);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  }
}&lt;/p&gt;
&lt;p&gt;console.log(descriptorFor(&quot;single-device-single-user&quot;));
console.log(descriptorFor(&quot;ad-group&quot;, { groupSid: &quot;S-1-5-21-...-5101&quot; }));
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;pOptionalEntropy&lt;/code&gt; parameter to &lt;code&gt;CryptProtectData&lt;/code&gt; lets you tag a blob with an extra secret the unwrap call must supply. It does not bind the blob to a process or a publisher. If your &quot;entropy&quot; is a constant compiled into your binary, every reverse-engineer who reads the binary can reproduce your unprotect call as the user. For real per-application separation today, use the Chromium 2024 pattern [@thn-app-bound]: wrap your DPAPI / DPAPI-NG blob in a SYSTEM-elevated COM service that enforces a per-binary identity check.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;12.2 For a defender or DFIR analyst&lt;/h3&gt;
&lt;p&gt;Triage the credential-vault inventory in §5 first. The high-value paths are &lt;code&gt;%APPDATA%\Microsoft\Protect\&amp;amp;lt;SID&amp;amp;gt;\&lt;/code&gt;, &lt;code&gt;%APPDATA%\Microsoft\Protect\CREDHIST&lt;/code&gt;, &lt;code&gt;%APPDATA%\Microsoft\Credentials\&lt;/code&gt;, &lt;code&gt;%LOCALAPPDATA%\Microsoft\Vault\&lt;/code&gt;, the Chromium / Edge profile databases, and the AD &lt;code&gt;CN=Master Root Keys,...&lt;/code&gt; container.&lt;/p&gt;
&lt;p&gt;The SACL guidance from the GoldenGMSA repository [@goldengmsa-repo] is the only detective control today: &lt;em&gt;&quot;configure a SACL on the KDS root key objects for everyone reading the msKds-RootKeyData attribute. Once the system access control list (SACL) is configured, any attempt to dump the key data of a KDS root key will generate security event 4662 on the DC where the object type is msKds-ProvRootKey and the account name is not a DC.&quot;&lt;/em&gt; Plus the cross-trust SACL on &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; with property GUID &lt;code&gt;{0e78295a-c6d3-0a40-b491-d62251ffa0a6}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tooling: Mimikatz [@mimikatz-dpapi-wiki] &lt;code&gt;dpapi::*&lt;/code&gt; modules, SharpDPAPI [@sharpdpapi-readme], DPAPIck [@bursztein-talk-page] (Bursztein-Picod 2010), GoldenGMSA [@goldengmsa-repo], GoldenDMSA [@goldendmsa-repo], and the Volatility [@volatility3-repo] &lt;code&gt;lsadump&lt;/code&gt; / &lt;code&gt;cachedump&lt;/code&gt; / &lt;code&gt;hashdump&lt;/code&gt; plugins for live-memory extraction of &lt;code&gt;DPAPI_SYSTEM&lt;/code&gt; and the other LSA secrets that seed SYSTEM-context master-key derivation.&lt;/p&gt;
&lt;p&gt;{`&lt;/p&gt;
Walk a synthetic profile-directory layout and emit a DPAPI-relevant triage report.
&lt;p&gt;import os
from collections import defaultdict&lt;/p&gt;
Synthetic profile layout for demonstration only.
&lt;p&gt;synthetic = {
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/S-1-5-21-1234-1001/Preferred&quot;: &quot;8KB&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/S-1-5-21-1234-1001/0d4a...&quot;: &quot;740B&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Protect/CREDHIST&quot;: &quot;176B&quot;,
    &quot;Users/alice/AppData/Roaming/Microsoft/Credentials/abcdef...&quot;: &quot;300B&quot;,
    &quot;Users/alice/AppData/Local/Microsoft/Vault/4BF4C442-9B8A-41A0-B380-DD4A704DDB28/Policy.vpol&quot;: &quot;180B&quot;,
    &quot;Users/alice/AppData/Local/Google/Chrome/User Data/Default/Cookies&quot;: &quot;4MB&quot;,
    &quot;Users/alice/AppData/Local/Google/Chrome/User Data/Local State&quot;: &quot;12KB&quot;,
}&lt;/p&gt;
&lt;p&gt;categories = {
    &quot;Master keys&quot;:          &quot;/Microsoft/Protect/S-1-&quot;,
    &quot;CREDHIST chain&quot;:       &quot;/Protect/CREDHIST&quot;,
    &quot;Credential Manager&quot;:   &quot;/Microsoft/Credentials/&quot;,
    &quot;Windows Vault&quot;:        &quot;/Microsoft/Vault/&quot;,
    &quot;Chrome state key&quot;:     &quot;/Google/Chrome/User Data/Local State&quot;,
    &quot;Chrome cookies&quot;:       &quot;/Google/Chrome/User Data/Default/Cookies&quot;,
}&lt;/p&gt;
&lt;p&gt;report = defaultdict(list)
for path, size in synthetic.items():
    for label, marker in categories.items():
        if marker in path:
            report[label].append((path, size))&lt;/p&gt;
&lt;p&gt;for label, items in report.items():
    print(&quot;==&quot;, label)
    for path, size in items:
        print(&quot;  &quot;, path, &quot;(&quot; + size + &quot;)&quot;)
`}&lt;/p&gt;
&lt;h3&gt;12.3 For a red-team operator&lt;/h3&gt;
&lt;p&gt;The chain of primitives most-commonly used (verbatim from the harmj0y operational guide [@harmj0y-operational-guide] and the Mimikatz wiki [@mimikatz-dpapi-wiki]):&lt;/p&gt;

The operational vocabulary, in order of dependency:&lt;ol&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;sekurlsa::dpapi&quot;&lt;/code&gt; -- enumerate cached master keys from a live &lt;code&gt;lsass.exe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;dpapi::masterkey /in:&amp;lt;MK&amp;gt; /sid:&amp;amp;lt;SID&amp;amp;gt; /password:&amp;lt;known&amp;gt;&quot;&lt;/code&gt; -- unwrap a master-key file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;dpapi::cred /in:&amp;lt;credfile&amp;gt;&quot;&lt;/code&gt; -- decrypt a Credential Manager entry.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mimikatz &quot;lsadump::backupkeys /system:dc.contoso.local /export&quot;&lt;/code&gt; -- export the &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;[MS-BKRP]&lt;/code&gt;&lt;/a&gt; RSA private key from a writable DC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SharpDPAPI triage /pvk:key.pvk&lt;/code&gt; -- offline triage with the domain backup key.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SharpChrome cookies /pvk:key.pvk&lt;/code&gt; -- decrypt Chrome / Edge cookies offline.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GoldenGMSA gmsainfo&lt;/code&gt; then &lt;code&gt;GoldenGMSA compute -k &amp;lt;root-key-guid&amp;gt; -s &amp;lt;gmsa-sid&amp;gt; -m &amp;lt;managed-password-id&amp;gt;&lt;/code&gt; -- offline gMSA password derivation per the March 2022 disclosure [@semperis-golden-gmsa].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GoldenDMSA wordlist&lt;/code&gt; / &lt;code&gt;bruteforce&lt;/code&gt; / &lt;code&gt;compute&lt;/code&gt; -- the four-phase Server 2025 dMSA pipeline per the July 2025 disclosure [@semperis-golden-dmsa].&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;The post-Credential-Guard scope reality: LSASS-isolated NT-hashes are gone (the &lt;em&gt;Credential Guard&lt;/em&gt; article in this series covers what &lt;code&gt;LsaIso.exe&lt;/code&gt; actually computes); on-disk DPAPI master keys, Chrome cookies, and Vault credentials are still there. The credential-vault inventory in §5 is the operator&apos;s map; the §10 disclosure list is the operator&apos;s playbook.&lt;/p&gt;
&lt;h3&gt;12.4 For a platform or identity engineer&lt;/h3&gt;
&lt;p&gt;Provision the KDS root key carefully. Use the &lt;code&gt;Add-KdsRootKey&lt;/code&gt; [@ms-add-kdsrootkey] default 10-day &lt;code&gt;EffectiveTime&lt;/code&gt; for production forests so AD replication converges before any consumer derives against the new key; the &lt;code&gt;-EffectiveTime ((Get-Date).AddHours(-10))&lt;/code&gt; override is for single-DC test forests only, never production.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Golden gMSA defensive answer is detective, not preventive. Configure the &lt;code&gt;msKds-RootKeyData&lt;/code&gt; SACL &lt;em&gt;before&lt;/em&gt; any production gMSA exists, so every read of the root-key attributes generates Security Event 4662 and you have a baseline of &quot;DC accounts only, no humans, ever.&quot; Add the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; cross-trust audit on day 1 too. After-the-fact SACL provisioning leaves a window during which the key may have been read silently.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Server 2025 dMSA, monitor the &lt;code&gt;msDS-ManagedPasswordId&lt;/code&gt; [@ms-ms-adts-managedpassword] brute-force surface until Microsoft addresses the time-component predictability the Golden dMSA disclosure [@semperis-golden-dmsa] named.&lt;/p&gt;
&lt;p&gt;For Hello for Business, prefer the TPM-bound KSP (&lt;code&gt;MS_PLATFORM_CRYPTO_PROVIDER&lt;/code&gt;); the software-KSP DPAPI-NG fallback [@ms-whfb-howitworks] is the structural worst case (per §8.3) and inherits the KDS root-key dependency on every TPM-less device.&lt;/p&gt;
&lt;p&gt;Cross-platform context: Apple Keychain [@apple-platform-security-keychain] reaches a stronger upper bound (Secure-Enclave-bound + code-identity-pinned via the Apple Developer Program); GNOME libsecret [@libsecret-reference] covers the analogous Linux primitive over the Secret Service D-Bus interface. Neither is a drop-in replacement; both have shapes worth borrowing if Microsoft ever publishes the Generation-4 design.&lt;/p&gt;
&lt;h3&gt;12.5 The closing reflection&lt;/h3&gt;
&lt;p&gt;The credential vault under everything has a single-sentence summary in 2026: classic DPAPI is as strong as the user&apos;s password; DPAPI-NG is as strong as the KDS root key&apos;s life-cycle SOP is; both architectures admit ceilings the cryptography cannot move. The literacy a practitioner needs is the ability to recognise which ceiling any new incident hits. Twelve sections later, you have it.&lt;/p&gt;
&lt;h2&gt;Frequently Asked Questions&lt;/h2&gt;

No. Credential Guard [@ms-credential-guard] protects LSA-isolated secrets only. Chrome cookies live in the user&apos;s profile under DPAPI / DPAPI-NG and are decryptable by any process running as the user, exactly as before. The Chromium 2024 app-bound encryption [@thn-app-bound] is a per-process workaround for the §9.1 user-context ceiling, not a fix inside DPAPI itself.

A web reset of a *consumer* Microsoft Account password does not append to CREDHIST and does not benefit from [`[MS-BKRP]`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-bkrp/) backup -- there is no domain in the consumer scenario. Master keys encrypted under the previous password become irrecoverable for consumer Microsoft Accounts, full stop. Domain-joined enterprise users escape this because the domain backup key still works.

True if the KDS root key [@ms-add-kdsrootkey] is intact -- the Semperis write-up [@semperis-golden-gmsa] records the *&quot;randomly generated password of 256 bytes, making it infeasible to crack&quot;* claim. False under the Golden gMSA / Golden dMSA [@semperis-golden-dmsa] assumption that any DA / SYSTEM on a DC can read `msKds-RootKeyData`. A 256-byte random password is irrelevant if the attacker can derive it offline.

No. DPAPI-NG [@ms-cng-dpapi] is a redesign whose protection model is *descriptor-based* (multi-principal, multi-device) rather than *user-and-machine-bound*. The two APIs coexist; classic DPAPI is still the default for `CryptProtectData` [@ms-cryptprotectdata] callers, and DPAPI-NG is the path for `NCryptProtectSecret` [@ms-ncryptprotectsecret] callers.

No. On TPM-less devices the WHfB private key sits in a CNG software-KSP container persisted as a DPAPI-NG blob whose protection descriptor binds it to user SID + device, per the Hello for Business architecture [@ms-whfb-howitworks]. The TPM-bound case is the preferred deployment; the software-KSP fallback is the structural worst case and inherits the §9.3 KDS root-key dependency.

No. `CryptProtectMemory` [@ms-cryptprotectmemory] scrubs in-memory secrets between same-process / cross-process / cross-session lifetimes but cannot prevent the OS from writing the page-protected RAM into `hiberfil.sys` on suspend-to-disk. BitLocker on the system volume is the structural defence (the *BitLocker on Windows* article in this series covers full-volume encryption end-to-end).

No. It broke the *secrecy of DPAPI&apos;s design*. The 2010 disclosure [@usenix-woot10] made the master-key chain public and tractable for offline forensics; it did not weaken the cryptography. The &quot;break&quot; was always structural -- DPAPI is as strong as the user&apos;s password is. The two-author byline is Bursztein and Picod (Black Hat DC 2010, USENIX WOOT 10), not &quot;Bursztein, Picod and Aussel.&quot;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;dpapi-and-dpapi-ng-the-credential-vault-under-everything&quot; keyTerms={[
  { term: &quot;DPAPI&quot;, definition: &quot;The Data Protection API; the per-user / per-machine secret-storage primitive in every Windows release from Windows 2000 onward.&quot; },
  { term: &quot;Master key&quot;, definition: &quot;A 64-byte random secret per user, stored under %APPDATA%/Microsoft/Protect/&amp;lt;SID&amp;gt;/&amp;lt;GUID&amp;gt;, encrypted under a pre-key derived from the user&apos;s password and SID.&quot; },
  { term: &quot;[MS-BKRP] BackupKey Remote Protocol&quot;, definition: &quot;The LSASS-hosted RPC interface that lets a member computer dual-wrap its master key under both the user password pre-key and a DC RSA backup public key; the canonical universal-decryption primitive available to Domain Admins.&quot; },
  { term: &quot;CREDHIST&quot;, definition: &quot;The previous-password hash chain stored in %APPDATA%/Microsoft/Protect/CREDHIST; one entry per self-initiated password change; broken by administrative reset and consumer-Microsoft-Account web reset.&quot; },
  { term: &quot;Protection descriptor (DPAPI-NG)&quot;, definition: &quot;The DPAPI-NG self-describing string (SID, SDDL, LOCAL, WEBCREDENTIALS, CERTIFICATE) that names the set of principals permitted to remove protection from a blob.&quot; },
  { term: &quot;Microsoft Key Distribution Service (kdssvc.dll)&quot;, definition: &quot;The DC-side daemon that implements the [MS-GKDI] protocol and computes per-(group, period) keys deterministically from a single forest-wide root key.&quot; },
  { term: &quot;KDS root key&quot;, definition: &quot;The single forest-wide secret that anchors every per-(group, period) key the KDS will ever derive; provisioned exactly once per forest with Add-KdsRootKey; documented as having no rotation procedure.&quot; },
  { term: &quot;Group Managed Service Account (gMSA)&quot;, definition: &quot;A Server-2012-introduced AD account whose 256-byte password is derived from the KDS chain and rotated every 30 days, gated by the msDS-GroupMSAMembership SDDL.&quot; },
  { term: &quot;Software KSP&quot;, definition: &quot;The non-hardware-bound CNG Key Storage Provider that persists key material as DPAPI-NG-protected files; used as the WHfB fallback on TPM-less devices.&quot; },
  { term: &quot;Golden gMSA / Golden dMSA&quot;, definition: &quot;The 2022 / 2025 Semperis offline-derivation attacks that compute any gMSA / dMSA password the forest will ever issue, given a one-shot read of the four KDS root-key attributes.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>dpapi</category><category>dpapi-ng</category><category>kds</category><category>gmsa</category><category>credential-guard</category><category>mimikatz</category><category>golden-gmsa</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The Empty Hash: Credential Guard, the LsaIso Trustlet, and the Eleven-Year LSASS Extraction Tradition</title><link>https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/</link><guid isPermaLink="true">https://paragmali.com/blog/the-empty-hash-credential-guard-the-lsaiso-trustlet-and-the-/</guid><description>Why a 2026 Mimikatz dump returns [LSA Isolated Data] instead of an NTLM hash, what LsaIso.exe really computes, and the five things Credential Guard was never going to close.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Credential Guard moves the long-lived NTLM hash and the Kerberos long-term key out of `lsass.exe` (in the VTL0 NT kernel) and into `LsaIso.exe` (in VTL1, behind the hypervisor).** The hash is no longer in the dump because the hash is no longer in the process. Default-on for domain-joined, non-domain-controller Windows 11 22H2+ and Windows Server 2025 systems that meet the hardware requirements [@ms-cg-overview]. The architecture closes the eleven-year LSASS-memory-dump class. It does not close credential **use** (Kerberoast [@attack-kerberoast]), token impersonation (the PrintSpoofer / Potato chain [@itm4n-printspoofer]), plaintext-secret protocols [@ms-cg-considerations] (NTLMv1, MS-CHAPv2, Digest, CredSSP), or the trustlet&apos;s own RPC output (Pass-the-Challenge, December 2022 [@lyak-passchallenge-wayback]). This is the deep look at the canonical VBS trustlet -- the encrypted-blob fields, the IUM API surface, the five residual attack classes, and Microsoft&apos;s own honest accounting of what Credential Guard was never going to protect.
&lt;h2&gt;1. The 3:14 a.m. Mimikatz that returned an empty hash&lt;/h2&gt;
&lt;p&gt;It is 3:14 a.m. on a 2026 Windows 11 24H2 box. The operator has SYSTEM. The operator has &lt;code&gt;SeDebugPrivilege&lt;/code&gt;. The operator has bypassed Protected Process Light the way PPLdump [@github-ppldump] did in 2021, has dumped &lt;code&gt;lsass.exe&lt;/code&gt; with &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; from Mimikatz [@github-mimikatz], and is staring at the screen.&lt;/p&gt;
&lt;p&gt;For the nine years before mid-2015, the next line on that screen would have been the user&apos;s NTLM hash. Tonight, the next line is something else entirely.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;msv : [00000003] Primary * Username : alice * Domain   : CONTOSO * NTLM     : [LSA Isolated Data] Is NT Present: True Context Handle: 0x1b6d5216c60 Proxy Info: 0x7ffdd8bfd380 Encrypted blob: a000000000000000080000006400000001000000010100000100000036...4e746c6d48617368... DPAPI: c02c86e371103ad7d7d352b19af1a74a00000000&lt;/code&gt; Structurally identical to the PassTheChallenge README [@github-passthechallenge] example, with username and domain renamed for narrative clarity. Hex prefix, field names, and embedded &lt;code&gt;NtlmHash&lt;/code&gt; ASCII tag are verbatim. This is the artefact that tells the operator the architectural shift happened.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The literal string &lt;code&gt;[LSA Isolated Data]&lt;/code&gt; sits where the NTLM hash used to sit. The hex prefix &lt;code&gt;a000000000000000&lt;/code&gt; is the same prefix on every Credential-Guard-protected box on the planet. The trailing ASCII tag &lt;code&gt;4e746c6d48617368&lt;/code&gt; decodes to &lt;code&gt;NtlmHash&lt;/code&gt;: the field name survives, the value does not.&lt;/p&gt;
&lt;p&gt;This article is the deep look at the canonical VBS trustlet that is responsible for that empty hash. It is the companion piece to the broader VBS trustlets treatment in this series [@paragmali-com-secure-kernel], which uses &lt;code&gt;LsaIso.exe&lt;/code&gt; as its running example without unfolding the four things that matter most about it: the eleven-year extraction history that motivated the design; what &lt;code&gt;LsaIso.exe&lt;/code&gt; actually computes and what every field of the encrypted blob means; Pass-the-Challenge -- the residual class Credential Guard was never going to close; and the honest, Microsoft-documented limits [@ms-cg-howitworks], enumerated.&lt;/p&gt;
&lt;p&gt;A note on intent and verification: this is defensive research. Every primary source was verified live on 2026-05-11, against the public web; every command and tool named is in the open-source security canon, used today by Microsoft&apos;s own product teams, by enterprise red teams, and by every blue team that takes the storage-versus-use distinction seriously.&lt;/p&gt;
&lt;p&gt;The hash is not in the dump because the hash is no longer in the process. Where it went, and why Microsoft moved it, is twenty-two years of &lt;code&gt;lsass.exe&lt;/code&gt; history.&lt;/p&gt;
&lt;h2&gt;2. Why LSASS became the single highest-value memory dump on Windows (1993--2014)&lt;/h2&gt;
&lt;p&gt;Twenty-two years before the empty hash, &lt;code&gt;lsass.exe&lt;/code&gt; shipped in Windows NT 3.1. It was not, at first, the most-attacked process on Windows. It became that, slowly, over the course of eleven years and one tool. This is the tradition the trustlet was built to break.&lt;/p&gt;

The user-mode Windows service that handles interactive logon, NTLM challenge-response, Kerberos AS/TGS exchanges, security-policy enforcement, password changes, and the loading of every Security Support Provider DLL the system uses for authentication. Until Credential Guard, it also held every long-lived authentication secret for every signed-in user in its own process memory, because the protocols it implemented required the secret to be present when the network talked to it. See the canonical LSA Authentication [@ms-lsa-authentication] reference.
&lt;p&gt;The architectural reason &lt;code&gt;lsass.exe&lt;/code&gt; had to hold the secret is structural to the protocols it speaks. NTLM [@paragmali-com-in-windows] and Kerberos are challenge-response protocols. The server sends a challenge; the client encrypts the challenge with a key derived from the password; the server compares. The key the client uses is not the password itself but the NT one-way function output (NTOWF) [@wiki-pth] -- the MD4 of the UTF-16-LE password. For Kerberos the client uses a long-term key (DES, RC4, or AES) derived from the password under a protocol-defined string-to-key function [@en-wikipedia-org-wiki-kerberosprotocol]). In both cases the server expects the client to prove possession of a value that is functionally equivalent to the password, every time the client authenticates.&lt;/p&gt;

The MD4 hash of the UTF-16-LE encoded password. Despite the name, NTOWF is one-way only with respect to the original password. With respect to the network, the NTOWF *is* the credential: any process that holds it can compute the response to any NTLM challenge any server will ever issue, with no further information about the user.
&lt;p&gt;For single-sign-on to work -- the user types the password once, the OS uses it transparently for every later authentication that day -- something has to remember that derived value, in clear, in a process that wakes up whenever a remote service asks the kernel to authenticate. That something is &lt;code&gt;lsass.exe&lt;/code&gt;. Until 2015, &quot;remembers&quot; meant &quot;holds the bytes in process memory.&quot;The phrase &quot;the hash is the password&quot; is not a metaphor. The NTLM challenge-response computation &lt;code&gt;DESL(NTOWF, challenge)&lt;/code&gt; (three separate DES encryptions on 7-byte key segments per MS-NLMP section 3.3.1) accepts the NTOWF directly. An attacker who holds the NTOWF and can reach a server that speaks NTLM does not need to know the password at all. This is the &lt;em&gt;structural&lt;/em&gt; reason Pass-the-Hash works on every NTLM-speaking service in the network.&lt;/p&gt;
&lt;h3&gt;The eight inflection points&lt;/h3&gt;
&lt;p&gt;In 1997, Paul Ashton published the original Pass-the-Hash technique on Bugtraq [@wiki-pth] -- a modified Samba SMB client that accepted user password hashes instead of cleartext passwords. The conceptual claim landed: if the client only proves possession of the hash, the hash is the credential. The implementation claim took another eleven years to land.&lt;/p&gt;
&lt;p&gt;In 2001, Sir Dystic of Cult of the Dead Cow disclosed SMBRelay at lanta.con on March 31 [@cdc-smbrelay] (not March 21 as some Wikipedia revisions claim, per the project&apos;s own page). SMBRelay was the &lt;em&gt;use&lt;/em&gt;-class breakthrough: rather than crack the hash, intercept the protocol exchange and let the victim&apos;s own client do the cryptography against the attacker&apos;s chosen target.&lt;/p&gt;
&lt;p&gt;In 2008, Hernan Ochoa shipped the Pass-the-Hash Toolkit [@wiki-pth] -- the load-bearing 2008 contribution -- and introduced &quot;dump the hash from &lt;code&gt;lsass.exe&lt;/code&gt; memory&quot; as a public, repeatable post-exploitation technique. The toolkit was later superseded by Windows Credential Editor [@wiki-pth]. For the first time, an attacker did not need to crack anything. The attacker needed &lt;code&gt;OpenProcess(VM_READ)&lt;/code&gt; on &lt;code&gt;lsass.exe&lt;/code&gt; and a parser.The Pass-the-Hash Toolkit and Windows Credential Editor [@wiki-pth] were the immediate ancestors of Mimikatz. They established the LSASS-process-memory dump as the canonical credential-extraction primitive on Windows; Mimikatz only had to follow the trail and add WDigest plaintext recovery on top.&lt;/p&gt;
&lt;p&gt;In May 2011, Benjamin Delpy released Mimikatz, closed-source [@wired-mimikatz], and added one feature on top of WCE that turned the field upside down: &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; returned not just NTLM hashes but plaintext WDigest passwords. WDigest -- a digest-authentication SSP that Microsoft had shipped in Windows XP and Server 2003 to support HTTP digest -- stored the encrypted password blob &lt;em&gt;and&lt;/em&gt; the encryption key in &lt;code&gt;lsass.exe&lt;/code&gt; memory, simultaneously, so that the SSP could re-derive the digest response on demand. Delpy called the result, accurately, &quot;like storing a password-protected secret in an email with the password in the same email&quot; [@wired-mimikatz].&lt;/p&gt;

It&apos;s like storing a password-protected secret in an email with the password in the same email. -- Benjamin Delpy, on the WDigest plaintext-cache architecture
&lt;p&gt;In September 2011, Mimikatz was used in the DigiNotar breach [@wiki-diginotar] -- the certificate-authority compromise that issued forged certificates for Google, Microsoft, and Twitter domains, used via MITM against roughly 300,000 Iranian Gmail users [@wiki-diginotar]. Mimikatz crossed from researcher curio to nation-state-grade tradecraft in a single news cycle.Wired&apos;s profile [@wired-mimikatz] recounts an early-2012 Positive Hack Days incident in Moscow in which, immediately after Delpy&apos;s Mimikatz talk, a man in a dark suit demanded that Delpy put his slides and a copy of Mimikatz on a USB drive. Delpy complied and then -- before leaving Russia -- published the code as open source on GitHub. It is the moment Delpy realised he had built something that nation-state services were now travelling to obtain in person.&lt;/p&gt;
&lt;p&gt;On April 6, 2014, at 22:02:03, Delpy committed Mimikatz 2.0 to GitHub as open source [@github-mimikatz]. The compile timestamp is in the README banner, verbatim. Microsoft&apos;s lead time on every WDigest-class disclosure dropped from &quot;months&quot; to &quot;the next minute any attacker reads the README.&quot;&lt;/p&gt;
&lt;p&gt;On May 13, 2014, Microsoft shipped KB2871997 / MSA 2871997 [@ms-kb2871997]. On Windows 8.1 and Server 2012 R2 and later, the registry value &lt;code&gt;WDigest\UseLogonCredential&lt;/code&gt; defaults to &lt;code&gt;0&lt;/code&gt; and WDigest no longer caches plaintext credentials in &lt;code&gt;lsass.exe&lt;/code&gt; memory. The plaintext leg closed. The hash leg could not, because the protocol required it.&lt;/p&gt;

timeline
    title LSASS as the highest-value Windows process, 1993-2014
    1993 : NT 3.1 ships : lsass.exe holds NTOWF + Kerberos keys
    1997 : Paul Ashton : Pass-the-Hash on Bugtraq
    2001 : Sir Dystic : SMBRelay at lanta.con
    2008 : Hernan Ochoa : Pass-the-Hash Toolkit (later WCE)
    2011 : Benjamin Delpy : Mimikatz closed-source release (May)
    2011 : DigiNotar breach : Mimikatz used in the wild (September)
    2014 : Mimikatz 2.0 : GitHub open-source (April 6, 22:02:03)
    2014 : KB2871997 : WDigest cache disabled by default (May 13)

The class of attack in which an authenticated client proves possession of an NTOWF (the NT one-way function output, MD4 of the UTF-16-LE password) directly, without ever knowing the cleartext password. The technique was originally published by Paul Ashton in 1997 [@wiki-pth] and was made native to Windows by Hernan Ochoa&apos;s 2008 Pass-the-Hash Toolkit [@wiki-pth]. It is structural to the NTLM protocol; closing the class requires either eliminating the protocol or moving the hash out of any process the attacker can read.
&lt;p&gt;By May 2014, Microsoft had patched what could be patched. Mimikatz 2.0 was on GitHub. The hash was still in the process, because it had to be. The next move had to be architectural. But before Microsoft made that move, they tried four other things.&lt;/p&gt;
&lt;h2&gt;3. What Microsoft tried before trustlets (2007--2014)&lt;/h2&gt;
&lt;p&gt;If you cannot move the secret, what can you do? Microsoft tried four answers between 2007 and 2014. Each is in production today. None of them moves the secret.&lt;/p&gt;
&lt;h3&gt;Generation 2: Vista&apos;s Protected Process (2007)&lt;/h3&gt;
&lt;p&gt;In Windows Vista, Microsoft introduced the Protected Process [@ionescu-bh2015-pdf] primitive: a binary signed under a designated Microsoft media-protection certificate could run in a process whose memory other Windows processes -- including processes running as administrator -- could not read or modify. The reason was DRM. Audio and video pipelines wanted a way to keep AACS and PlayReady decryption keys out of debuggers. The Protected Process primitive was not, in 2007, applied to &lt;code&gt;lsass.exe&lt;/code&gt;. Six years passed before Microsoft generalised it.&lt;/p&gt;
&lt;h3&gt;Generation 3: LSA Protection / &lt;code&gt;RunAsPPL&lt;/code&gt; (2013)&lt;/h3&gt;
&lt;p&gt;In Windows 8.1, Microsoft generalised Protected Process into Protected Process Light (PPL) [@itm4n-runasppl], a signer-level lattice that allowed multiple signer &quot;kinds&quot; to live alongside the original DRM kind, and the &lt;code&gt;RunAsPPL&lt;/code&gt; registry value lit up &lt;code&gt;lsass.exe&lt;/code&gt; as a PPL [@paragmali-com-app-ide].&lt;/p&gt;

A Windows process that runs at a signer-level higher than ordinary administrator processes, such that ordinary administrators cannot open it for memory read or for code injection. Created in Windows 8.1 as a generalisation of the Vista Protected Process primitive. Enforcement is done by the NT kernel: `OpenProcess` with `PROCESS_VM_READ` from a non-PPL caller returns `ERROR_ACCESS_DENIED` (0x5) [@itm4n-runasppl] regardless of the caller&apos;s token privileges.
&lt;p&gt;itm4n&apos;s reference write-up of &lt;code&gt;RunAsPPL&lt;/code&gt; [@itm4n-runasppl] reproduces what Mimikatz sees on a PPL-protected &lt;code&gt;lsass.exe&lt;/code&gt;: the call to &lt;code&gt;OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, lsass_pid)&lt;/code&gt; -- the verbatim opener of &lt;code&gt;kuhl_m_sekurlsa_acquireLSA()&lt;/code&gt; -- fails with &lt;code&gt;0x00000005&lt;/code&gt;, &lt;code&gt;ERROR_ACCESS_DENIED&lt;/code&gt;. The hash extraction routine never runs, because the attacker cannot read the page.&lt;/p&gt;
&lt;p&gt;itm4n&apos;s writeup is also the canonical source for what &lt;code&gt;RunAsPPL&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt;. The same NT kernel that enforces PPL is the kernel the attacker is trying to subvert. Two bypass classes exist in the public record. The first is kernel-mode: an attacker who loads a signed driver -- including Delpy&apos;s own &lt;code&gt;mimidrv.sys&lt;/code&gt; [@itm4n-runasppl] -- can suspend PPL enforcement from kernel-space because the kernel is the enforcement mechanism. This is the &lt;em&gt;bring your own vulnerable driver&lt;/em&gt; bypass class.&lt;/p&gt;

A privilege-escalation pattern in which an attacker with administrator privilege loads a signed-but-vulnerable third-party driver, then exploits a known vulnerability in the driver to run arbitrary code at kernel mode. Because the driver is signed, the kernel loads it; because the kernel loaded the driver, the driver can disable any defence the kernel enforces, including PPL. Microsoft&apos;s recommended vulnerable-driver block-list shrinks the BYOVD inventory; it does not eliminate the class. Delpy&apos;s own `mimidrv.sys` is the canonical reference exploit driver [@itm4n-runasppl] for this class against `lsass.exe`.
&lt;p&gt;The second is userland: itm4n&apos;s PPLdump (April 2021) [@github-ppldump] exploited a structural weakness in the PPL section-validation logic. A new Windows process loads NTDLL, then asks the image loader to load other DLLs. PPLs are allowed to load DLLs from the &lt;code&gt;\KnownDlls&lt;/code&gt; directory, and -- crucially -- the digital signature of a &lt;code&gt;\KnownDlls&lt;/code&gt; entry is checked when the section is created, not when it is mapped into the address space of a PPL process. PPLdump used &lt;code&gt;DefineDosDevice&lt;/code&gt; to swap the symbolic link of a &lt;code&gt;\KnownDlls&lt;/code&gt; entry, and the PPL &lt;code&gt;lsass.exe&lt;/code&gt; mapped the swapped-in attacker DLL into its own address space, with PPL enforcement intact. The SCRT writeup [@blog-scrt-bypass-lsa] is the canonical 2021 reference. Microsoft closed the userland weakness in build 19044.1826, the July 2022 update [@itm4n-end-of-ppldump], with an &lt;code&gt;LdrpInitializeProcess&lt;/code&gt; patch in NTDLL gated by a &lt;code&gt;Feature_Servicing_2206c_38427506__private_IsEnabled&lt;/code&gt; feature flag. On Windows 8.1 and Server 2012 R2, PPLdump&apos;s behaviour is unstable per the project README [@github-ppldump]: itm4n notes the exploit fails on fully updated machines for an unidentified earlier patch. The userland weakness is therefore closed across the modern estate; legacy boxes that have lapsed on cumulative updates remain the practical exposure.itm4n is explicit about the architectural framing: LSA Protection is &quot;a true quick win [@itm4n-runasppl]&quot; because attackers &quot;will have to use some relatively advanced tricks if they want to work around it, which ultimately increases their chance of being detected.&quot; But in the same post: &quot;[LSA Protection] tends to be confused with [Credential Guard], which is completely different ... Credential Guard and LSA Protection are actually complementary.&quot; That confusion is the most common architectural error in defensive-security reviews of Windows endpoints.&lt;/p&gt;
&lt;h3&gt;Generation 4: KB2871997 + the compensating-control playbook (2014)&lt;/h3&gt;
&lt;p&gt;KB2871997 [@ms-kb2871997] shipped on May 13, 2014 and rolled up three behavioural changes: WDigest cache disabled by default in Windows 8.1 / Server 2012 R2 and later (&lt;code&gt;UseLogonCredential = 0&lt;/code&gt;); the &lt;code&gt;TokenLeakDetectDelaySecs&lt;/code&gt; registry default; and a follow-on October 14, 2014 update that added Restricted Admin mode for Remote Desktop Connection [@ms-kb2871997] on Windows 7 / Server 2008 R2. The same broader 2013--2014 credential-protection initiative also delivered the Protected Users group [@ms-protected-users] (an Active Directory feature shipped in Windows 8.1 [@wiki-win81] / Server 2012 R2 [@wiki-ws2012r2], October 2013). Protected Users is the device-side mitigation: members cannot use credential delegation (CredSSP), Windows Digest, NTLM cached credentials or NTOWFs, DES or RC4 in Kerberos preauthentication, or offline cached verifiers; their TGT lifetime is capped at four hours.&lt;/p&gt;

Protected Users membership requires AES-only Kerberos. Estates with legacy applications that rely on RC4 service tickets (a long tail in any healthcare or industrial deployment) cannot enable Protected Users without a forklift modernisation of their Kerberos client and server inventory. This is the practical reason the Protected Users adoption rate, ten years after the feature shipped, sits well below 100% on enterprise estates that have every other 2014-era mitigation enabled.
&lt;h3&gt;Generation 4.5: Tier 0 isolation, jump-server architecture, AdminSDHolder hygiene&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;Mitigating Pass-the-Hash&lt;/em&gt; v1 (2012) and v2 (2014) playbooks [@ms-lsa-protection] layered organisational changes on top of the per-host technical changes: tier the administrative model so that Tier 0 credentials never log on to Tier 1 or Tier 2 hosts; require every Tier 0 administrative session to traverse a dedicated jump server; clean up AdminSDHolder so that orphaned high-privilege accounts cannot be re-used. The playbooks are still cited in 2026 deployment guides because the underlying recommendations remain correct.&lt;/p&gt;

flowchart TD
    G0[&quot;Gen 0: NT 3.1 lsass.exe (1993)&lt;br /&gt;NTOWF + Kerberos keys in process memory&quot;]
    G1[&quot;Gen 1: WDigest plaintext cache (XP/2003)&lt;br /&gt;Plaintext + key both in lsass.exe&quot;]
    G2[&quot;Gen 2: Vista Protected Process (2007)&lt;br /&gt;For DRM; not applied to lsass.exe&quot;]
    G3[&quot;Gen 3: LSA Protection / RunAsPPL (2013)&lt;br /&gt;NT-kernel-enforced; mimidrv + PPLdump bypassable&quot;]
    G4[&quot;Gen 4: KB2871997 + Protected Users (2014)&lt;br /&gt;WDigest off; AES-only Kerberos; 4hr TGT&quot;]
    G5[&quot;Gen 5: Credential Guard / LsaIso.exe (2015)&lt;br /&gt;Hypervisor-enforced; NT kernel out of TCB&quot;]
    G6[&quot;Gen 6: Default-on (Win 11 22H2 / Server 2025)&lt;br /&gt;No-UEFI-lock&quot;]
    G0 --&amp;gt; G1 --&amp;gt; G2 --&amp;gt; G3 --&amp;gt; G4
    G4 --&amp;gt;|&quot;NT kernel still in TCB&quot;| G5
    G5 --&amp;gt; G6
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; As long as the secret lives in a process whose address space is governed by the same NT kernel that the attacker can compromise, the secret is extractable. Generations 0--4 add layers inside the NT-kernel TCB. The 2014 conclusion -- that you cannot patch your way out of the storage problem -- is structural to that TCB argument; the chain Gen 0 -&amp;gt; Gen 4 above traces it explicitly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each of these layers shrinks the attack surface. None of them changes where the hash physically lives. The 2014 conclusion was unavoidable: the only fix is to move the hash out of the kernel that the attacker can compromise. So Microsoft did.&lt;/p&gt;
&lt;h2&gt;4. Credential Guard lands, then hardens, then defaults on (May 2015 -- November 2024)&lt;/h2&gt;
&lt;p&gt;On May 4, 2015, Brad Anderson stood at Microsoft Ignite [@ms-brad-ignite-2015] and said &lt;em&gt;&quot;more than 75 percent of all these attacks come down to weak credentials or compromised identities.&quot;&lt;/em&gt; Eighty-six days later, Windows 10 Enterprise RTM shipped with &lt;code&gt;LsaIso.exe&lt;/code&gt; running in VTL1.The 75-percent figure is the verbatim Anderson keynote quote and tracks Microsoft&apos;s own internal incident-response telemetry from the 2014--2015 period. The keynote explicitly demonstrates Device Guard at length; the &lt;em&gt;Credential Guard&lt;/em&gt; announcement at the same event is corroborated by ITPro Today&apos;s same-day recap (Wayback snapshot) [@itprotoday-ignite] and Microsoft&apos;s own subsequent blog posts.&lt;/p&gt;
&lt;h3&gt;The eight-event chronology&lt;/h3&gt;
&lt;p&gt;On May 4, 2015, the Anderson Ignite keynote announced Virtualization-Based Security, Device Guard, and Credential Guard alongside the Hello and Microsoft Passport identity story. On July 29, 2015, Windows 10 RTM [@ms-cg-overview] shipped with &lt;code&gt;LsaIso.exe&lt;/code&gt; as Trustlet ID 1 on Enterprise and Education SKUs. On August 5--6, 2015, Alex Ionescu reverse-engineered the trustlet model at Black Hat USA and published the slide deck [@ionescu-bh2015-pdf] that documents the dual-EKU + Signature Level 12 constraint and names &lt;code&gt;LSAISO.EXE&lt;/code&gt; as Trustlet ID 1 verbatim.&lt;/p&gt;
&lt;p&gt;Through 2016--2020, Server 2016 brought Credential Guard to server installs [@ms-ws2016-whatsnew], and the VSM master key + TPM 2.0 binding [@ms-cg-howitworks] hardened the persistent-state path.&lt;/p&gt;
&lt;p&gt;On September 20, 2022, Windows 11 22H2 became generally available with Credential Guard default-on for domain-joined non-DC hardware-eligible boxes [@ms-cg-overview], shipped without UEFI Lock. On December 26, 2022, Oliver Lyak published Pass-the-Challenge [@lyak-passchallenge-wayback]: the trustlet itself was faithful, but its RPC output became the new attack surface. On November 1, 2024, Windows Server 2025 became generally available and extended the default-on stance to server with the same domain-controller carve-out: &quot;Enabling Credential Guard on domain controllers isn&apos;t recommended. Credential Guard doesn&apos;t provide any added security to domain controllers, and can cause application compatibility issues on domain controllers.&quot; [@ms-cg-overview]&lt;/p&gt;

A binary signed at Signature Level 12 with both the Windows System Component Verification EKU (1.3.6.1.4.1.311.10.3.6) and the Isolated User Mode EKU (1.3.6.1.4.1.311.10.3.37), exporting an `s_IumPolicyMetadata` structure from a `.tpolicy` PE section, loaded by the Secure Kernel into VTL1 user mode at boot via `NtCreateUserProcess` with the `PsAttributeSecureProcess` attribute. Documented verbatim in Alex Ionescu&apos;s Black Hat USA 2015 deck [@ionescu-bh2015-pdf], which is still the load-bearing reverse-engineering primary on the trustlet model.

Two privilege levels enforced by the Hyper-V hypervisor on top of the host CPU&apos;s existing ring 0 / ring 3 split. VTL0 is the Normal World: Ring 3 user mode and Ring 0 NT kernel mode. VTL1 is the Secure World: Ring 3 user mode runs trustlets like `LsaIso.exe`, Ring 0 runs the Secure Kernel (`securekernel.exe`). The hypervisor uses Second-Level Address Translation (SLAT) to ensure VTL0 page tables cannot map physical pages that VTL1 has marked private. The Hypervisor TLFS Virtual Secure Mode reference [@ms-tlfs-vsm] defines `#define HV_NUM_VTLS 2` and notes that &quot;Architecturally, up to 16 levels of VTLs are supported; however a hypervisor may choose to implement fewer than 16 VTLs. Currently, only two VTLs are implemented.&quot;

The Ring-3 user mode component of VTL1. IUM hosts trustlets (signed user-mode binaries) that the Secure Kernel loads at boot. IUM processes have no device drivers, no third-party modules, and no normal-world IPC except via the explicitly-marshalled secure-call interface that the Secure Kernel mediates. Quarkslab&apos;s IUM debugging walkthrough [@quarkslab-falcon-ium] names &quot;the isolated version of LSASS (`LSAIso.exe`) when Credential Guard is enabled&quot; as the canonical IUM example.
&lt;p&gt;The four shipping trustlets per Ionescu&apos;s 2015 reverse-engineering [@ionescu-bh2015-pdf]: Trustlet ID 0 is the Secure Kernel Process (Device Guard); Trustlet ID 1 is &lt;code&gt;LSAISO.EXE&lt;/code&gt; (Credential Guard); Trustlet ID 2 is &lt;code&gt;vmsp.exe&lt;/code&gt; (the Hyper-V virtual TPM host side); Trustlet ID 3 is the vTPM provisioning trustlet. Eleven years later, that list is still exactly four, with ID 1 still the most-discussed.&lt;/p&gt;
&lt;p&gt;Every domain-joined Windows 11 box ships with &lt;code&gt;LsaIso.exe&lt;/code&gt; running today. What that small binary actually is, what it computes, and what an attacker who has SYSTEM on the box now sees is the load-bearing technical question of the next section.&lt;/p&gt;
&lt;h2&gt;5. What &lt;code&gt;LsaIso.exe&lt;/code&gt; actually is&lt;/h2&gt;
&lt;p&gt;The trustlet is a small binary that sits inside a separate kernel from the one your shell is running under. Its identity is precise, its API is small, and its memory is unreadable from the side of the boundary you are on. Microsoft&apos;s documentation gives the one-sentence shape:&lt;/p&gt;

With Credential Guard enabled, the LSA process in the operating system talks to a component called the isolated LSA process that stores and protects those secrets, LSAIso.exe. Data stored by the isolated LSA process is protected using VBS and isn&apos;t accessible to the rest of the operating system. -- Microsoft Learn, *How Credential Guard works* [@ms-cg-howitworks]
&lt;p&gt;That sentence hides everything interesting. The next six subsections unfold it.&lt;/p&gt;
&lt;h3&gt;5.1 Identity in the trustlet model&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;LsaIso.exe&lt;/code&gt; passes the five-gate trustlet definition [@ionescu-bh2015-pdf] by construction: Trustlet ID 1; signed at Signature Level 12; carries both the Windows System Component Verification EKU (1.3.6.1.4.1.311.10.3.6) and the Isolated User Mode EKU (1.3.6.1.4.1.311.10.3.37); exports the &lt;code&gt;s_IumPolicyMetadata&lt;/code&gt; structure from a &lt;code&gt;.tpolicy&lt;/code&gt; PE section; and is loaded by SMSS / wininit at boot through &lt;code&gt;NtCreateUserProcess&lt;/code&gt; with the &lt;code&gt;PsAttributeSecureProcess&lt;/code&gt; attribute, which routes through the Secure Kernel [@paragmali-com-the-en] rather than the NT kernel.&lt;/p&gt;

An Extended Key Usage object identifier embedded in an Authenticode signature that constrains what the signed binary is allowed to do. The Windows kernel and Secure Kernel inspect EKUs at load time. The dual-EKU requirement on trustlets means a signature legitimate for ordinary kernel-mode driver loading is *not* sufficient to load a binary as a trustlet; both the WSCV and the IUM EKU must be present, both signed by Microsoft.
&lt;p&gt;The two EKUs together are the identity gate. A binary that has only the WSCV EKU is a normal Microsoft-signed component.The IUM EKU is not a publicly issuable Authenticode EKU; only Microsoft can mint it -- per the Trustlet identity model documented verbatim in Ionescu&apos;s Black Hat USA 2015 deck [@ionescu-bh2015-pdf]. A binary that has only the IUM EKU does not exist in the wild. A binary that has both, and is signed by Microsoft, is admissible as a trustlet. The IUM EKU is not issued by any commercial CA; it is a Microsoft-internal OID with a Microsoft-internal issuance policy.&lt;/p&gt;
&lt;h3&gt;5.2 The agent / trustlet split&lt;/h3&gt;
&lt;p&gt;Credential Guard splits &lt;code&gt;lsass.exe&lt;/code&gt; (the historical agent) into two cooperating processes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lsass.exe&lt;/code&gt; in VTL0&lt;/strong&gt; holds protocol state, network I/O, and every Security Support Provider DLL the system loads: &lt;code&gt;msv1_0.dll&lt;/code&gt; (NTLM), &lt;code&gt;kerberos.dll&lt;/code&gt; (Kerberos), &lt;code&gt;negoexts.dll&lt;/code&gt; (SPNEGO extensions), &lt;code&gt;cloudap.dll&lt;/code&gt; (the Microsoft Entra cloud authentication package), &lt;code&gt;wdigest.dll&lt;/code&gt; (Digest, with caching disabled), &lt;code&gt;tspkg.dll&lt;/code&gt; (Terminal Services / CredSSP), &lt;code&gt;livessp.dll&lt;/code&gt; (Microsoft account / Live), &lt;code&gt;pku2u.dll&lt;/code&gt; (peer-to-peer Kerberos), and &lt;code&gt;schannel.dll&lt;/code&gt; (TLS). The core SSP/AP set (Negotiate, Kerberos, NTLM, Digest, CredSSP, Schannel) is enumerated in Microsoft&apos;s SSP Packages Provided by Microsoft [@ms-ssp-packages] reference; CloudAP, NegoExts, TSPkg, LiveSSP, and PKU2U are documented under the broader LSA Authentication [@ms-lsa-authentication] reference. &lt;code&gt;lsass.exe&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; hold the long-lived NTOWF or Kerberos long-term keys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;LsaIso.exe&lt;/code&gt; in VTL1&lt;/strong&gt; holds NTLM hashes and Kerberos TGTs, plus a small fixed RPC API that lets the agent compute responses against those secrets without ever exposing them.&lt;/li&gt;
&lt;/ul&gt;

flowchart LR
    subgraph VTL0NT[&quot;VTL0 -- NT kernel governs the entire user-mode process space&quot;]
        L[&quot;lsass.exe&lt;br /&gt;NTOWF, Kerberos keys,&lt;br /&gt;SSP DLLs, network I/O&quot;]
        M[&quot;mimikatz&lt;br /&gt;SeDebugPrivilege&quot;]
    end
    M --&amp;gt;|&quot;OpenProcess(VM_READ) + memory dump&quot;| L

flowchart LR
    subgraph V0[&quot;VTL0 (Normal World)&quot;]
        L[&quot;lsass.exe&lt;br /&gt;SSP DLLs, network I/O,&lt;br /&gt;protocol state&lt;br /&gt;(NO long-term key)&quot;]
        M[&quot;mimikatz&lt;br /&gt;SeDebugPrivilege&quot;]
    end
    subgraph V1[&quot;VTL1 (Secure World)&quot;]
        I[&quot;LsaIso.exe&lt;br /&gt;NTOWF + Kerberos keys&quot;]
        SK[&quot;securekernel.exe&lt;br /&gt;(secure kernel)&quot;]
    end
    M --&amp;gt;|&quot;OpenProcess(VM_READ)&quot;| L
    L --&amp;gt;|&quot;LSA_ISO_RPC_SERVER ALPC&lt;br /&gt;NtlmIumCalculateNtResponse(...)&quot;| SK
    SK --&amp;gt;|&quot;validated secure call&quot;| I
    I --&amp;gt;|&quot;derived response&quot;| SK
    SK --&amp;gt;|&quot;return value&quot;| L
&lt;p&gt;The architectural pivot is that the &lt;code&gt;mimikatz&lt;/code&gt;-style memory dump still reaches &lt;code&gt;lsass.exe&lt;/code&gt;, but it no longer reaches the long-term key. The key has moved across a boundary the hypervisor [@paragmali-com-a-security] enforces with hardware page-table-permission bits, and no VTL0 process -- regardless of token, regardless of privilege -- can map the page.&lt;/p&gt;
&lt;h3&gt;5.3 The encrypted-blob format and the IUM API&lt;/h3&gt;
&lt;p&gt;The visible artefact of the move is the &lt;code&gt;[LSA Isolated Data]&lt;/code&gt; block in the Pypykatz dump from §1. The structure of that block is documented byte-by-byte in the PassTheChallenge README [@github-passthechallenge]: an opaque encrypted payload, a &lt;code&gt;Context Handle&lt;/code&gt; (an opaque RPC handle that identifies the per-logon session inside the trustlet), a &lt;code&gt;Proxy Info&lt;/code&gt; field that points to the protocol-side session metadata in &lt;code&gt;lsass.exe&lt;/code&gt;, and a &lt;code&gt;DPAPI&lt;/code&gt; GUID that ties the encrypted blob to the per-user DPAPI master-key chain.&lt;/p&gt;

The Windows API for protecting per-user secrets at rest. The DPAPI master-key chain is keyed off the user&apos;s password (or NTOWF for Pass-the-Hash-resistant variants), and is the canonical persistence layer for credentials and certificates that need to survive process restarts. In the Credential Guard architecture, the per-user DPAPI keys are themselves derived from material the trustlet has access to; the GUID in the `[LSA Isolated Data]` block links the in-memory trustlet record to the on-disk DPAPI chain.
&lt;p&gt;The four IUM-side methods that matter for NTLM authentication, as documented by Lyak&apos;s Pass-the-Challenge writeup [@lyak-passchallenge-wayback]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;EncryptData&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;DecryptData&lt;/code&gt;&lt;/strong&gt;: the trustlet&apos;s general-purpose AES-GCM wrap and unwrap on opaque blobs, used by every other Credential Guard code path that needs to round-trip a secret through &lt;code&gt;lsass.exe&lt;/code&gt; memory without &lt;code&gt;lsass.exe&lt;/code&gt; ever seeing the cleartext.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NtlmIumProtectCredential&lt;/code&gt;&lt;/strong&gt;: the trustlet entry point that converts an NTOWF supplied by &lt;code&gt;lsass.exe&lt;/code&gt; immediately after a logon (when the user typed the password and &lt;code&gt;msv1_0.dll&lt;/code&gt; derived the NTOWF in VTL0 memory) into the isolated form. After this call returns, the only copy of the NTOWF that survives is inside the trustlet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NtlmIumCalculateNtResponse&lt;/code&gt;&lt;/strong&gt;: the trustlet entry point that computes an NTLMv1 response from the protected NTOWF and a server-supplied challenge. This is the function that gets called every time the user authenticates to an SMB share, an MS-SQL server, an Exchange front-end, or any other NTLM endpoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;NtlmIumLm20GetNtlm3ChallengeResponse&lt;/code&gt;&lt;/strong&gt;: the equivalent for NTLMv2.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Pypykatz fork output structure carries the exact byte layout for all of this: &lt;em&gt;Is NT Present&lt;/em&gt;, &lt;em&gt;Context Handle&lt;/em&gt;, &lt;em&gt;Proxy Info&lt;/em&gt;, &lt;em&gt;Encrypted blob&lt;/em&gt;, &lt;em&gt;DPAPI&lt;/em&gt;. The verbatim hex prefix &lt;code&gt;a000000000000000080000006400000001000000010100000100000036&lt;/code&gt; is a length-prefixed serialisation header. The literal string &lt;code&gt;4e746c6d48617368&lt;/code&gt; -- which decodes from hex to the ASCII string &lt;code&gt;NtlmHash&lt;/code&gt; -- is the field-name tag inside the ciphertext. The ciphertext itself is the AES-GCM-wrapped NTOWF; the tag tells you what the cleartext used to be called.The fact that the field-name tag survives the wrap is not a bug. AES-GCM is an authenticated cipher; by construction, its tag is a MAC over the ciphertext, not an obfuscation primitive over the plaintext. The serialiser includes the field name in the structure so that the trustlet can correctly route the request when the agent calls back. The name tag is your verifiable &quot;the encrypted blob really is the hash&quot; artefact.&lt;/p&gt;
&lt;p&gt;{`
// The verbatim hex prefix from the PassTheChallenge README dump example.
// (Full blob is longer; this prefix is the load-bearing identifying header.)
const blobPrefix = &apos;a000000000000000080000006400000001000000010100000100000036&apos;;&lt;/p&gt;
&lt;p&gt;// Inferred field decomposition from the byte pattern of the verbatim
// PassTheChallenge README dump example. The README documents the hex-dump
// shape and the embedded NtlmHash ASCII tag, but does not name the per-byte
// fields; the decomposition below is illustrative.
//   [ProtectionLevel | StructLen | Version | Cipher | TagLen | EncryptedPayload]
// The encrypted payload itself contains an embedded ASCII tag identifying
// the field that was wrapped.&lt;/p&gt;
&lt;p&gt;function parseHeader(hex) {
  const bytes = hex.match(/.{2}/g).map(b =&amp;gt; parseInt(b, 16));
  // Little-endian 64-bit length-like fields; the trustlet uses fixed widths.
  const protectionLevel = bytes[0];                    // 0xa0 in this dump
  const structLen       = bytes.slice(8, 16);          // 8 bytes (LE)
  const version         = bytes[16];                   // 0x01
  const cipher          = bytes[20];                   // 0x01 = AES-GCM
  const tagLen          = bytes[24];                   // 0x01
  return { protectionLevel, structLen, version, cipher, tagLen };
}&lt;/p&gt;
&lt;p&gt;const fields = parseHeader(blobPrefix);
console.log(&apos;ProtectionLevel:&apos;, &apos;0x&apos; + fields.protectionLevel.toString(16));
console.log(&apos;Version       :&apos;, fields.version);
console.log(&apos;Cipher        :&apos;, fields.cipher === 1 ? &apos;AES-GCM (per spec)&apos; : &apos;unknown&apos;);
console.log(&apos;TagLen        :&apos;, fields.tagLen);&lt;/p&gt;
&lt;p&gt;// The literal &apos;4e746c6d48617368&apos; (= ASCII &apos;NtlmHash&apos;) sits inside the ciphertext
// further into the blob. Its presence is the verifiable &apos;this really is the hash&apos;
// signal in the PassTheChallenge dumps.
const ntlmHashTag = Buffer.from(&apos;4e746c6d48617368&apos;, &apos;hex&apos;).toString(&apos;ascii&apos;);
console.log(&apos;Embedded tag  :&apos;, ntlmHashTag);   // -&amp;gt; &apos;NtlmHash&apos;
`}&lt;/p&gt;
&lt;h3&gt;5.4 The &lt;code&gt;LSA_ISO_RPC_SERVER&lt;/code&gt; ALPC port&lt;/h3&gt;
&lt;p&gt;The agent reaches the trustlet through a single secure-call endpoint named &lt;code&gt;LSA_ISO_RPC_SERVER&lt;/code&gt; (terminology per Lyak&apos;s writeup [@lyak-passchallenge-wayback]). The marshalling layer is the IUM Base API. The actual VTL boundary crossing is a hypercall: when a VTL0 thread invokes the secure call, the hypervisor switches the CPU to VTL1, the Secure Kernel inspects the call ordinal, copies the input buffer across the boundary into a VTL1-owned page, and dispatches to the trustlet&apos;s entry point. The reverse path mirrors that step for the return value.&lt;/p&gt;

The undocumented Windows IPC primitive that succeeds the older LPC. ALPC ports support multiple message-passing modes, fast handles, and direct shared-memory regions. In Credential Guard, the agent talks to the trustlet via an ALPC port whose server side is implemented inside the Secure Kernel, so that the IPC delivery path itself crosses the VTL boundary without exposing any VTL1 memory to VTL0. Lyak&apos;s Pass-the-Challenge writeup [@lyak-passchallenge-wayback] names the channel verbatim.
&lt;p&gt;This single endpoint is the entire externally-reachable surface of the trustlet. There is no debugger interface, no driver-load path, no shared-memory region, and no second ALPC port. The trustlet&apos;s code runs only when the agent calls it, and the agent can only call it through one specific channel that the Secure Kernel mediates.&lt;/p&gt;

sequenceDiagram
    participant SRV as Remote SMB server
    participant LSASS as &quot;lsass.exe (VTL0 -- msv1_0.dll)&quot;
    participant SK as &quot;securekernel.exe (VTL1 ring 0)&quot;
    participant ISO as &quot;LsaIso.exe (VTL1 trustlet)&quot;
    SRV-&amp;gt;&amp;gt;LSASS: NTLM challenge (8-byte server challenge)
    LSASS-&amp;gt;&amp;gt;SK: Secure call: NtlmIumCalculateNtResponse(ctxHandle, challenge)
    SK-&amp;gt;&amp;gt;SK: validate ordinal, copy input across VTL boundary
    SK-&amp;gt;&amp;gt;ISO: dispatch (NTOWF retrieved from sealed in-process state)
    ISO-&amp;gt;&amp;gt;ISO: Three-DES against the isolated NTOWF -- NTLMv1 DESL per MS-NLMP 3.3.1
    ISO-&amp;gt;&amp;gt;SK: derived 24-byte NTLMv1 response
    SK-&amp;gt;&amp;gt;LSASS: response (no NTOWF returned)
    LSASS-&amp;gt;&amp;gt;SRV: NTLMv1 response on the wire
&lt;h3&gt;5.5 The &lt;code&gt;MSV1_0\IsolatedCredentialsRootSecret&lt;/code&gt; registry sentinel&lt;/h3&gt;
&lt;p&gt;Microsoft documents one verifiable artefact of default-on Credential Guard activation: the registry value &lt;code&gt;Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\IsolatedCredentialsRootSecret&lt;/code&gt; [@ms-cg-overview]. Its presence on a Windows 11 22H2+ Pro / Pro Education box is the evidence that default-on activated the feature. A Pro Edu deployment that does not show this value either has Credential Guard explicitly disabled by policy, or sits on hardware that does not meet the requirements (no IOMMU, Secure Boot off, no virtualization extensions in firmware).&lt;/p&gt;
&lt;h3&gt;5.6 TPM binding and the VSM master key&lt;/h3&gt;
&lt;p&gt;Persistent state in Credential Guard is rare. The trustlet does not normally persist the NTOWF or TGT material across reboots; the next user logon re-derives both. When persistence is needed, the data is sealed under what Microsoft calls the &lt;em&gt;VSM master key&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;On recent supported hardware with TPM 2.0, VSM data that is persisted will be protected by a key called the &lt;em&gt;VSM master key&lt;/em&gt;, which is protected by device firmware protections. ... The VSM master key is protected by the TPM, ensuring that the key and secrets protected by Credential Guard can only be accessed in a trusted environment.&quot; [@ms-cg-howitworks]&lt;/p&gt;
&lt;/blockquote&gt;

A symmetric key, generated and stored only in VTL1, that wraps any persistent state the trustlets need to survive reboots. The VSM master key is itself sealed by the TPM under PCR-bound policy, so an attacker who pulls the disk and reboots into a different OS cannot unseal the VSM master key without also reproducing the platform&apos;s pristine measured boot state. See the companion TPM in Windows article [@paragmali-tpm] for the full seal / unseal primitive treatment.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Credential Guard removes the NT kernel from the TCB for the long-lived NTOWF and the Kerberos long-term keys, by moving them into a process whose pages no other VTL can map. The trustlet still answers queries about the keys; what changed is who can touch the bytes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Where the hash physically lives, in 2026, is in pages of &lt;code&gt;LsaIso.exe&lt;/code&gt; that the VTL0 NT kernel cannot map. What an attacker on a default-on Credential Guard box actually sees, what the verification surface for defenders is, and what the operational reality looks like in production is the next question.&lt;/p&gt;
&lt;h2&gt;6. The operational reality of default-on Credential Guard&lt;/h2&gt;
&lt;p&gt;Default-on means specifics. Specifically: every domain-joined Windows 11 22H2+ Enterprise / Education box that meets the hardware requirements has Virtualization-Based Security up, has &lt;code&gt;LsaIso.exe&lt;/code&gt; running, has the registry sentinel at &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\IsolatedCredentialsRootSecret&lt;/code&gt; written, and reports &quot;Credential Guard&quot; in the running-services bitmask of &lt;code&gt;Win32_DeviceGuard&lt;/code&gt;. Pro and Pro Education boxes are not default-on targets; the special case where a Pro/Pro Edu device previously ran Credential Guard on Enterprise is the one path that lights it up there, and the registry sentinel from §5.5 is precisely how you detect that carry-over case.&lt;/p&gt;
&lt;h3&gt;Default-on scope and the no-UEFI-lock choice&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s Credential Guard overview page [@ms-cg-overview] is precise about scope: Windows 11 22H2 and later (Enterprise, Education), Windows Server 2025, domain-joined non-DC, hardware-eligible (Hyper-V Generation 2 VM with IOMMU on virtual hardware; UEFI Secure Boot, virtualization extensions, IOMMU, and TPM 2.0 on physical hardware). Pro and Pro Education hold the licence entitlement only via the Enterprise-to-Pro carry-over case. The default-on policy ships &quot;without UEFI Lock&quot; [@ms-cg-overview], which is a deliberate trade-off.&quot;Without UEFI Lock&quot; means an administrator can disable Credential Guard remotely (via Group Policy, Intune, or a registry change) without first sending someone to the box&apos;s UEFI menu. The trade-off: an attacker who has already obtained the level of privilege required to write the registry can also undo the same setting. Microsoft chose remote-disable convenience over the in-principle attacker-disable hardening because compatibility incidents -- a rolled-out third-party SSP that breaks under CG -- are an operational reality, and not being able to disable the feature remotely turns an SSP regression into a desk-side support ticket. The overview page [@ms-cg-overview] documents the rationale verbatim.&lt;/p&gt;
&lt;h3&gt;The three supported verification surfaces&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s configuration guide [@ms-cg-configure] names three supported ways to verify Credential Guard is running, and explicitly disrecommends a fourth:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;msinfo32&lt;/code&gt;&lt;/strong&gt;: opens the System Information UI; the line &quot;Virtualization-based Security Services Running&quot; includes &quot;Credential Guard&quot; when the trustlet is up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PowerShell &lt;code&gt;Get-CimInstance Win32_DeviceGuard&lt;/code&gt;&lt;/strong&gt;: returns a &lt;code&gt;SecurityServicesRunning&lt;/code&gt; array whose values are a bitmask.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WinInit Event ID 13&lt;/strong&gt; in the System log: &quot;Credential Guard (LsaIso.exe) was started and will protect LSA credentials.&quot; [@ms-cg-configure]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The disrecommended approach is &quot;look for &lt;code&gt;LsaIso.exe&lt;/code&gt; in Task Manager.&quot; Microsoft&apos;s words: &quot;Checking Task Manager if LsaIso.exe is running isn&apos;t a recommended method for determining whether Credential Guard is running.&quot; [@ms-cg-configure] Task Manager runs in VTL0 and queries an enumeration that an attacker who controls VTL0 can hide; the three supported surfaces all consult the hypervisor or the boot-time event log, neither of which a VTL0 attacker can edit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use the supported surfaces, not Task Manager. The PowerShell one-liner is &lt;code&gt;(Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard).SecurityServicesRunning&lt;/code&gt;. The returned array contains &lt;code&gt;1&lt;/code&gt; when Credential Guard is running; &lt;code&gt;2&lt;/code&gt; denotes Hypervisor-Enforced Code Integrity (HVCI) per the broader &lt;code&gt;Win32_DeviceGuard&lt;/code&gt; schema [@learn-microsoft-com-code-integrity]. The corresponding WinInit Event IDs are 13 (Credential Guard started), 14 (configuration loaded), 15 (warning -- secure kernel not running), 16 (failed to launch), and 17 (UEFI configuration error), per the configuration guide [@ms-cg-configure].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// Mirrors what (Get-CimInstance Win32_DeviceGuard).SecurityServicesRunning returns.
// Microsoft&apos;s Win32_DeviceGuard documentation enumerates the values:
//   1 = Credential Guard
//   2 = Hypervisor-enforced Code Integrity (HVCI / Memory Integrity)
//   3 = System Guard Secure Launch
//   4 = SMM Firmware Measurement
//   5 = Kernel-mode Hardware-enforced Stack Protection
//   6 = Kernel-mode Hardware-enforced Stack Protection (Audit mode)
//   7 = Hypervisor-Enforced Paging Translation
// Note: MBEC (Mode-Based Execution Control) is a CPU capability advertised
// in the SEPARATE AvailableSecurityProperties array, not here.
const SECURITY_SERVICES = {
  1: &apos;Credential Guard&apos;,
  2: &apos;Hypervisor-enforced Code Integrity (HVCI)&apos;,
  3: &apos;System Guard Secure Launch&apos;,
  4: &apos;SMM Firmware Measurement&apos;,
  5: &apos;Kernel-mode Hardware-enforced Stack Protection&apos;,
  6: &apos;Kernel-mode Hardware-enforced Stack Protection (Audit mode)&apos;,
  7: &apos;Hypervisor-Enforced Paging Translation&apos;
};&lt;/p&gt;
&lt;p&gt;function describe(running) {
  if (!running.length) return &apos;No VBS services running&apos;;
  return running.map(v =&amp;gt; SECURITY_SERVICES[v] || (&apos;Unknown service id &apos; + v)).join(&apos;, &apos;);
}&lt;/p&gt;
&lt;p&gt;// On a default-on Windows 11 22H2+ domain-joined Pro/Enterprise box this returns:
console.log(describe([1, 2]));
// =&amp;gt; &quot;Credential Guard, Hypervisor-enforced Code Integrity (HVCI)&quot;&lt;/p&gt;
&lt;p&gt;// On a Windows 10 box without VBS enabled:
console.log(describe([]));
// =&amp;gt; &quot;No VBS services running&quot;
`}&lt;/p&gt;
&lt;h3&gt;What changes for the protocols&lt;/h3&gt;
&lt;p&gt;When Credential Guard is enabled, four SSPs lose the ability to use signed-in credentials: &quot;NTLMv1, MS-CHAPv2, Digest, and CredSSP can&apos;t use the signed-in credentials&quot; [@ms-cg-howitworks]. For NTLMv1 and Digest the practical effect is small (NTLMv1 is end-of-life [@paragmali-ntlmless]; Digest is essentially unused outside legacy HTTP digest authentication). For MS-CHAPv2 and CredSSP the effect is real: any single-sign-on path that depended on those protocols breaks with Credential Guard on. The considerations page [@ms-cg-considerations] calls out PEAP-MSCHAPv2 / EAP-MSCHAPv2 WiFi and VPN configurations explicitly: &quot;If you&apos;re using WiFi and VPN endpoints that are based on MS-CHAPv2, they&apos;re subject to similar attacks as for NTLMv1.&quot; [@ms-cg-considerations] The recommended remediation is to migrate the endpoints to PEAP-TLS / EAP-TLS (certificate-based authentication).&lt;/p&gt;
&lt;p&gt;For Kerberos, Credential Guard &quot;doesn&apos;t allow unconstrained Kerberos delegation or DES encryption, not only for signed-in credentials, but also prompted or saved credentials&quot; [@ms-cg-howitworks]. Constrained Delegation and Resource-Based Constrained Delegation continue to work. The remaining Kerberos &lt;code&gt;etype&lt;/code&gt; choices on the wire on a Credential Guard box are AES-128 and AES-256.&lt;/p&gt;
&lt;h3&gt;What doesn&apos;t change&lt;/h3&gt;
&lt;p&gt;The agent surface still exposes every SSP that loads inside &lt;code&gt;lsass.exe&lt;/code&gt;. The trustlet isolates the secret the SSP uses; it does not isolate the &lt;em&gt;parser&lt;/em&gt; that the SSP runs against an attacker-controlled wire format. A bug in &lt;code&gt;msv1_0.dll&lt;/code&gt;&apos;s NTLM parser is exactly as exploitable on a 2026 Credential-Guard-on box as it was on a 2015 Credential-Guard-off box. The trustlet does not guard the agent; the trustlet guards the key.&lt;/p&gt;

A VBS-based feature that uses the hypervisor&apos;s SLAT enforcement to ensure that any kernel-mode page that is executable is also signed and immutable, and any writable kernel-mode page is non-executable. HVCI closes the kernel-driver-loader leg of the BYOVD / PPL bypass class for *unsigned* drivers, but it does not close BYOVD against a signed-but-vulnerable driver. HVCI is orthogonal to Credential Guard; the overview page [@ms-cg-overview] recommends running both.
&lt;p&gt;Credential Guard is on; the surface is documented; the verification is one PowerShell line. So what other things claim to &quot;protect LSASS,&quot; and how do they fit together with Credential Guard?&lt;/p&gt;
&lt;h2&gt;7. The other things that &quot;protect LSASS&quot;&lt;/h2&gt;
&lt;p&gt;Six other things in the Microsoft security stack get called &quot;LSASS protection&quot; in someone&apos;s marketing. None of them is a substitute for Credential Guard. Most of them are complements. The difference matters because the choice between them is not a choice; the answer is &lt;em&gt;all of them, layered&lt;/em&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Enforcement TCB&lt;/th&gt;
&lt;th&gt;Attacker bar to defeat&lt;/th&gt;
&lt;th&gt;Residual class it leaves open&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;LSA Protection (&lt;code&gt;RunAsPPL&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;NT kernel (signer-level lattice)&lt;/td&gt;
&lt;td&gt;Signed kernel driver (BYOVD via &lt;code&gt;mimidrv.sys&lt;/code&gt; [@itm4n-runasppl]); userland on legacy via PPLdump [@github-ppldump]&lt;/td&gt;
&lt;td&gt;Trustlet RPC outputs; non-LSA process credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credential Guard / &lt;code&gt;LsaIso.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hypervisor + Secure Kernel + VTL1 trustlet&lt;/td&gt;
&lt;td&gt;Hypervisor escape; VTL1 code-execution bug&lt;/td&gt;
&lt;td&gt;Pass-the-Challenge [@lyak-passchallenge-wayback]; credential &lt;em&gt;use&lt;/em&gt;; tokens; supplied creds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HVCI / Memory Integrity&lt;/td&gt;
&lt;td&gt;Hypervisor-enforced kernel page W^X&lt;/td&gt;
&lt;td&gt;Signed-and-vulnerable driver that does not load arbitrary unsigned code&lt;/td&gt;
&lt;td&gt;Kernel-mode logic bugs in signed drivers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Defender for Identity LSASS read-monitoring [@ms-defender-identity]&lt;/td&gt;
&lt;td&gt;Behavioural detection (no TCB)&lt;/td&gt;
&lt;td&gt;Stealth tradecraft that does not trip the canonical signatures&lt;/td&gt;
&lt;td&gt;Anything not yet patterned&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hello for Business&lt;/td&gt;
&lt;td&gt;Per-device TPM-bound asymmetric key (no shared secret on the wire)&lt;/td&gt;
&lt;td&gt;TPM compromise; on-device keylogger before sign-in&lt;/td&gt;
&lt;td&gt;Not a substitute -- it is what CG protects on cloud-joined boxes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restricted Admin / Protected Users&lt;/td&gt;
&lt;td&gt;Protocol-level credential-delegation suppression&lt;/td&gt;
&lt;td&gt;Per-protocol; does not move where the secret lives&lt;/td&gt;
&lt;td&gt;Everything Credential Guard already covers, plus the four-hour TGT cap&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;LSA Protection&apos;s kernel-driver-loader bypass class is closed by HVCI for unsigned drivers but not for signed-and-vulnerable ones. Defender for Identity is a detection layer, not a TCB boundary. Hello for Business [@paragmali-com-hellos-hardwar] replaces the password with a TPM-bound asymmetric key [@ms-hello-business]: the Hello for Business overview [@ms-hello-business] row in the Security comparison table reads &quot;It uses &lt;strong&gt;key-based&lt;/strong&gt; or &lt;strong&gt;certificate-based&lt;/strong&gt; authentication. There&apos;s no symmetric secret (password) which can be stolen from a server or phished from a user and used remotely.&quot; The Microsoft Entra ID Primary Refresh Token (PRT) inside &lt;code&gt;cloudap.dll&lt;/code&gt; is the cloud-joined analogue of the on-prem trustlet model: the PRT itself is protected by the trustlet on Credential-Guard-enabled boxes, with Hello as the per-device long-term key chain. Restricted Admin and Protected Users [@ms-protected-users] suppress credential delegation at the protocol layer; on a Credential-Guard-on box they are &lt;em&gt;additionally&lt;/em&gt; effective because they remove the prompt path, but they are not a substitute for the storage-isolation primitive.&lt;/p&gt;

The structural model differs in interesting ways across general-purpose desktop operating systems. macOS uses the Apple Secure Enclave [@apple-secure-enclave]: a separate coprocessor &quot;isolated from the main processor&quot; running an Apple-customised L4 microkernel, with its own attestation chain and a constrained API surface that does not require a &quot;secure call&quot; from the application processor to be tunnelled through a trusted broker. Linux relies on the in-process Kerberos credential cache and per-user keyrings (KCM [@sssd-kcm], GNOME Keyring, KWallet); none of these provide kernel-bypass isolation by default, and the equivalent of &quot;dump LSASS&quot; is &quot;dump the user&apos;s keyring file plus the per-user master key from `~/.local/share/`.&quot; ChromeOS uses cryptohome [@chromium-cryptohome] plus per-user U2F keys, structurally close to the Hello-for-Business model. Windows is the only general-purpose desktop OS that combines a TPM-bound long-term key (Hello), a hypervisor-isolated derived-secret store (Credential Guard / LsaIso), and a behavioural detection layer (Defender for Identity). It is also the only one that accumulated the largest deployed base of password-equivalent secrets in process memory before it found the architectural answer.
&lt;p&gt;Credential Guard closes the storage class. Layering closes the adjacent classes. But there are five classes the layers cannot close -- five things Credential Guard was never going to close, by documented design. The next section enumerates each one.&lt;/p&gt;
&lt;h2&gt;8. The five things Credential Guard was never going to close&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s own &lt;em&gt;How Credential Guard works&lt;/em&gt; [@ms-cg-howitworks] page lists what Credential Guard &lt;em&gt;does not&lt;/em&gt; protect, in plain English. The list has five classes. Each class has a publicly disclosed worked example. Each worked example is in 2026 production attacker tradecraft. This is the honest accounting.&lt;/p&gt;
&lt;h3&gt;8.1 Pass-the-Challenge: the trustlet&apos;s RPC output as the new attack surface&lt;/h3&gt;
&lt;p&gt;On December 26, 2022, Oliver Lyak published Pass-the-Challenge [@lyak-passchallenge-wayback]. The technique is exactly the lesson of §5: the trustlet&apos;s pages are unreadable, but the trustlet&apos;s RPC output is exactly the response the attacker wants, and the attacker can ask for it.&lt;/p&gt;
&lt;p&gt;The attack flow, end to end:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The attacker has SYSTEM and &lt;code&gt;SeDebugPrivilege&lt;/code&gt; on a Credential-Guard-on box (any of the bypass paths from §3 still apply for getting to that point; Credential Guard does not change them).&lt;/li&gt;
&lt;li&gt;The attacker injects a security-package DLL named &lt;code&gt;SecurityPackage.dll&lt;/code&gt; (per the PassTheChallenge tool&apos;s source [@github-passthechallenge]) into &lt;code&gt;lsass.exe&lt;/code&gt;. Inside &lt;code&gt;lsass.exe&lt;/code&gt;, that DLL inherits the established ALPC channel to the trustlet, because it is now part of the agent.&lt;/li&gt;
&lt;li&gt;The attacker uses the Pypykatz fork [@github-pypykatz-ly4k] to extract the per-logon &lt;code&gt;Context Handle&lt;/code&gt; and &lt;code&gt;Proxy Info&lt;/code&gt; from the &lt;code&gt;[LSA Isolated Data]&lt;/code&gt; block of an existing user session.&lt;/li&gt;
&lt;li&gt;The attacker calls the trustlet&apos;s &lt;code&gt;NtlmIumCalculateNtResponse&lt;/code&gt; method through the established ALPC channel, supplying the &lt;code&gt;Context Handle&lt;/code&gt; and &quot;the static challenge &lt;code&gt;1122334455667788&lt;/code&gt;&quot; [@github-passthechallenge], the value historically used in pre-computed NTLMv1 rainbow tables and accepted by the &lt;code&gt;crack.sh&lt;/code&gt; [@lyak-passchallenge-wayback] cracking service.&lt;/li&gt;
&lt;li&gt;The trustlet faithfully returns the NTLMv1 response. No memory of the trustlet is read. No bug in the trustlet is exploited. The trustlet does what it was built to do.&lt;/li&gt;
&lt;li&gt;The attacker submits the response to &lt;code&gt;crack.sh&lt;/code&gt;. &quot;In less than a minute, I received an email from crack.sh stating that the NTLM hash was successfully recovered in 30 seconds: &lt;code&gt;65A13AB2FAEB5B700DE1A938AE5621CA&lt;/code&gt;.&quot; [@lyak-passchallenge-wayback]&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There is also a v2 variant. Lyak: &quot;Another interesting option is to compute an NTLMv2 response using the LSAIso method &lt;code&gt;NtlmIumLm20GetNtlm3ChallengeResponse&lt;/code&gt;.&quot; [@lyak-passchallenge-wayback] The v2 variant uses an Impacket modification plus an AD CS [@lyak-passchallenge-wayback] Web Enrollment relay to obtain a certificate for the target user (Certipy&apos;s &lt;code&gt;Administrator&lt;/code&gt; certificate-based authentication path) without needing the cleartext NT hash at all.&lt;/p&gt;

sequenceDiagram
    participant ATT as Attacker (SYSTEM)
    participant LSASS as &quot;lsass.exe (VTL0) -- SecurityPackage.dll injected&quot;
    participant SK as &quot;securekernel.exe (VTL1 ring 0)&quot;
    participant ISO as &quot;LsaIso.exe (VTL1 trustlet)&quot;
    participant CRACK as crack.sh
    ATT-&amp;gt;&amp;gt;LSASS: Inject SecurityPackage.dll
    ATT-&amp;gt;&amp;gt;LSASS: Extract Context Handle from Pypykatz dump
    LSASS-&amp;gt;&amp;gt;SK: NtlmIumCalculateNtResponse(ctxHandle, 1122334455667788)
    SK-&amp;gt;&amp;gt;ISO: dispatch (signed-and-attested call)
    ISO-&amp;gt;&amp;gt;SK: 24-byte NTLMv1 response
    SK-&amp;gt;&amp;gt;LSASS: response
    LSASS-&amp;gt;&amp;gt;ATT: response (no NTOWF, just the ciphertext)
    ATT-&amp;gt;&amp;gt;CRACK: submit NTLMv1 ciphertext for 1122334455667788
    CRACK-&amp;gt;&amp;gt;ATT: NT hash recovered in ~30 seconds
&lt;p&gt;Microsoft&apos;s response landed in two phases. First, NTLMv1 was deprecated and disabled by default in Windows 11 24H2 / Server 2025 [@paragmali-ntlmless], which removes the &lt;code&gt;crack.sh&lt;/code&gt; rainbow-table leg specifically. Second, the trustlet stopped accepting NTLMv1 calls on the same builds. The &lt;em&gt;class&lt;/em&gt; -- &quot;use the trustlet to mint derived material&quot; -- remains structural to the agent / trustlet split, because closing it requires removing either the agent&apos;s ability to call the trustlet (which would defeat single-sign-on) or the attacker&apos;s ability to compromise the agent (which is the point of every other layer in the stack).&lt;/p&gt;

Pass-the-Challenge is not a Microsoft bug. It is a class property of any agent / trustlet split where the agent owns the protocol code. If `lsass.exe` could not call the trustlet, the trustlet would be useless: there would be no path from the wire challenge to a response. If `lsass.exe` *can* call the trustlet, then an attacker who compromises `lsass.exe` can call it too. Closing this gap structurally requires rewriting the SSP loading model so that protocol code, too, runs inside the trustlet -- which would put parsers for arbitrary attacker-controlled wire formats inside VTL1 and dramatically expand the trustlet TCB. Microsoft has not announced an intent to do that. The honest read of the architecture is that the storage surface is closed and the use surface is structurally open.
&lt;h3&gt;8.2 Credential &lt;em&gt;use&lt;/em&gt; without theft&lt;/h3&gt;
&lt;p&gt;Three named techniques in 2026 production tradecraft do not require reading the memory of any Credential-Guard-protected machine. They request derived material from the network and do offline cryptography on the response.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kerberoasting.&lt;/strong&gt; Tim Medin disclosed Kerberoasting at DerbyCon 4 in September 2014 [@irongeek-derbycon-medin] under the talk title &lt;em&gt;Attacking Microsoft Kerberos: Kicking the Guard Dog of Hades&lt;/em&gt;. The mechanism, per the MITRE ATT&amp;amp;CK technique page [@attack-kerberoast]: any authenticated domain user requests a TGS-REP ticket for any registered Service Principal Name. &quot;Portions of these tickets may be encrypted with the RC4 algorithm, meaning the Kerberos 5 TGS-REP etype 23 hash of the service account associated with the SPN is used as the private key and is thus vulnerable to offline Brute Force attacks that may expose plaintext credentials.&quot; [@attack-kerberoast] The ticket arrives on the attacker&apos;s machine; the cracking happens on the attacker&apos;s GPUs; no memory of any Credential-Guard-protected box is ever read.&lt;/p&gt;

The class of attack in which any authenticated domain user requests a Kerberos TGS-REP ticket for any registered Service Principal Name and submits the encrypted portion of the response to offline cracking, recovering the service-account password if it is weak. Documented as MITRE ATT&amp;amp;CK T1558.003 [@attack-kerberoast]. Kerberoasting reads no memory of the targeted host; it consumes only network responses to entirely-legitimate Kerberos requests.
&lt;p&gt;&lt;strong&gt;AS-REP Roasting.&lt;/strong&gt; The same class for accounts with &lt;code&gt;DONT_REQ_PREAUTH&lt;/code&gt; set [@attack-asreproast]: the attacker requests a Kerberos AS-REP without sending preauthentication, the KDC returns a ticket portion encrypted with the user&apos;s long-term key, and the attacker cracks offline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resource-Based Constrained Delegation (RBCD).&lt;/strong&gt; Originally described by Elad Shamir in &lt;em&gt;Wagging the Dog&lt;/em&gt; (January 2019) [@shenanigans-wagging-dog]; refined by James Forshaw&apos;s &quot;Exploiting RBCD using a normal user&quot; (May 2022) [@tiraniddo-rbcd]; turned into a turnkey LPE by Dec0ne&apos;s KrbRelayUp (2022) [@github-krbrelayup], which the README describes -- accurately -- as &quot;essentially a universal no-fix local privilege escalation in windows domain environments where LDAP signing is not enforced (the default settings).&quot; [@github-krbrelayup] The attack abuses the &lt;code&gt;msDS-AllowedToActOnBehalfOfOtherIdentity&lt;/code&gt; LDAP attribute: if the attacker can write that attribute on a target computer object, they can mint a Kerberos service ticket &lt;em&gt;as anyone&lt;/em&gt; against the target. Forshaw&apos;s 2022 contribution removed the precondition that the attacker must control a computer account (it used to require a &lt;code&gt;MachineAccountQuota&lt;/code&gt;-bypass); after Forshaw, &lt;em&gt;any&lt;/em&gt; authenticated domain user with write access to the attribute is enough.&lt;/p&gt;

A Kerberos delegation feature in which the resource (server) lists which principals are allowed to delegate to it via the `msDS-AllowedToActOnBehalfOfOtherIdentity` LDAP attribute on the resource&apos;s computer object. RBCD enables S4U2Self and S4U2Proxy chains where the configured principal can request a service ticket *as any user* against the resource, including Domain Administrators. Abuse documented in Wagging the Dog [@shenanigans-wagging-dog], refined in tiraniddo.dev [@tiraniddo-rbcd], and weaponised in KrbRelayUp [@github-krbrelayup].
&lt;h3&gt;8.3 The SeImpersonatePrivilege Potato chain&lt;/h3&gt;
&lt;p&gt;The Potato family [@paragmali-com-on-the] is a chain of escalations from a low-privilege service user (anyone with &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt;) to NT AUTHORITY\SYSTEM. The chain starts with Hot Potato (Stephen Breen, January 16, 2016) [@foxglove-hot-potato]: NBNS spoofing plus WPAD plus HTTP-to-SMB NTLM relay. The &lt;code&gt;breenmachine&lt;/code&gt; writeup [@foxglove-hot-potato] is verbatim: &quot;Hot Potato (aka: Potato) takes advantage of known issues in Windows to gain local privilege escalation in default configurations, namely NTLM relay (specifically HTTP-&amp;gt;SMB relay) and NBNS spoofing.&quot; [@foxglove-hot-potato]&lt;/p&gt;
&lt;p&gt;Rotten Potato (Breen + Chris Mallz, September 26, 2016) [@foxglove-rotten-potato] replaced the NBNS / WPAD / WSUS triggering with a synthesised DCOM round-trip via &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; against the BITS CLSID &lt;code&gt;4991d34b-80a1-4291-83b6-3328366b9097&lt;/code&gt; over a local TCP port, achieving 100% reliability across Windows versions. Juicy Potato (Andrea Pierini &lt;code&gt;@ohpe&lt;/code&gt; + Claudio Tenaglia &lt;code&gt;@decoder_it&lt;/code&gt;, August 2018) [@github-juicy-potato] made the CLSID a parameter, dropping the BITS-on-port-6666 hardcoding. PrintSpoofer (itm4n, May 2, 2020) [@itm4n-printspoofer] replaced the DCOM coercion with a Print Spooler named-pipe coercion, surviving Microsoft&apos;s Server 2019 / Windows 10 19H1 mitigations against the DCOM-based predecessors.&lt;/p&gt;

The Windows token privilege that allows a process to call `ImpersonateLoggedOnUser` against a token obtained from another security context. Service accounts (`NT AUTHORITY\NETWORK SERVICE`, IIS app pool identities, MSSQL service accounts) hold this privilege by default. As `decoder_it` first observed [@itm4n-printspoofer], if you have `SeAssignPrimaryToken` or `SeImpersonate` privilege, you are SYSTEM: combine it with a coerced inbound NTLM authentication from `NT AUTHORITY\SYSTEM` to a local listener, and `CreateProcessWithToken` finishes the chain.
&lt;p&gt;The Potato chain exploits &lt;em&gt;tokens&lt;/em&gt;, not credentials. The chain of Hot / Rotten / Juicy / PrintSpoofer / RoguePotato / GodPotato has been continuous since January 2016 because every link in the chain abuses a Windows OS feature (DCOM marshalling, RPC, named-pipe impersonation, Print Spooler, COM activation through alternative interfaces) that has a legitimate use case Microsoft cannot remove. Credential Guard does not protect tokens; Credential Guard protects credentials.&lt;/p&gt;
&lt;h3&gt;8.4 Plaintext-secret protocols and supplied credentials&lt;/h3&gt;
&lt;p&gt;&quot;When Credential Guard is enabled, NTLMv1, MS-CHAPv2, Digest, and CredSSP can&apos;t use the signed-in credentials&quot; [@ms-cg-howitworks], but they &lt;em&gt;can&lt;/em&gt; still be used with prompted or saved credentials. In every such case the cleartext password (or a symmetric secret derived from it) is supplied to &lt;code&gt;lsass.exe&lt;/code&gt; from outside the trustlet, so the trustlet has nothing to protect at the moment of use.&lt;/p&gt;
&lt;p&gt;The considerations page [@ms-cg-considerations] names PEAP-MSCHAPv2 / EAP-MSCHAPv2 WiFi and VPN configurations as the most consequential remaining surface in 2026: a corporate WiFi or VPN endpoint that authenticates users with MS-CHAPv2 still cracks under the same offline tradecraft as the original NTLMv1 attacks, because the protocol itself uses MD4 + DES against the user&apos;s NT hash. The recommendation: &quot;organizations move away from passwords to other authentication methods, such as Windows Hello for Business, FIDO 2 security keys, or smart cards&quot; [@ms-cg-considerations], or migrate the WiFi / VPN endpoint to certificate-based PEAP-TLS / EAP-TLS.&lt;/p&gt;
&lt;h3&gt;8.5 Out-of-LSA credential storage&lt;/h3&gt;
&lt;p&gt;Four storage locations are out of scope for Credential Guard by Microsoft&apos;s own design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Generic Credential Manager entries&lt;/strong&gt; -- web passwords, browser-stored credentials, the Windows Credential Manager&apos;s &quot;Web Credentials&quot; tab. &quot;Generic credentials, such as user names and passwords that you use to sign in websites, aren&apos;t protected since the applications require your clear-text password.&quot; [@ms-cg-considerations]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-Microsoft Security Support Providers.&lt;/strong&gt; &quot;Some non-Microsoft Security Support Providers (SSPs and APs) might not be compatible with Credential Guard because it doesn&apos;t allow non-Microsoft SSPs to ask for password hashes from LSA. ... For example, using the KerbQuerySupplementalCredentialsMessage API isn&apos;t supported.&quot; [@ms-cg-considerations] Third-party SSPs that depend on hash retrieval through that API simply break under Credential Guard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Active Directory database on domain controllers.&lt;/strong&gt; &quot;Credential Guard doesn&apos;t protect the Active Directory database running on Windows Server domain controllers.&quot; [@ms-cg-howitworks] The most-attacked LSASS on the network -- &lt;code&gt;lsass.exe&lt;/code&gt; on the domain controller, holding &lt;code&gt;NTDS.dit&lt;/code&gt; and the &lt;code&gt;krbtgt&lt;/code&gt; long-term key -- is explicitly out of Credential Guard&apos;s scope. Microsoft&apos;s stated rationale is that domain controllers do not benefit from the same isolation, because the entire AD database is, by design, available to the LSA process on a DC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Credential-input pipelines such as Remote Desktop Gateway and Just-In-Time admin access tooling&lt;/strong&gt;, where the typed cleartext is supplied to &lt;code&gt;lsass.exe&lt;/code&gt; over an inbound network protocol and is in clear at the moment of arrival.&lt;/li&gt;
&lt;/ul&gt;

Doesn&apos;t prevent an attacker with malware on the PC from using the privileges associated with any credential. We recommend using dedicated PCs for high value accounts. -- Microsoft Learn, *How Credential Guard works* [@ms-cg-howitworks]

flowchart LR
    CG[&quot;What CG closes:&lt;br /&gt;Long-term key in lsass.exe memory&quot;]
    R1[&quot;Pass-the-Challenge:&lt;br /&gt;trustlet RPC output&lt;br /&gt;(Lyak, Dec 2022)&quot;]
    R2[&quot;Credential use without theft:&lt;br /&gt;Kerberoast, AS-REP Roast,&lt;br /&gt;RBCD / KrbRelayUp&quot;]
    R3[&quot;Token impersonation:&lt;br /&gt;Hot/Rotten/Juicy/PrintSpoofer&lt;br /&gt;SeImpersonatePrivilege&quot;]
    R4[&quot;Plaintext protocols:&lt;br /&gt;NTLMv1, MS-CHAPv2, Digest,&lt;br /&gt;CredSSP&quot;]
    R5[&quot;Out-of-LSA storage:&lt;br /&gt;Web creds, non-MS SSPs,&lt;br /&gt;NTDS.dit on DCs&quot;]
    CG -.does not close.-&amp;gt; R1
    CG -.does not close.-&amp;gt; R2
    CG -.does not close.-&amp;gt; R3
    CG -.does not close.-&amp;gt; R4
    CG -.does not close.-&amp;gt; R5
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The trustlet is the storage layer; the agent is the use layer; an attacker who controls the agent can request derived material the trustlet was never going to refuse. This is the structural reason Credential Guard was never going to close the use surface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Five classes documented; five worked examples named. What is &lt;em&gt;not yet&lt;/em&gt; documented -- the open problems where the research is still in progress -- is what the next section walks.&lt;/p&gt;
&lt;h2&gt;9. Open problems&lt;/h2&gt;
&lt;p&gt;Five things the Credential Guard architecture has not yet closed. One of them is structural; four are deployment frontiers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.1 Trustlet IUM API surface fuzzing.&lt;/strong&gt; Pass-the-Challenge proved one corner of the agent-callable RPC surface is exploitable when fed inputs the developer did not anticipate (the static &lt;code&gt;1122334455667788&lt;/code&gt; challenge whose responses are pre-computed in commercial cracking tables). The systematic audit of every IUM API entry point -- there are not many; the trustlet is small -- has not been published. A blue-team-friendly fuzzer that exercises the channel from a controlled VTL0 agent against a controlled VTL1 target is on the public to-do list of several research groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.2 Domain-controller LSASS / &lt;code&gt;NTDS.dit&lt;/code&gt; / &lt;code&gt;krbtgt&lt;/code&gt; protection.&lt;/strong&gt; Microsoft documents the DC carve-out as out of scope [@ms-cg-howitworks]. An architectural fix would require a DC-resident trustlet model that can answer Kerberos AS-REP and TGS-REP queries against the entire &lt;code&gt;NTDS.dit&lt;/code&gt; without compromising AD replication semantics. That model is not on the public roadmap, and the practical recommendation -- the dedicated-Tier-0-PAW model from the &lt;em&gt;Mitigating Pass-the-Hash&lt;/em&gt; v2 playbook [@ms-lsa-protection] -- still applies in 2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.3 TGT and service-ticket lifetime in &lt;code&gt;lsass.exe&lt;/code&gt; after the trustlet mints them.&lt;/strong&gt; Pass-the-Ticket on the agent recovers the &lt;em&gt;current&lt;/em&gt; TGT or service ticket from &lt;code&gt;lsass.exe&lt;/code&gt; memory. Credential Guard isolates the long-term key; it does not isolate the per-session derived material that the agent has to hold to send on the wire. The trustlet&apos;s TGT protection [@ms-cg-howitworks] is verbatim: the long-term-key path is closed, the service-ticket path is not. A 2026 attacker with &lt;code&gt;SeDebugPrivilege&lt;/code&gt; who dumps &lt;code&gt;lsass.exe&lt;/code&gt; recovers the &lt;em&gt;Kerberos service tickets&lt;/em&gt; even though they cannot recover the underlying NTOWF.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.4 Pass-the-Cookie / token-lift class against derived material.&lt;/strong&gt; Microsoft Entra Primary Refresh Token (PRT) [@ms-entra-prt] cookies issued by the trustlet to the agent become bearer tokens until the session ends. Per-token device binding raises the bar (the cookie is bound to a TPM-bound device key, so use of the cookie outside the device is detectable by the cloud), but it does not close the class for an attacker who has on-device persistence and can replay the cookie from the same device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.5 Compatibility and observability frontier.&lt;/strong&gt; The third-party SSP / MS-CHAPv2 / CredSSP behaviour-change surface keeps showing up in real-estate compatibility reports. Microsoft&apos;s &lt;em&gt;Considerations&lt;/em&gt; page [@ms-cg-considerations] is updated routinely; the practical operational pattern in 2026 is &quot;enable Credential Guard via Intune in audit mode for 30 days, harvest the compatibility errors, fix or replace the affected SSPs, then promote to enforce.&quot; That pattern is now well-trodden but the per-estate inventory is real work.&lt;/p&gt;
&lt;p&gt;Open problems are interesting; daily practice is more interesting. What does a 2026 administrator, researcher, red-team operator, and detection engineer actually do with Credential Guard?&lt;/p&gt;
&lt;h2&gt;10. Practical guide&lt;/h2&gt;
&lt;p&gt;Four audiences; four operational checklists. Each is short because each builds on a section we have already walked.&lt;/p&gt;
&lt;h3&gt;For an administrator or platform engineer&lt;/h3&gt;
&lt;p&gt;Verify Credential Guard is running using the three supported surfaces [@ms-cg-configure]: &lt;code&gt;(Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard).SecurityServicesRunning&lt;/code&gt; should contain &lt;code&gt;1&lt;/code&gt;; &lt;code&gt;msinfo32&lt;/code&gt; should list &quot;Credential Guard&quot; under Virtualization-based Security Services Running; the System event log should show WinInit Event 13. Deploy via Intune Settings Catalog or GPO with &quot;Enabled without lock&quot; [@ms-cg-configure]. Inventory NTLMv1, MS-CHAPv2, Digest, CredSSP, and non-Microsoft SSP usage &lt;em&gt;before&lt;/em&gt; enabling, because those are the protocols that will lose SSO under Credential Guard.&lt;/p&gt;

On a Credential-Guard-on box, the following one-liner returns `True`:&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;(Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard).SecurityServicesRunning -contains 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;1&lt;/code&gt; corresponds to Credential Guard in the &lt;code&gt;SecurityServicesRunning&lt;/code&gt; bitmask [@ms-cg-configure]. Pair with the System event log filter &lt;code&gt;EventID=13, Source=Wininit&lt;/code&gt; to confirm the boot-time launch event. Use these to verify, not Task Manager: Microsoft explicitly disrecommends the Task Manager check.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &quot;Credential Guard should be enabled before a device is joined to a domain or before a domain user signs in for the first time. If Credential Guard is enabled after domain join, the user and device secrets may already be compromised.&quot; [@ms-cg-configure] On a default-on Windows 11 22H2+ deployment this is automatic; on legacy estates being migrated, it requires a re-image cycle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;For a security researcher&lt;/h3&gt;
&lt;p&gt;The verifiable trustlet artefacts are: the &lt;code&gt;.tpolicy&lt;/code&gt; PE section in &lt;code&gt;LsaIso.exe&lt;/code&gt;; the &lt;code&gt;s_IumPolicyMetadata&lt;/code&gt; export; the dual-EKU signature with the IUM EKU 1.3.6.1.4.1.311.10.3.37 visible in the certificate chain. The IUM-side enumeration approach is &lt;code&gt;NtQuerySystemInformation&lt;/code&gt; with the &lt;code&gt;SystemIsolatedUserModeInformation&lt;/code&gt; class. Quarkslab&apos;s IUM-debugging walkthrough [@quarkslab-falcon-ium] documents the nested-virt setup (VMware L1 + Hyper-V L2), the GDB-stub attach on &lt;code&gt;hvix64.exe&lt;/code&gt;, the patch on &lt;code&gt;SecureKernel!SkpsIsProcessDebuggingEnabled&lt;/code&gt; to force-return 1, and the walk to &lt;code&gt;SecureKernel.exe&lt;/code&gt; from &lt;code&gt;HvCallVtlReturn&lt;/code&gt; at hypercall ID 0x12. Lyak&apos;s PassTheChallenge methodology [@github-passthechallenge] is the canonical worked example for the agent-side trustlet RPC interaction.&lt;/p&gt;
&lt;h3&gt;For a red-team operator&lt;/h3&gt;
&lt;p&gt;Assume the long-term hash and TGT are not in &lt;code&gt;lsass.exe&lt;/code&gt;. Assume the trustlet&apos;s RPC output is. The 2026 LPE / credential playbook focuses on credential &lt;em&gt;use&lt;/em&gt; (Kerberoast against weak service-account passwords; AS-REP Roast against accounts with &lt;code&gt;DONT_REQ_PREAUTH&lt;/code&gt;; RBCD via KrbRelayUp [@github-krbrelayup]; AD CS misconfigurations -- the ESC1-ESC11 enumeration), token impersonation (the PrintSpoofer / Potato chain [@itm4n-printspoofer]), and supplied-credential capture (keylogger on the prompt path). The companion NTLMless article in this series [@paragmali-ntlmless] covers the protocol-removal frontier that closes the Pass-the-Challenge NTLMv1 leg specifically.&lt;/p&gt;
&lt;h3&gt;For a detection engineer&lt;/h3&gt;
&lt;p&gt;WinInit Events 15, 16, and 17 (&quot;Credential Guard configured but did not run&quot;) are a high-fidelity &quot;attacker disabled Credential Guard&quot; detection -- if the box is supposed to be Credential-Guard-on and the boot-time event logs show one of those IDs, something blocked the trustlet from launching. ETW Microsoft-Antimalware-Engine plus AMSI [@ms-amsi] on &lt;code&gt;lsass.exe&lt;/code&gt; security-package load is the high-fidelity detection surface for Pass-the-Challenge-style injection (the attacker has to load a security-package DLL into &lt;code&gt;lsass.exe&lt;/code&gt; to get the established ALPC channel). On the network side, a &lt;code&gt;crack.sh&lt;/code&gt; submission carrying the static &lt;code&gt;1122334455667788&lt;/code&gt; challenge is an indicator of Pass-the-Challenge cracking activity by an internal user.&lt;/p&gt;
&lt;p&gt;Three misconceptions about Credential Guard get asked in every defensive-architecture review. The FAQ that follows resolves them, with primary citations for each answer.&lt;/p&gt;
&lt;h2&gt;11. Frequently asked questions&lt;/h2&gt;
&lt;p&gt;These are the seven questions that come up in every Credential Guard architectural review. Each answer is grounded in a primary source.&lt;/p&gt;

No. The *long-lived* NTLM hash and the Kerberos *long-term key* are unstealable from VTL0 memory; the per-session Kerberos service tickets are not protected, though the TGT is [@ms-cg-howitworks]. Pass-the-Ticket on the agent recovers the current session&apos;s tickets even on a Credential-Guard-on box. The architectural pivot is &quot;long-lived secret out of the agent&apos;s memory,&quot; not &quot;no secret in the agent&apos;s memory.&quot;

Yes. The dump succeeds; the contents are different. Where the NT hash field used to hold the bytes of the hash, [the field now holds the literal string `[LSA Isolated Data]` followed by an opaque ciphertext](https://github.com/ly4k/PassTheChallenge), with embedded `Context Handle`, `Proxy Info`, and `DPAPI` GUID fields. The encrypted blob is AES-GCM-wrapped by the trustlet under a key the agent does not hold. The dump is a statement of architecture, not a statement of failure.

No. Kerberoasting [@attack-kerberoast] cracks the service account&apos;s NT hash from a TGS-REP delivered over the wire by the KDC. No memory of the Credential-Guard-protected box is ever read. The mitigation for Kerberoasting is strong service-account passwords (or moving to managed service accounts with auto-rotated 240-character passwords), not Credential Guard.

No. The Potato chain [@itm4n-printspoofer] (Hot, Rotten, Juicy, PrintSpoofer, RoguePotato, GodPotato) escalates from a service user with `SeImpersonatePrivilege` to NT AUTHORITY\SYSTEM by impersonating a coerced inbound SYSTEM authentication. The chain operates on *tokens*, not *credentials*. Credential Guard protects credentials.

No, by design. Microsoft documents the carve-out verbatim: &quot;Enabling Credential Guard on domain controllers isn&apos;t recommended. Credential Guard doesn&apos;t provide any added security to domain controllers, and can cause application compatibility issues on domain controllers.&quot; [@ms-cg-overview] The most-attacked LSASS on the network -- on the domain controller, holding `NTDS.dit` and the `krbtgt` long-term key -- is explicitly out of scope. The mitigations for DC LSASS are physical and procedural: dedicated Tier-0 Privileged Access Workstations, no general-purpose interactive logon, and the *Mitigating Pass-the-Hash* v2 playbook [@ms-lsa-protection].

No. PPL is kernel-enforced inside the NT TCB; Credential Guard is a VTL1 trustlet outside it. itm4n&apos;s writeup is explicit: &quot;LSA Protection tends to be confused with Credential Guard, which is completely different ... Credential Guard and LSA Protection are actually complementary.&quot; [@itm4n-runasppl] Both should be enabled. PPL raises the bar for opportunistic attackers; Credential Guard moves the secret across a TCB boundary that an NT-kernel-mode attacker cannot cross.

Because the application chains through a protocol that cannot use Credential-Guard-protected credentials. &quot;When Credential Guard is enabled, NTLMv1, MS-CHAPv2, Digest, and CredSSP can&apos;t use the signed-in credentials&quot; [@ms-cg-howitworks]; third-party SSPs that depend on `KerbQuerySupplementalCredentialsMessage` simply break under Credential Guard [@ms-cg-considerations]. The remediation is to migrate the application to a supported protocol (Kerberos with AES, certificate-based EAP-TLS / PEAP-TLS, or Hello-for-Business per-application keys).
&lt;p&gt;The empty hash from §1 is, in 2026, a property of every domain-joined Windows 11 22H2+ box on the planet. Eleven years of &lt;code&gt;lsass.exe&lt;/code&gt; extraction history made the architectural pivot inevitable; eight years of trustlet maturation have made the pivot the default. What remains -- the use surface, the protocol surface, the token surface, the typed-credential surface, the third-party-SSP surface -- is the next eleven years of work.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;credential-guard-lsass-isolation-the-canonical-vbs-trustlet&quot; keyTerms={[
  { term: &quot;lsass.exe&quot;, definition: &quot;The user-mode Windows service that handles authentication and (until Credential Guard) held every long-lived credential in process memory. The agent in the agent / trustlet split.&quot; },
  { term: &quot;LsaIso.exe&quot;, definition: &quot;The Credential Guard trustlet (Trustlet ID 1) running in VTL1, holding the NTOWF and Kerberos long-term keys behind a hypervisor boundary.&quot; },
  { term: &quot;NTOWF&quot;, definition: &quot;The MD4 of the UTF-16-LE password. Functionally equivalent to the password for any NTLM-speaking service; the canonical Pass-the-Hash credential.&quot; },
  { term: &quot;Pass-the-Hash&quot;, definition: &quot;An attack class in which the client proves possession of the NTOWF without knowing the cleartext password. Originally published by Paul Ashton in 1997.&quot; },
  { term: &quot;Pass-the-Challenge&quot;, definition: &quot;Lyak&apos;s December 2022 attack class against Credential Guard: inject into lsass.exe, call NtlmIumCalculateNtResponse against the static challenge 1122334455667788, submit to crack.sh, recover the NT hash in ~30 seconds.&quot; },
  { term: &quot;PPL (Protected Process Light)&quot;, definition: &quot;A signer-level NT-kernel-enforced isolation mechanism that prevents non-PPL callers from opening lsass.exe for memory read. Bypassable from kernel via mimidrv.sys and from userland (on legacy Windows) via PPLdump.&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A Microsoft-signed binary loaded by the Secure Kernel into VTL1 user mode at boot. Identified by Trustlet ID; constrained by Signature Level 12 and the dual-EKU (WSCV + IUM) signature.&quot; },
  { term: &quot;VTL0 / VTL1&quot;, definition: &quot;Virtual Trust Levels enforced by the Hyper-V hypervisor. VTL0 = Normal World (NT kernel + user-mode); VTL1 = Secure World (Secure Kernel + IUM trustlets).&quot; },
  { term: &quot;IUM (Isolated User Mode)&quot;, definition: &quot;The Ring-3 user mode component of VTL1; the address space in which trustlets execute.&quot; },
  { term: &quot;ALPC&quot;, definition: &quot;Advanced Local Procedure Call: the Windows IPC primitive used to carry the LSA_ISO_RPC_SERVER channel between lsass.exe in VTL0 and LsaIso.exe in VTL1.&quot; },
  { term: &quot;Kerberoasting&quot;, definition: &quot;An attack on Kerberos service-account passwords by requesting TGS-REP tickets for arbitrary SPNs and cracking the etype-23 RC4-encrypted portion offline. Disclosed by Tim Medin at DerbyCon 4 (September 2014).&quot; },
  { term: &quot;RBCD (Resource-Based Constrained Delegation)&quot;, definition: &quot;A Kerberos delegation feature abused via the msDS-AllowedToActOnBehalfOfOtherIdentity LDAP attribute to mint service tickets as any user against a target. Refined by Forshaw 2022; weaponised in KrbRelayUp.&quot; },
  { term: &quot;SeImpersonatePrivilege&quot;, definition: &quot;The Windows token privilege held by service accounts that allows ImpersonateLoggedOnUser. The basis of the entire Potato escalation family.&quot; },
  { term: &quot;DPAPI&quot;, definition: &quot;The Windows per-user secret-protection API. The DPAPI GUID in the [LSA Isolated Data] block ties the trustlet record to the on-disk per-user master-key chain.&quot; },
  { term: &quot;VSM master key&quot;, definition: &quot;A symmetric key generated and stored only in VTL1, sealed by the TPM under PCR-bound policy, that wraps any persistent state the trustlets need to survive reboots.&quot; }
]} questions={[
  { q: &quot;Why did Microsoft conclude in 2014 that no patch could fix the LSASS-extraction class?&quot;, a: &quot;Because the secret is in a process whose memory is governed by the same NT kernel an attacker with administrator can subvert. Generations 0-4 add layers (PPL, WDigest disable, Protected Users, Tier-0 isolation) inside the NT-kernel TCB; only changing the TCB (moving the secret to a kernel the attacker cannot reach) addresses the structural problem.&quot; },
  { q: &quot;Distinguish LSA Protection (RunAsPPL) from Credential Guard.&quot;, a: &quot;PPL is NT-kernel-enforced; the same kernel an attacker is trying to subvert. Credential Guard is hypervisor-enforced; the secret moves to a separate kernel (the Secure Kernel / VTL1) the NT-kernel attacker cannot cross. They are complementary, not substitutes.&quot; },
  { q: &quot;What is in the encrypted blob field of a Pypykatz [LSA Isolated Data] dump on a Credential-Guard-on box?&quot;, a: &quot;An AES-GCM-wrapped serialised record containing (among other fields) the NTOWF, with a length-prefixed header (verbatim hex prefix a000000000000000080000006400000001000000010100000100000036) and an embedded ASCII tag 4e746c6d48617368 = NtlmHash that names the wrapped field. The wrap key is held only in VTL1 by LsaIso.exe.&quot; },
  { q: &quot;Walk the Pass-the-Challenge attack flow end to end.&quot;, a: &quot;Inject SecurityPackage.dll into lsass.exe; extract Context Handle from the Pypykatz dump; call NtlmIumCalculateNtResponse over the established ALPC channel with the static challenge 1122334455667788; receive the trustlet-computed NTLMv1 response; submit to crack.sh; receive the NT hash in approximately 30 seconds. The trustlet is faithful; the agent&apos;s request is the attack surface.&quot; },
  { q: &quot;Why is Pass-the-Challenge a class property of the agent / trustlet split rather than a Microsoft bug?&quot;, a: &quot;If lsass.exe could not call the trustlet, the trustlet would be useless (no path from wire challenge to response). If lsass.exe can call the trustlet, an attacker who compromises lsass.exe inherits the channel. Closing the gap structurally requires moving protocol code into the trustlet, which would dramatically expand the trustlet TCB and is not on Microsoft&apos;s roadmap.&quot; },
  { q: &quot;Name three things Credential Guard explicitly does not protect.&quot;, a: &quot;Domain controllers (NTDS.dit, krbtgt long-term key); credential use without theft (Kerberoasting, AS-REP Roasting, RBCD); SeImpersonatePrivilege Potato chain (token, not credential); plaintext-secret protocols (NTLMv1, MS-CHAPv2, Digest, CredSSP); out-of-LSA storage (web credentials, non-Microsoft SSPs, Remote Desktop Gateway prompt path).&quot; },
  { q: &quot;Why was default-on Credential Guard shipped without UEFI Lock?&quot;, a: &quot;To allow administrators to disable the feature remotely if a third-party SSP or MS-CHAPv2-dependent workflow breaks. The trade-off is that an attacker who has already obtained the privilege required to flip the registry value can also disable Credential Guard. Microsoft chose the operational reality of remote-disable convenience over the in-principle attacker-disable hardening.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>credential-guard</category><category>lsaiso</category><category>vbs-trustlets</category><category>lsass</category><category>mimikatz</category><category>pass-the-challenge</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>VBS Trustlets: What Actually Runs in the Secure Kernel</title><link>https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/</link><guid isPermaLink="true">https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/</guid><description>A field guide to Virtualization-Based Security trustlets on Windows 11: the five gates a binary passes to become one, the inbox roster, and where the model ends.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Trustlets are the user-mode processes Microsoft places in Virtual Trust Level 1** to hold the secrets a SYSTEM-privilege attacker on the Windows kernel must never reach: NTLM hashes, Kerberos tickets, biometric templates, virtual TPM keys, and (in 2025-2026) just-in-time admin tokens. A binary becomes a trustlet by passing five gates at load time: a process attribute, two specific signing EKUs at Signature Level 12, a `.tpolicy` PE section containing `s_IumPolicyMetadata`, a Trustlet Instance GUID, and a stripped-down loader path. Once loaded, the trustlet talks to the rest of Windows over ALPC, services an agent process in VTL0, and uses only 48 of NT&apos;s roughly 480 syscalls. The Hyper-V hypervisor refuses to map its pages into VTL0. That is what &quot;isolated&quot; means.
&lt;h2&gt;1. Four Locked Rooms&lt;/h2&gt;
&lt;p&gt;It is 3:14 a.m. and a red-team operator on a fully patched Windows 11 25H2 box has, after eight hours of careful work, achieved the prize: a SYSTEM-privilege write primitive in the NT kernel. For two decades that has been the moment when the engagement ends and the report writes itself. SYSTEM in the kernel meant every process, every page, every secret. Game over.&lt;/p&gt;
&lt;p&gt;It is not game over.&lt;/p&gt;
&lt;p&gt;The operator&apos;s target list has four items on it. The &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows&quot; rel=&quot;noopener&quot;&gt;NTLM hashes&lt;/a&gt; and Kerberos Ticket-Granting Tickets sitting in &lt;code&gt;lsass.exe&lt;/code&gt;. The user&apos;s fingerprint template, in whatever process the &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar&quot; rel=&quot;noopener&quot;&gt;Windows Hello&lt;/a&gt; biometric pipeline puts it. The just-in-time admin token that Administrator Protection issued thirty seconds ago. The keys of the four Hyper-V virtual machines running on the box, including the one hosting the user&apos;s corporate VPN. Four secrets. Four user-mode processes. And on this 2026 machine, four locked rooms whose pages the operator&apos;s kernel write primitive cannot touch and whose contents the operator&apos;s kernel does not have permission to ask.&lt;/p&gt;
&lt;p&gt;Those four processes are &lt;em&gt;trustlets&lt;/em&gt;. They run in a different kernel from the one the operator just compromised, on a different virtual trust level enforced by a hypervisor running underneath both. The operator owns the NT kernel; the NT kernel does not own them. That sentence is what changed in 2015, and the rest of this piece is what it actually means.&lt;/p&gt;
&lt;p&gt;This is not &quot;Microsoft hid the memory better.&quot; It is not obfuscation, not a clever access-control rule, not a kernel mitigation that the next CVE will erase. It is an architectural relocation: the user-mode processes that hold the secrets no longer live in the operating system the attacker compromised. The hypervisor refuses to map their pages into Virtual Trust Level 0 (&quot;VTL0&quot;), and the operator&apos;s kernel is in VTL0.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Four user-mode processes survive a SYSTEM kernel write primitive on a 2026 Windows 11 box. That is what changed in 2015, and trustlets are the reason.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The promise of this piece is to explain trustlets at the level of &quot;what does &lt;code&gt;LsaIso.exe&lt;/code&gt; actually do, how is it built, how does it talk to the rest of the system, and where does the model end.&quot; Not at the level of &quot;VBS isolates them.&quot; By the end, four locked rooms will have become something you can name, list, audit, and reason about. Where the public record runs out (some trustlet binary names and IDs are not on Microsoft&apos;s published list as of mid-2026), the piece will say so, and it will tell you what the actual records look like instead of inventing replacements.&lt;/p&gt;
&lt;p&gt;So how does a user-mode process become unreachable from SYSTEM-in-the-NT-kernel? The answer is not new. It begins, like much of operating-system security, at MIT in the early 1970s.&lt;/p&gt;
&lt;h2&gt;2. The User-Mode-In-A-Higher-Privilege Problem&lt;/h2&gt;
&lt;p&gt;In March 1972 Michael Schroeder and Jerome Saltzer published a paper in the &lt;em&gt;Communications of the ACM&lt;/em&gt; describing an unusual machine. The Multics team at MIT had been wrestling with a question that does not, at first glance, sound like a security question. What should happen when a user program calls a password-checking routine that needs to read the system password file? The user program must not be allowed to read that file directly. The routine must be allowed to read it. The two pieces of code run in the same process. How does the machine know which one is asking?&lt;/p&gt;
&lt;p&gt;Schroeder and Saltzer&apos;s answer was eight hardware-enforced rings of privilege, with each segment in memory carrying a &lt;em&gt;ring bracket&lt;/em&gt; in its descriptor word, and with cross-ring calls validated automatically by the hardware [@multicians-protection] [@multicians-papers]. The hardware that shipped this design was the Honeywell 6180 in 1973 [@wiki-protection-ring]. The pattern matters more than the gear. Some user code needed to run with more privilege than its caller and less privilege than the kernel. Multics arranged eight such layers from user code at the outermost ring down to the supervisor at ring 0 [@wiki-multics].&lt;/p&gt;

The set of hardware, firmware, and software whose correct operation is necessary to enforce a security policy. If any component of the TCB can be subverted, the policy can be subverted. The smaller the TCB, the easier it is to audit; the larger it is, the more places an attacker can find a foothold.
&lt;p&gt;A few years later at Carnegie Mellon, William Wulf, Roy Levin, and the Hydra team took a different swing at the same problem. Hydra was a capability-based, object-oriented microkernel that ran on the C.mmp multiprocessor between 1971 and 1975 [@wiki-hydra]. Where Multics multiplied rings, Hydra multiplied &lt;em&gt;vocabulary&lt;/em&gt;: every protected resource was an object addressable only through capability tokens, and security-critical subsystems lived not inside the kernel but as user-mode capability-holders trusted by the kernel to enforce their own policy. Levin et al.&apos;s 1975 SOSP paper &quot;Policy/Mechanism Separation in HYDRA&quot; gave the design its slogan, and that slogan has outlived the system that produced it [@levy-capabook].Hydra&apos;s &quot;policy versus mechanism&quot; phrasing still appears verbatim in modern object-capability literature, in the design discussion of WebAssembly&apos;s component model, and in seL4&apos;s published rationale.&lt;/p&gt;
&lt;p&gt;For two decades the L4 family answered &quot;but is this fast enough to be practical?&quot; Jochen Liedtke&apos;s 1993 prototype, hand-coded in i386 assembly, ran inter-process communication twenty times faster than Carnegie&apos;s Mach microkernel [@wiki-l4]. His 1995 SOSP paper &quot;On µ-Kernel Construction&quot; was inducted into the ACM SIGOPS Hall of Fame in 2015 and is the foundational statement of the minimal-kernel, maximal-user-mode-trusted-services design. By 2010, OKL4, a commercial L4 derivative, had shipped in over one billion mobile devices [@wiki-l4].&lt;/p&gt;

A kernel design that pushes as much functionality as possible out of kernel mode and into user-mode &quot;servers&quot; that communicate via inter-process calls. Filesystem code, networking stacks, even device drivers can run as user-mode processes. The kernel itself shrinks to a few thousand lines of code that schedule processes, route messages, and enforce memory isolation, and nothing else.
&lt;p&gt;In 2009 the lineage reached an end that nobody had reached before. Gerwin Klein, Kevin Elphinstone, Gernot Heiser and the NICTA team published &lt;em&gt;seL4: Formal Verification of an OS Kernel&lt;/em&gt; at SOSP, reporting a machine-checked proof of functional correctness from a formal specification down to the C implementation [@sel4-sosp-paper]. seL4 was open-sourced in July 2014 [@wiki-sel4]; the seL4 Foundation&apos;s About page states plainly that seL4 stands out because of its thoroughgoing formal verification [@sel4-about]. A kernel of about 8,700 lines of C, formally verified from specification to C implementation, with sub-microsecond inter-process calls.&lt;/p&gt;
&lt;p&gt;Schroeder and Saltzer asked it for hardware rings. Hydra asked it for capabilities. Liedtke asked it for inter-process speed. Klein and Heiser asked it of formal logic. The question stayed the same: how do you let some user-mode code hold a secret that some other code in the same machine is not allowed to read, when both pieces of code are scheduled by the same kernel? The Multics answer was rings. The Hydra answer was capabilities. The L4 answer was a tiny kernel plus IPC. The seL4 answer was a tiny kernel plus IPC, plus a proof.&lt;/p&gt;
&lt;p&gt;The Microsoft answer, in July 2015, was a hypervisor.&lt;/p&gt;

timeline
    title User-mode-in-higher-privilege lineage
    1972 : Multics 8-ring hardware
         : Honeywell 6180 ring brackets
    1974 : Hydra capabilities
    1975 : Policy vs mechanism
    1993 : L4 microkernel
         : Fast user-mode IPC
         : Windows NT ships ring 0/3
    2007 : Vista Protected Processes
    2009 : seL4 verification
    2013 : Windows 8.1 PPL
    2015 : Windows 10 IUM ships
         : Trustlets 0-3 enumerated
    2024 : VBS Enclaves go third-party
    2026 : Administrator Protection
&lt;p&gt;If the architectural answer was already in the 1970s academic literature, why did Microsoft wait until 2015 to ship it on Windows? Because three earlier attempts to ship user-mode isolation on Windows -- under three different names, in three different decades -- each failed in the same way.&lt;/p&gt;
&lt;h2&gt;3. Three Tries Before Trustlets&lt;/h2&gt;
&lt;p&gt;Before 2015 Microsoft tried three times to ship user-mode isolation on Windows. All three shipped in production. All three failed in the same way.&lt;/p&gt;
&lt;h3&gt;2007: Vista Protected Processes&lt;/h3&gt;
&lt;p&gt;Windows Vista introduced &lt;em&gt;Protected Processes&lt;/em&gt; in January 2007. The motivation was not credential security; it was Digital Rights Management. The Protected Media Path required a set of binaries -- &lt;code&gt;audiodg.exe&lt;/code&gt;, &lt;code&gt;mfpmp.exe&lt;/code&gt;, and a handful of others involved in Blu-ray playback -- whose memory non-protected processes could not read, whose threads could not be debugged from outside, and whose DLL imports could not be hijacked at runtime [@wiki-pmp]. The kernel enforced these rules by refusing to grant the relevant access masks (&lt;code&gt;PROCESS_VM_READ&lt;/code&gt;, &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, &lt;code&gt;THREAD_ALL_ACCESS&lt;/code&gt;) to handles requested from non-protected processes.&lt;/p&gt;
&lt;p&gt;The mechanism was elegant. The threat model was not. Alex Ionescu announced in January 2007 -- within weeks of Vista&apos;s general availability -- that he had developed a bypass method for the Protected Media Path [@wiki-pmp]. The same NT kernel that enforced the protection was the kernel an attacker would compromise to bypass it. A signed kernel driver, or any of the long stream of subsequent kernel vulnerabilities, would walk straight through.&lt;/p&gt;
&lt;h3&gt;2012: AppContainer and the LowBox token&lt;/h3&gt;
&lt;p&gt;Windows 8 introduced &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention&quot; rel=&quot;noopener&quot;&gt;AppContainer&lt;/a&gt; process isolation in October 2012, originally to support Windows Store apps (later unified as the Universal Windows Platform in Windows 10) [@wiki-uwp]. Each AppContainer process ran with a &lt;em&gt;LowBox&lt;/em&gt; token: a low-integrity primary token plus a SID, plus a set of named capabilities (&lt;code&gt;internetClient&lt;/code&gt;, &lt;code&gt;picturesLibrary&lt;/code&gt;, and so on), plus a per-AppContainer named-object subtree under &lt;code&gt;\Sessions\&amp;lt;N&amp;gt;\AppContainerNamedObjects\&amp;lt;SID&amp;gt;&lt;/code&gt;. The NT kernel checked the SID against object DACLs at every object access, denying access by default and granting it only where the AppContainer&apos;s declared capabilities matched the requested operation.&lt;/p&gt;
&lt;p&gt;This is a Hydra-style capability lattice bolted onto NT&apos;s existing access-control system. It is a useful sandboxing primitive for &lt;em&gt;untrusted&lt;/em&gt; code, and modern browsers (the Edge renderer, the Chromium sandbox) consume it for exactly that purpose. It is not a defence against an attacker who already has kernel code execution. In August 2018 James Forshaw at Google Project Zero published an exploit for Issue 1550 that turned the AppContainer named-object namespace itself into an arbitrary-directory-creation primitive [@forshaw-2018]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The AppInfo service... calls the undocumented API CreateAppContainerToken... As the API is called without impersonating the user... the object directories are created with the identity of the service, which is SYSTEM.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A low-integrity caller could direct that SYSTEM-owned creation at any directory it pleased and use the result to elevate. The lattice held; the lattice&apos;s &lt;em&gt;enforcer&lt;/em&gt; did not. AppContainers continue to ship, doing their actual job (sandboxing untrusted code) reasonably well. They were never going to answer the trustlet question (isolating trusted code from a compromised kernel) because they are NT-kernel-enforced.&lt;/p&gt;
&lt;h3&gt;2013: Protected Process Light (PPL) and &lt;code&gt;RunAsPPL&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Windows 8.1 generalised the Vista mechanism into a &lt;em&gt;signer-level lattice&lt;/em&gt;. Each protected process now had a two-dimensional protection level: a signer (&lt;code&gt;WinTcb&lt;/code&gt;, &lt;code&gt;Windows&lt;/code&gt;, &lt;code&gt;Antimalware&lt;/code&gt;, &lt;code&gt;Authenticode&lt;/code&gt;, others) and a protection type (&lt;code&gt;PsProtectedSignerTcb&lt;/code&gt;, &lt;code&gt;PsProtectedSignerAuthenticode&lt;/code&gt;, others). Higher-signer processes could manipulate lower-signer ones; same-signer processes could not see across the line. The first canonical use case was anti-malware services that registered an Early Launch Anti-Malware (ELAM) driver and then ran their user-mode service as a Protected Process Light [@msdocs-protecting-am].&lt;/p&gt;

A Windows 8.1 process attribute that constrains which other processes can request high-privilege access to it. PPL extends the Vista Protected Process mechanism with a signer-level lattice (WinTcb &amp;gt; Windows &amp;gt; Antimalware &amp;gt; Authenticode &amp;gt; None) and a protection type. The NT kernel enforces the rules. LSASS running as a PPL is the canonical use case, exposed to administrators via the `RunAsPPL` registry value [@itm4n-runasppl].
&lt;p&gt;Alex Ionescu&apos;s 2013 essay &quot;The Evolution of Protected Processes Part 3&quot; documented the resulting Signing Levels table -- Signature Level 12 named &quot;Windows,&quot; Level 13 &quot;Windows Protected Process Light,&quot; Level 14 &quot;Windows TCB&quot; [@ionescu-ppp3] [@ionescu-ppp1]. That table is the load-bearing reference for every later trustlet design: every IUM binary on a 2026 Windows machine must satisfy &lt;em&gt;at least&lt;/em&gt; Signature Level 12. Microsoft shipped LSASS-as-PPL (&quot;LSA Protection,&quot; exposed through the &lt;code&gt;RunAsPPL&lt;/code&gt; registry value under &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\Lsa&lt;/code&gt;) as the canonical example: a way to keep the lower-privileged half of an administrator&apos;s session from reading credential material out of LSASS memory.&lt;/p&gt;
&lt;p&gt;It worked, for some values of &quot;worked.&quot; It worked against pass-the-hash tools that ran as an ordinary administrator without a signed kernel driver. It did not work against an attacker willing to load any signed driver, and -- as became clear in 2021 -- it did not work even from userland once the bypass class was identified.&lt;/p&gt;
&lt;p&gt;In August 2018 James Forshaw, in the same Project Zero post that exposed the AppContainer issue, also documented a &lt;code&gt;DefineDosDevice&lt;/code&gt; plus Known-DLL hijack technique. By creating a symbolic link in the NT object manager namespace that aliased a Known DLL section, an administrative caller could induce a target PPL process to load arbitrary code at the next image load [@forshaw-2018]. In 2021 the researcher who blogs as itm4n weaponised the same primitive into &lt;code&gt;PPLdump&lt;/code&gt;, a userland tool that dumped &lt;code&gt;lsass.exe&lt;/code&gt; memory from an administrator command prompt with no kernel driver involved [@itm4n-runasppl]. itm4n&apos;s writeup is honest about what this means:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Like any other protection though, it is not bulletproof and it is not sufficient on its own, but it is still particularly efficient.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft closed the &lt;code&gt;DefineDosDevice&lt;/code&gt; corner of this class in Windows 10 21H2 build 19044.1826, shipped in July 2022 [@itm4n-end-of-ppldump]. That is eight years of mainstream PPL deployment during which the LSASS-as-PPL credential boundary was bypassable without ring 0 access at all.&lt;/p&gt;
&lt;h3&gt;The pattern&lt;/h3&gt;
&lt;p&gt;Three primitives. Three different protection mechanisms. One common failure mode.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Enforcer&lt;/th&gt;
&lt;th&gt;Threat model&lt;/th&gt;
&lt;th&gt;Defeated by&lt;/th&gt;
&lt;th&gt;Status today&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Vista Protected Process&lt;/td&gt;
&lt;td&gt;2007&lt;/td&gt;
&lt;td&gt;NT kernel&lt;/td&gt;
&lt;td&gt;Untrusted user code reading DRM-protected media buffers&lt;/td&gt;
&lt;td&gt;Signed kernel drivers; Ionescu Jan 2007 [@wiki-pmp]&lt;/td&gt;
&lt;td&gt;Superseded by PPL for non-DRM use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppContainer / LowBox&lt;/td&gt;
&lt;td&gt;2012&lt;/td&gt;
&lt;td&gt;NT kernel&lt;/td&gt;
&lt;td&gt;Untrusted store-app code escaping its capability sandbox&lt;/td&gt;
&lt;td&gt;SYSTEM-owned directory creation via service impersonation [@forshaw-2018]&lt;/td&gt;
&lt;td&gt;Active for sandboxing untrusted code; not a trustlet substitute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protected Process Light (&lt;code&gt;RunAsPPL&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2013&lt;/td&gt;
&lt;td&gt;NT kernel&lt;/td&gt;
&lt;td&gt;Userland administrative attacker reading LSASS credential material&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DefineDosDevice&lt;/code&gt; plus Known-DLL hijack; PPLdump 2021 [@itm4n-runasppl]&lt;/td&gt;
&lt;td&gt;Active as defence-in-depth; closed in build 19044.1826, July 2022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isolated User Mode / trustlets&lt;/td&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;Hypervisor + Secure Kernel&lt;/td&gt;
&lt;td&gt;VTL0 kernel attacker reading user-mode secrets&lt;/td&gt;
&lt;td&gt;Secure-call interface bugs; agent-side RPC residual [@amar-bh2020]&lt;/td&gt;
&lt;td&gt;Active; subject of this article&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Three rows, one diagnosis. Every NT-kernel-enforced isolation primitive shares the attacker&apos;s TCB. Improving the lattice the NT kernel enforces does not move the security ceiling, because the NT kernel itself can be compromised; once it is, any policy decision the NT kernel makes is the attacker&apos;s policy decision. Microsoft&apos;s own VBS hardware-requirements page admits the diagnosis verbatim:&lt;/p&gt;

VBS uses hardware virtualization and the Windows hypervisor to create an isolated virtual environment that becomes the root of trust of the OS that assumes the kernel can be compromised. -- Microsoft, OEM VBS hardware requirements [@msdocs-oem-vbs]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;RunAsPPL&lt;/code&gt; is useful defence in depth. It is not, and has never been, a substitute for Credential Guard. itm4n&apos;s 2021 PPLdump release was the proof for the userland half of that statement; signed-driver loaders are the proof for the ring-zero half. If your threat model includes a determined attacker with administrative rights, Credential Guard is the boundary; PPL is the speed bump in front of it [@itm4n-runasppl].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If every primitive the NT kernel enforces shares the attacker&apos;s TCB, the kernel that enforces user-mode isolation has to be a &lt;em&gt;different&lt;/em&gt; kernel. In July 2015 Microsoft shipped one.&lt;/p&gt;
&lt;h2&gt;4. July 2015: The Hypervisor Becomes the Arbiter&lt;/h2&gt;
&lt;p&gt;On 29 July 2015 Microsoft shipped Windows 10 build 10240 [@wiki-win10-history]. Two new ideas shipped with it. The first was Hyper-V&apos;s hypervisor running &lt;em&gt;underneath&lt;/em&gt; the NT kernel even on a laptop, not just on a server hosting virtual machines [@wiki-hyperv]. The second was a separate kernel running alongside the NT kernel, at a different Virtual Trust Level. Together those two ideas produce a substrate where the long-time equation &quot;SYSTEM kernel write primitive equals every secret in user-mode memory&quot; is no longer true.&lt;/p&gt;

A hypervisor-managed privilege axis added on top of x86&apos;s existing ring 0 / ring 3 split. Each VTL has its own kernel mode and its own user mode. Higher VTLs can read and write lower-VTL memory; lower VTLs cannot read or write higher-VTL memory at all. The Hyper-V Top-Level Functional Specification reserves up to 16 VTLs; the current Hyper-V implementation defines `#define HV_NUM_VTLS 2` [@msdocs-vsm].
&lt;p&gt;The Hyper-V Top-Level Functional Specification states the rule directly: &lt;em&gt;&quot;VSM achieves and maintains isolation through Virtual Trust Levels (VTLs)... Architecturally, up to 16 levels of VTLs are supported; however a hypervisor may choose to implement fewer than 16 VTL&apos;s. Currently, only two VTLs are implemented&quot;&lt;/em&gt; [@msdocs-vsm]. The NT kernel runs in VTL0 ring 0; user-mode applications run in VTL0 ring 3. The &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel&quot; rel=&quot;noopener&quot;&gt;Secure Kernel&lt;/a&gt; runs in VTL1 ring 0; trustlets run in VTL1 ring 3. Each VTL transition takes the CPU through a VMEXIT and back, with VMCS save and restore on each crossing [@quarkslab-virtual-journey].The architectural cap of sixteen VTLs is in the published specification but is not deployed. Stocking the unused slots would require both hypervisor changes and a new design for who manages the additional kernel images. The two-VTL design is the entire shipped product.&lt;/p&gt;
&lt;p&gt;Quarkslab&apos;s reverse-engineering team put the practical consequence in one sentence in their IUM-debugging writeup: &lt;em&gt;&quot;VTL0 is the Normal World, where the traditional kernel-mode and user-mode code run in ring 0 and ring 3, respectively. On top of that, a new world appears: VTL1 is the privileged Secure World, where the Secure Kernel runs in ring 0, and a limited number of IUM processes run in ring 3. Code running in VTL0, even in ring 0, cannot access the higher-privileged VTL1&quot;&lt;/em&gt; [@quarkslab-debug-ium].&lt;/p&gt;
&lt;p&gt;That sentence is the architectural fact the whole article rests on. The hypervisor configures each guest physical page&apos;s permissions on a per-VTL basis using the CPU&apos;s Second Level Address Translation tables. A page can be readable from VTL0 and VTL1, readable from VTL1 only, or readable from neither.On Intel hardware, the per-VTL permissions are implemented with Extended Page Tables (EPT); on AMD they use Nested Page Tables (NPT). The hypervisor keeps the per-VTL EPT/NPT entries in its own memory, not in the guest&apos;s.&lt;/p&gt;

The hardware mechanism (Intel EPT, AMD NPT) that lets a hypervisor define page-level read, write, and execute permissions independent of the guest&apos;s own page tables. With VTLs, SLAT entries are per-VTL: a page&apos;s permissions when the CPU is executing VTL1 code can differ from the same page&apos;s permissions when the CPU is executing VTL0 code. A SYSTEM-privilege VTL0 attacker who edits the NT kernel&apos;s page tables cannot change the VTL1-side permissions, because those live in hypervisor-managed structures that VTL0 page-table writes do not touch.

flowchart LR
    subgraph VTL0[&quot;VTL0 (Normal World)&quot;]
        ring3_0[&quot;Ring 3: lsass.exe, vmwp.exe, user apps&quot;]
        ring0_0[&quot;Ring 0: NT kernel + signed drivers&quot;]
        ring3_0 --&amp;gt; ring0_0
    end
    subgraph VTL1[&quot;VTL1 (Secure World)&quot;]
        ring3_1[&quot;Ring 3: LsaIso.exe, vmsp.exe, trustlets&quot;]
        ring0_1[&quot;Ring 0: Secure Kernel (securekernel.exe)&quot;]
        ring3_1 --&amp;gt; ring0_1
    end
    VTL0 -. ALPC over agent ALPC port .-&amp;gt; VTL1
    VTL1 -. read VTL0 memory .-&amp;gt; VTL0
    hv[&quot;Hyper-V hypervisor: per-VTL SLAT permissions&quot;]
    VTL0 --&amp;gt; hv
    VTL1 --&amp;gt; hv
&lt;p&gt;The VTL hierarchy is not symmetric. VTL1 code can read VTL0 memory; that is how a trustlet can dispatch the contents of an &lt;code&gt;lsass.exe&lt;/code&gt; RPC request the moment after VTL0 wrote it. VTL0 code cannot read VTL1 memory under any condition the hypervisor permits. A kernel write primitive in VTL0 lets the attacker corrupt the NT kernel&apos;s data structures, modify drivers, and walk every VTL0 process&apos;s pages. The attacker can do every one of those things and not be one byte closer to the contents of &lt;code&gt;LsaIso.exe&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s IUM documentation at Windows 10 RTM named two trustlets explicitly: &lt;strong&gt;Trustlet ID 0 = the Secure Kernel Process&lt;/strong&gt; (hosts Device Guard and Hypervisor-protected Code Integrity policy decisions), and &lt;strong&gt;Trustlet ID 1 = &lt;code&gt;LSAISO.EXE&lt;/code&gt;&lt;/strong&gt; (Credential Guard&apos;s isolated LSA, holding NTLM hashes and Kerberos Ticket-Granting Tickets out of VTL0 reach). Two more (IDs 2 and 3, covered in §6) also shipped on the RTM image and were enumerated a week later by Ionescu&apos;s Black Hat reverse-engineering [@msdocs-ium] [@ionescu-bh2015]. Microsoft Learn&apos;s IUM page introduces the vocabulary the rest of this piece will use:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Trustlets (also known as trusted processes, secure processes, or IUM processes) are programs running as IUM processes in VSM... With VSM enabled, the Local Security Authority (LSASS) environment runs as a trustlet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A week after Windows 10 shipped, on 5 August 2015, Alex Ionescu walked into a Black Hat USA briefing room in Mandalay Bay and reverse-engineered the entire thing in front of an audience [@ionescu-bh2015-infocondb]. His talk, &quot;Battle of the SKM and IUM: How Windows 10 Rewrites OS Architecture,&quot; is the canonical first public account of the trustlet model and the source from which Microsoft&apos;s own later documentation borrows terminology one for one [@ionescu-bh2015]. Almost every concrete fact in the next section -- the syscall allow-list, the EKUs, the &lt;code&gt;.tpolicy&lt;/code&gt; section, the Trustlet Instance GUID -- traces back to that single deck.&lt;/p&gt;
&lt;p&gt;Now we know what world a trustlet lives in. What architecturally &lt;em&gt;is&lt;/em&gt; one?&lt;/p&gt;
&lt;h2&gt;5. The Five Gates&lt;/h2&gt;
&lt;p&gt;A trustlet is not a special process &lt;em&gt;class&lt;/em&gt; the way a Protected Process is. It is an ordinary Portable Executable binary that has been loaded under five very specific conditions. Walk through them once and you will be able to recognise a trustlet in a &lt;code&gt;dumpbin /headers&lt;/code&gt; listing. The status is mechanical, not categorical. Chapter 9 of &lt;em&gt;Windows Internals, Seventh Edition, Part 2&lt;/em&gt; (Allievi, Russinovich, Ionescu, Solomon) covers the same architecture from the kernel-team side as a reference complement to Ionescu&apos;s BH2015 reverse-engineering [@windows-internals-7e-pt2].&lt;/p&gt;

A Windows user-mode process that runs in Virtual Trust Level 1 user mode (ring 3 of the Secure World), scheduled by the Secure Kernel and isolated from VTL0 by Hyper-V&apos;s per-VTL SLAT enforcement. A binary becomes a trustlet only if it satisfies five load-time conditions: a process attribute, two signing EKUs at Signature Level 12, a `.tpolicy` PE section containing `s_IumPolicyMetadata`, a Trustlet Instance GUID, and a stripped-down loader path. Trustlets are sometimes also called &quot;trusted processes,&quot; &quot;secure processes,&quot; or &quot;IUM processes&quot; [@msdocs-ium].

The user-mode environment of Virtual Trust Level 1. IUM is, structurally, ring 3 of VTL1. Its inhabitants are trustlets; its kernel is the Secure Kernel; its system-call surface is approximately one-tenth of NT&apos;s. Quarkslab&apos;s IUM-debugging writeup describes IUM as the place where *&quot;a limited number of IUM processes run in ring 3&quot;* of VTL1; Microsoft&apos;s Win32 documentation describes the same architectural placement with different wording [@quarkslab-debug-ium] [@msdocs-ium].
&lt;h3&gt;Gate 1: the process attribute&lt;/h3&gt;
&lt;p&gt;VTL0 user-mode code cannot call &lt;code&gt;CreateProcess&lt;/code&gt; and produce a trustlet. The Win32 API does not expose the necessary primitive. A trustlet is born via a direct &lt;code&gt;NtCreateUserProcess&lt;/code&gt; syscall that carries a &lt;code&gt;PsAttributeSecureProcess&lt;/code&gt; attribute with a 64-bit Trustlet ID. Only callers that already live in VTL1, or callers in VTL0 that hold a specific brokering capability, can request that attribute and have the Secure Kernel honour it [@ionescu-bh2015].&lt;/p&gt;
&lt;p&gt;This is intentional. The Win32 layering is one of the surfaces an attacker can compromise, so the trustlet boot path bypasses it. There is no &quot;trustlet via shell&quot; -- not for an administrator, not for SYSTEM, not for the Secure Kernel itself other than through the documented internal path.&lt;/p&gt;
&lt;h3&gt;Gate 2: two EKUs at Signature Level 12&lt;/h3&gt;
&lt;p&gt;The binary must be signed with a certificate chain that contains two specific Enhanced Key Usage identifiers, and the resulting Signing Level must be 12 or higher. From Ionescu&apos;s BH2015 deck (correcting a typo in the slide): &lt;em&gt;&quot;They must have a Signature Level of 12... This means they must have the Windows System Component Verification EKU (1.3.6.1.4.1.311.10.3.6)... They must have the IUM EKU 1.3.6.1.4.1.311.10.3.37&quot;&lt;/em&gt; [@ionescu-bh2015].&lt;/p&gt;

An X.509 certificate extension that restricts which purposes a certificate can be used for. An EKU is an object identifier (OID); a code-signing certificate that claims an OID of `1.3.6.1.4.1.311.10.3.6` is asserting it is valid for the &quot;Windows System Component Verification&quot; purpose. The Windows code-integrity subsystem (`ci.dll`) checks the requested EKU against the actual certificate at signature time and refuses to load the image if the EKU is missing or the certificate is not chained to a trusted root [@ionescu-ppp3].
&lt;p&gt;Both EKUs are required. The Windows System Component Verification EKU establishes the binary as a Microsoft-signed Windows component. The IUM EKU asserts the binary&apos;s &lt;em&gt;intent&lt;/em&gt; to load as a trustlet. A PPL EKU may sit on top, layering the PPL signer-level check on the trustlet check, but the two-EKU minimum is what Signing Level 12 enforces.The system-component EKU check is skipped when both Test Signing is enabled and the local machine trusts the Microsoft Test Root. That is the exact attack class Ionescu names verbatim in the BH2015 deck: &quot;compromise the platform via Test Signing&quot; disables the signing gate that defines trustlet identity.&lt;/p&gt;
&lt;h3&gt;Gate 3: the &lt;code&gt;.tpolicy&lt;/code&gt; section and &lt;code&gt;s_IumPolicyMetadata&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Every trustlet image must contain a PE section named &lt;code&gt;.tpolicy&lt;/code&gt; marked &lt;code&gt;IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ&lt;/code&gt;. The section must export the symbol &lt;code&gt;s_IumPolicyMetadata&lt;/code&gt;, a structure with three required components: a version byte set to 1, a 64-bit Trustlet ID that must match the one the process attribute requested, and a per-trustlet policy table containing entries for ETW (event tracing), debug permissions, crash-dump key release, and other trustlet-specific runtime knobs [@ionescu-bh2015].&lt;/p&gt;
&lt;p&gt;The Secure Kernel parses this section at load time via an internal routine the deck names &lt;code&gt;SkpspFindPolicy&lt;/code&gt;. A binary with no &lt;code&gt;.tpolicy&lt;/code&gt; section, or with one whose Trustlet ID disagrees with the process-attribute Trustlet ID, or whose version byte is anything other than 1, fails the gate. The Secure Kernel does not &quot;infer&quot; a trustlet identity; it reads it out of the binary the attacker would have had to sign.&lt;/p&gt;
&lt;h3&gt;Gate 4: the Trustlet Instance GUID&lt;/h3&gt;
&lt;p&gt;Once gates 1-3 pass, the trustlet calls a secure-service routine the deck names &lt;code&gt;IumSetTrustletInstance&lt;/code&gt;, identified by secure-call ordinal &lt;code&gt;0x80000001&lt;/code&gt;. That routine binds the running process to a Trustlet Instance GUID, the runtime identity by which the Secure Kernel discriminates one instance of a trustlet from another. Hyper-V partition GUIDs flow into this identifier for the vTPM trustlets, so that the secrets a partition&apos;s vTPM holds are scoped to that partition&apos;s Instance GUID.&lt;/p&gt;
&lt;p&gt;The same Instance GUID can be shared across distinct Trustlet IDs. That is the architectural primitive Microsoft uses for trustlet-to-trustlet authentication: the host-side Hyper-V vTPM (&lt;code&gt;vmsp.exe&lt;/code&gt;, Trustlet ID 2) and the vTPM provisioning trustlet (ID 3) cooperate on a single partition&apos;s secrets by sharing the partition&apos;s Instance GUID. The Secure Kernel&apos;s &lt;code&gt;SkCapabilities&lt;/code&gt; table hardcodes which Trustlet IDs are permitted to invoke which secure-storage operations against an Instance GUID; for the 2015-era IUM surface, the only ID-discriminated rules are &lt;code&gt;CheckByTrustletId 2&lt;/code&gt; for &lt;code&gt;SecureStorageGet&lt;/code&gt; and &lt;code&gt;CheckByTrustletId 3&lt;/code&gt; for &lt;code&gt;SecureStorageSet&lt;/code&gt; [@ionescu-bh2015].&lt;/p&gt;
&lt;h3&gt;Gate 5: the stripped-down loader&lt;/h3&gt;
&lt;p&gt;A trustlet&apos;s image loader is not the standard NT loader. The Secure Kernel routes trustlet loads through a path the deck names &lt;code&gt;LdrpIsSecureProcess&lt;/code&gt;, which skips an unusually long list of features. Application Verifier hooks: skipped. Image File Execution Options registry checks: skipped. SxS / Fusion DLL redirection: skipped. The CSRSS connection ordinary NT processes establish during startup: skipped (the &lt;code&gt;BASE_STATIC_SERVER_DATA&lt;/code&gt; structure CSRSS would normally hand back is fabricated locally on the trustlet&apos;s heap so dependent calls do not crash). Safer, AuthZ, Software Restriction Policies: all skipped. Any DLL load triggered from VTL0: refused.&lt;/p&gt;
&lt;p&gt;The result is a loader path with no attack surface against VTL0 environment variables, no susceptibility to NT&apos;s normal &quot;load this DLL instead&quot; knobs, and no opportunity for the user&apos;s CSRSS process to inject anything into the trustlet&apos;s address space. The system-call surface available inside the trustlet is restricted to roughly fifty allowed entries. Ionescu&apos;s deck states the count verbatim: &lt;em&gt;&quot;Only 48 system calls are currently allowed from IUM Trustlets&quot;&lt;/em&gt; [@ionescu-bh2015].&lt;/p&gt;

sequenceDiagram
    participant Caller as Caller (VTL1 or brokered VTL0)
    participant NT as NtCreateUserProcess
    participant CI as ci.dll (CipMincryptToSigningLevel)
    participant SK as Secure Kernel (SkpspFindPolicy)
    participant Ldr as LdrpIsSecureProcess
    participant Iset as IumSetTrustletInstance
    Caller-&amp;gt;&amp;gt;NT: Create with PsAttributeSecureProcess + Trustlet ID
    NT-&amp;gt;&amp;gt;CI: Verify EKUs System Component plus IUM and Signing Level ge 12
    CI--&amp;gt;&amp;gt;NT: Pass or fail
    NT-&amp;gt;&amp;gt;SK: Parse .tpolicy, validate s_IumPolicyMetadata
    SK--&amp;gt;&amp;gt;NT: Pass or fail
    NT-&amp;gt;&amp;gt;Ldr: Strip down loader and deny VTL0-triggered DLL loads
    Ldr--&amp;gt;&amp;gt;NT: Image mapped under IUM rules
    NT-&amp;gt;&amp;gt;Iset: Bind Trustlet Instance GUID
    Iset--&amp;gt;&amp;gt;NT: Trustlet alive in VTL1
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate&lt;/th&gt;
&lt;th&gt;What it checks&lt;/th&gt;
&lt;th&gt;Where it lives&lt;/th&gt;
&lt;th&gt;Failure outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1. Process attribute&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PsAttributeSecureProcess&lt;/code&gt; with 64-bit Trustlet ID, requested via &lt;code&gt;NtCreateUserProcess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NT kernel boot path&lt;/td&gt;
&lt;td&gt;Normal NT process; no IUM bit ever set [@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. EKUs + Signing Level&lt;/td&gt;
&lt;td&gt;Windows System Component EKU (&lt;code&gt;1.3.6.1.4.1.311.10.3.6&lt;/code&gt;) AND IUM EKU (&lt;code&gt;1.3.6.1.4.1.311.10.3.37&lt;/code&gt;); Signing Level &amp;gt;= 12&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ci.dll&lt;/code&gt; integrity check, &lt;code&gt;CipMincryptToSigningLevel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load refused; no trustlet [@ionescu-ppp3] [@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. &lt;code&gt;.tpolicy&lt;/code&gt; + &lt;code&gt;s_IumPolicyMetadata&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PE section with version 1, matching Trustlet ID, and per-trustlet policy entries&lt;/td&gt;
&lt;td&gt;Secure Kernel &lt;code&gt;SkpspFindPolicy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Load refused; no trustlet [@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Trustlet Instance GUID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IumSetTrustletInstance&lt;/code&gt; secure-call ordinal &lt;code&gt;0x80000001&lt;/code&gt;; per-partition scoping for vTPM&lt;/td&gt;
&lt;td&gt;Secure Kernel runtime&lt;/td&gt;
&lt;td&gt;Process exists but cannot bind to per-instance secret storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Loader strip-down&lt;/td&gt;
&lt;td&gt;Skip Application Verifier, IFEO, SxS, CSRSS, Safer, AuthZ, SRP; deny VTL0-triggered DLL loads&lt;/td&gt;
&lt;td&gt;NT &lt;code&gt;LdrpIsSecureProcess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Normal NT loader runs; image loads but is not isolated&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The pseudocode below walks each gate in order against a fake binary descriptor. It is not a loader, it is not an exploit, and it is not a security tool. It is a teaching aid: if you can read it, you can read the trustlet load path.&lt;/p&gt;
&lt;p&gt;{`
// Trustlet load-time gate check (educational pseudocode).
// Inspired by Ionescu BH2015 reverse-engineering of Win10 RTM (2015).
// Not a real loader; not a security tool.&lt;/p&gt;
&lt;p&gt;const WINDOWS_SYSTEM_COMPONENT_EKU = &quot;1.3.6.1.4.1.311.10.3.6&quot;;
const IUM_EKU                      = &quot;1.3.6.1.4.1.311.10.3.37&quot;;
const MIN_SIGNING_LEVEL            = 12; // &quot;Windows&quot;&lt;/p&gt;
&lt;p&gt;function loadTrustlet(bin) {
  // Gate 1: process attribute
  if (!bin.attr || !bin.attr.PsAttributeSecureProcess) {
    return &quot;fail at gate 1: no PsAttributeSecureProcess attribute&quot;;
  }
  const requestedId = bin.attr.PsAttributeSecureProcess.trustletId;&lt;/p&gt;
&lt;p&gt;  // Gate 2: two EKUs at Signing Level 12+
  const ekus = (bin.cert &amp;amp;&amp;amp; bin.cert.ekus) || [];
  if (!ekus.includes(WINDOWS_SYSTEM_COMPONENT_EKU)) {
    return &quot;fail at gate 2: missing Windows System Component EKU&quot;;
  }
  if (!ekus.includes(IUM_EKU)) {
    return &quot;fail at gate 2: missing IUM EKU&quot;;
  }
  if ((bin.cert.signingLevel || 0) &amp;lt; MIN_SIGNING_LEVEL) {
    return &quot;fail at gate 2: signing level below 12&quot;;
  }&lt;/p&gt;
&lt;p&gt;  // Gate 3: .tpolicy section with s_IumPolicyMetadata
  const tpol = bin.sections &amp;amp;&amp;amp; bin.sections[&quot;.tpolicy&quot;];
  if (!tpol || !tpol.exports || !tpol.exports.s_IumPolicyMetadata) {
    return &quot;fail at gate 3: no .tpolicy section with s_IumPolicyMetadata&quot;;
  }
  const meta = tpol.exports.s_IumPolicyMetadata;
  if (meta.version !== 1 || meta.trustletId !== requestedId) {
    return &quot;fail at gate 3: malformed or mismatched s_IumPolicyMetadata&quot;;
  }&lt;/p&gt;
&lt;p&gt;  // Gate 4: Trustlet Instance GUID (bound at runtime via IumSetTrustletInstance)
  const instance = bin.runtime &amp;amp;&amp;amp; bin.runtime.instanceGuid;
  if (!instance) {
    return &quot;fail at gate 4: no Trustlet Instance GUID bound&quot;;
  }&lt;/p&gt;
&lt;p&gt;  // Gate 5: stripped-down loader (skip Application Verifier, IFEO, SxS, CSRSS,
  // Safer, AuthZ, SRP; deny VTL0-triggered DLL loads).
  // We don&apos;t simulate the loader here; we just refuse VTL0-injected DLL loads.
  if (bin.loaderTriggers &amp;amp;&amp;amp; bin.loaderTriggers.fromVtl0) {
    return &quot;fail at gate 5: VTL0-triggered DLL load denied&quot;;
  }&lt;/p&gt;
&lt;p&gt;  return &quot;trustlet loaded: id=&quot; + requestedId
       + &quot; instance=&quot; + instance;
}&lt;/p&gt;
&lt;p&gt;// Smoke test.
const sample = {
  attr:    { PsAttributeSecureProcess: { trustletId: 1 } },
  cert:    { ekus: [
    &quot;1.3.6.1.4.1.311.10.3.6&quot;,
    &quot;1.3.6.1.4.1.311.10.3.37&quot;,
  ], signingLevel: 12 },
  sections: { &quot;.tpolicy&quot;: { exports: {
    s_IumPolicyMetadata: { version: 1, trustletId: 1 },
  } } },
  runtime: { instanceGuid: &quot;&quot; },
  loaderTriggers: { fromVtl0: false },
};
console.log(loadTrustlet(sample));
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A trustlet is what passes all five gates. There is no other definition. Status is mechanical, not categorical: it is what the Secure Kernel&apos;s load path produces when a properly signed binary with a properly formed &lt;code&gt;.tpolicy&lt;/code&gt; section calls &lt;code&gt;NtCreateUserProcess&lt;/code&gt; with a proper secure-process attribute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All five gates pass. The binary is now a trustlet. It is running in VTL1 user mode. The hypervisor refuses to map its pages into VTL0. Now what does it do? Who does it talk to?&lt;/p&gt;
&lt;h2&gt;6. The Inbox Roster&lt;/h2&gt;
&lt;p&gt;Five gates. Pass them all and you become a trustlet. Microsoft passes them on behalf of -- as of mid-2026 -- this list.&lt;/p&gt;
&lt;h3&gt;The agent / trustlet pattern&lt;/h3&gt;
&lt;p&gt;Before the roster, the pattern. Almost every shipping trustlet has a partner: an agent process in VTL0 that does the high-volume work of integrating with the rest of the operating system, and the trustlet itself in VTL1 holding the secret material. The two talk over an Asynchronous Local Procedure Call port whose server end is hosted by the trustlet.&lt;/p&gt;

A Windows inter-process communication primitive optimised for fast, fixed-size message exchange between processes on the same machine. The NT kernel hosts ALPC ports as named kernel objects (e.g., `\RPC Control\LSA_ISO_RPC_SERVER`); clients open a port and exchange messages with the server. For trustlets, the ALPC server runs inside the trustlet in VTL1; clients in VTL0 send requests, the Secure Kernel marshals the request across the VTL boundary, and the trustlet returns a result back to VTL0. The hash never leaves VTL1; the request and response do.

flowchart LR
    NetClient[Network or local client]
    Agent[&quot;lsass.exe (VTL0 agent)&lt;br /&gt;protocol parsing&lt;br /&gt;session state&lt;br /&gt;network I/O&quot;]
    SK[&quot;Secure Kernel&lt;br /&gt;(VTL1 ring 0)&lt;br /&gt;marshals secure calls&quot;]
    Trustlet[&quot;LsaIso.exe (VTL1 trustlet)&lt;br /&gt;NTLM hashes&lt;br /&gt;Kerberos TGTs&lt;br /&gt;EncryptData / DecryptData&quot;]
    NetClient --&amp;gt;|&quot;network protocol&quot;| Agent
    Agent --&amp;gt;|&quot;ALPC: LSA_ISO_RPC_SERVER&quot;| SK
    SK --&amp;gt;|&quot;IUM Base API&quot;| Trustlet
    Trustlet --&amp;gt;|&quot;opaque blob&quot;| SK
    SK --&amp;gt; Agent
&lt;p&gt;The roster below names the agent for each trustlet where Microsoft has published one. Where the agent is not publicly named, the row says so.&lt;/p&gt;
&lt;h3&gt;Trustlet ID 0 -- the Secure Kernel Process&lt;/h3&gt;
&lt;p&gt;The first inhabitant of VTL1 user mode. Hosts Device Guard and Hypervisor-protected Code Integrity policy decisions. Architecturally close to a daemon: it does not service external clients; it provides services the Secure Kernel itself relies on for policy decisions about whether a given image is permitted to load in VTL0 [@ionescu-bh2015].&lt;/p&gt;
&lt;h3&gt;Trustlet ID 1 -- &lt;code&gt;LsaIso.exe&lt;/code&gt; (Credential Guard)&lt;/h3&gt;
&lt;p&gt;The canonical trustlet. Holds NTLM hashes and Kerberos Ticket-Granting Tickets. Its agent in VTL0 is &lt;code&gt;lsass.exe&lt;/code&gt;, the Local Security Authority Subsystem Service that has held those secrets directly for every version of Windows NT until 2015. The ALPC port name is &lt;code&gt;LSA_ISO_RPC_SERVER&lt;/code&gt;. The IUM-side API the trustlet exposes is narrow: &lt;code&gt;EncryptData&lt;/code&gt; and &lt;code&gt;DecryptData&lt;/code&gt; on opaque blobs, plus a handful of internal management operations [@msdocs-credential-guard].&lt;/p&gt;
&lt;p&gt;The Microsoft Learn explanation is the verbatim public account:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With Credential Guard enabled, the LSA process in the operating system talks to a component called the isolated LSA process that stores and protects those secrets, LSAIso.exe. Data stored by the isolated LSA process is protected using VBS and isn&apos;t accessible to the rest of the operating system. LSA uses remote procedure calls to communicate with the isolated LSA process [@msdocs-credential-guard].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A VTL0 caller -- including SYSTEM-in-the-NT-kernel -- can ask the trustlet to encrypt a freshly supplied credential or to authenticate a freshly received challenge. It cannot ask the trustlet to expose the underlying NTLM hash. The hash never leaves VTL1. That is the entire point.&lt;/p&gt;
&lt;h3&gt;Trustlet ID 2 -- &lt;code&gt;vmsp.exe&lt;/code&gt; (Hyper-V vTPM, host side)&lt;/h3&gt;
&lt;p&gt;The Hyper-V &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;Virtual Trusted Platform Module&lt;/a&gt; on the host side. One &lt;code&gt;vmsp.exe&lt;/code&gt; instance per guest partition; the agent is &lt;code&gt;vmwp.exe&lt;/code&gt;, the Hyper-V Virtual Machine Worker Process for that partition. The Instance GUID is the partition&apos;s GUID, so that the keys a partition&apos;s vTPM holds are scoped to that partition and that partition only. Storage primitives include a Mailbox primitive (protected by a per-instance Security Cookie) and a Secure Storage primitive that produces Ingress and Egress blobs encrypted with per-Instance IDK material [@ionescu-bh2015] [@msdocs-guarded-fabric].&lt;/p&gt;
&lt;p&gt;Shielded VMs on Windows Server 2016 and later consume &lt;code&gt;vmsp.exe&lt;/code&gt;. A shielded VM, per Microsoft Learn, &lt;em&gt;&quot;has a virtual TPM, is encrypted using BitLocker, and can run only on healthy and approved hosts in the fabric&quot;&lt;/em&gt; [@msdocs-guarded-fabric]. The vTPM keys live in the host&apos;s &lt;code&gt;vmsp.exe&lt;/code&gt; trustlet; the &lt;a href=&quot;https://paragmali.com/blog/bitlocker-on-windows-architecture-attacks-and-the-limits-of-&quot; rel=&quot;noopener&quot;&gt;BitLocker volume master key&lt;/a&gt; in the guest is sealed against that vTPM; and a SYSTEM-privilege NT-kernel write primitive on the host cannot read the partition&apos;s vTPM secrets even though the host can otherwise reach the partition&apos;s memory.&lt;/p&gt;
&lt;h3&gt;Trustlet ID 3 -- vTPM provisioning trustlet&lt;/h3&gt;
&lt;p&gt;Pushes initial secrets into a partition&apos;s Instance GUID at vTPM creation time. The Secure Kernel&apos;s &lt;code&gt;SkCapabilities&lt;/code&gt; array hardcodes &lt;code&gt;CheckByTrustletId 2&lt;/code&gt; for &lt;code&gt;SecureStorageGet&lt;/code&gt; and &lt;code&gt;CheckByTrustletId 3&lt;/code&gt; for &lt;code&gt;SecureStorageSet&lt;/code&gt;; those are the only Trustlet-ID-checked secure-storage operations in the 2015-era IUM secure-call surface [@ionescu-bh2015]. The pair of trustlets cooperates on the same Instance GUID so the provisioning trustlet writes and &lt;code&gt;vmsp.exe&lt;/code&gt; reads, with the Secure Kernel enforcing that no other trustlet can do either.&lt;/p&gt;
&lt;h3&gt;Enhanced Sign-in Security (ESS) biometric matching component (Windows 11+)&lt;/h3&gt;
&lt;p&gt;Microsoft Learn documents the architectural placement of Windows Hello&apos;s facial-recognition algorithm verbatim:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When ESS is enabled, the face algorithm is protected using VBS to isolate it from the rest of Windows. The hypervisor is used to specify and protect memory regions, so that they can only be accessed by processes running in VBS. The hypervisor allows the face camera to write to these memory regions providing an isolated pathway... Sensors that support ESS have a certificate embedded during manufacturing [@msdocs-ess].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The page also documents the certificate chain that authenticates the camera to the matcher and the match-on-sensor requirement for fingerprint readers under ESS. Microsoft does &lt;em&gt;not&lt;/em&gt; publicly name the binary that hosts the face algorithm, and it does not publicly assign that binary a Trustlet ID. The architectural placement is a trustlet. The naming is not on the record.&lt;/p&gt;
&lt;h3&gt;Administrator Protection / Adminless issuer (Windows 11, rolling out 2025-26)&lt;/h3&gt;
&lt;p&gt;In October 2025 Microsoft shipped a preview of Administrator Protection in KB5067036 [@kb5067036] and reverted the rollout in the same update note [@msdocs-admin-protection]. The Microsoft Learn page describes the security model:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once authorized, Windows uses a hidden, system-generated, profile-separated user account to create an isolated admin token. This token is issued to the requesting process and is destroyed once the process ends, ensuring that admin privileges don&apos;t persist. Administrator protection introduces a new security boundary with support to fix any reported security bugs [@msdocs-admin-protection].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The implementation surface that issues those tokens is not publicly named. The architectural family resemblance to a trustlet is strong, and the &quot;new security boundary with support to fix any reported security bugs&quot; line is the formal commitment Microsoft makes for VBS-isolated components. Whether the issuer is a trustlet, a VBS Enclave, or a separately isolated VTL0 process is, as of mid-2026, not on the public record.&lt;/p&gt;
&lt;h3&gt;Third-party VBS Enclaves (Windows 11 24H2 and later)&lt;/h3&gt;
&lt;p&gt;For the first time since 2015, the trustlet primitive is exposed to third-party developers. A VBS Enclave is a DLL signed with a Trusted Signing certificate and loaded into a VTL1 enclave region of a host process via &lt;code&gt;CreateEnclave&lt;/code&gt; and &lt;code&gt;CallEnclave&lt;/code&gt;. The OS support is narrow:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows 11 Build 26100.2314 or later... Windows Server 2025 or later... Visual Studio 2022 version 17.9 or later... The Windows Software Development Kit (SDK) version 10.0.22621.3233 or later, which provides veiid.exe (the VBS Enclave import ID binding utility) and signtool.exe... A Trusted Signing account [@msdocs-vbs-enclaves].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Azure SQL&apos;s &quot;Always Encrypted with secure enclaves&quot; is the public flagship consumer. The architectural difference from an inbox trustlet is the API surface and the enclave-versus-process model: a VBS Enclave is a region inside an existing process&apos;s address space, not a separately scheduled process. The threat model is identical: the host (the rest of the process, including its VTL0 code) is the attacker, the enclave is the defender [@pulapaka-vbs-enclaves].&lt;/p&gt;
&lt;h3&gt;Roster table&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trustlet ID&lt;/th&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;th&gt;VTL0 agent&lt;/th&gt;
&lt;th&gt;ALPC endpoint&lt;/th&gt;
&lt;th&gt;Secret / operation&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;0&lt;/td&gt;
&lt;td&gt;Secure Kernel Process&lt;/td&gt;
&lt;td&gt;(internal; no external agent)&lt;/td&gt;
&lt;td&gt;(internal)&lt;/td&gt;
&lt;td&gt;Device Guard / HVCI policy decisions&lt;/td&gt;
&lt;td&gt;[@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LsaIso.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lsass.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;LSA_ISO_RPC_SERVER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NTLM hashes, Kerberos TGTs; &lt;code&gt;EncryptData&lt;/code&gt; / &lt;code&gt;DecryptData&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[@msdocs-credential-guard] [@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmsp.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmwp.exe&lt;/code&gt; (per partition)&lt;/td&gt;
&lt;td&gt;per-instance, partition GUID scoped&lt;/td&gt;
&lt;td&gt;Hyper-V vTPM, host side; secure storage &lt;code&gt;Get&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[@ionescu-bh2015] [@msdocs-guarded-fabric]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;vTPM provisioning trustlet&lt;/td&gt;
&lt;td&gt;(Hyper-V provisioning agent)&lt;/td&gt;
&lt;td&gt;per-instance, partition GUID scoped&lt;/td&gt;
&lt;td&gt;Initial secret provisioning; secure storage &lt;code&gt;Set&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;[@ionescu-bh2015]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(unpublished)&lt;/td&gt;
&lt;td&gt;ESS face-algorithm component&lt;/td&gt;
&lt;td&gt;Hello biometric pipeline; sensor-issued cert auth&lt;/td&gt;
&lt;td&gt;not publicly named&lt;/td&gt;
&lt;td&gt;Face template matching (fingerprint matching under ESS is match-on-sensor)&lt;/td&gt;
&lt;td&gt;[@msdocs-ess]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(unpublished)&lt;/td&gt;
&lt;td&gt;Administrator Protection issuer&lt;/td&gt;
&lt;td&gt;UAC / Authorization Manager broker&lt;/td&gt;
&lt;td&gt;not publicly named&lt;/td&gt;
&lt;td&gt;Just-in-time admin token issuance&lt;/td&gt;
&lt;td&gt;[@msdocs-admin-protection]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(third-party)&lt;/td&gt;
&lt;td&gt;VBS Enclave DLL&lt;/td&gt;
&lt;td&gt;host process (&lt;code&gt;CreateEnclave&lt;/code&gt; caller)&lt;/td&gt;
&lt;td&gt;direct calls via &lt;code&gt;CallEnclave&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application-defined; e.g., Azure SQL Always Encrypted&lt;/td&gt;
&lt;td&gt;[@msdocs-vbs-enclaves] [@pulapaka-vbs-enclaves]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The published authoritative trustlet list still stops at Trustlet IDs 0-3 from August 2015. Every roster published after that point has been inferred from secondary evidence: kernel symbols, ALPC port enumeration via &lt;code&gt;NtQuerySystemInformation&lt;/code&gt;, documented architectural placements. Microsoft has not republished an authoritative roster for any later Windows release.&lt;/p&gt;

Two trustlets in the list above are *architecturally* trustlets per Microsoft&apos;s published documentation but have not been publicly named or numbered. The ESS face-algorithm matcher is documented to live in VBS-isolated memory, with sensor-certificate authentication and template-encryption keys held in VBS, but the binary&apos;s name and Trustlet ID are not on the public record [@msdocs-ess]. The Administrator Protection token issuer&apos;s implementation surface is even less precisely specified -- &quot;a hidden, system-generated, profile-separated user account&quot; inside &quot;a new security boundary,&quot; but no commitment to whether the issuer is a trustlet, a VBS Enclave, or a separate isolated process [@msdocs-admin-protection]. This article will not invent names or numbers for either. Empirical enumeration via `NtQuerySystemInformation(SystemIsolatedUserModeInformation)` on a current Windows 11 build is the only way to obtain a current roster, and that route is outside the scope of this piece.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Credential Guard prevents the &lt;em&gt;memory-resident&lt;/em&gt; NTLM hash or Kerberos TGT from being read out of VTL0. It does not protect typed-in credentials, the agent-side relay surface, plaintext-secret protocols (CredSSP / NTLMv1 / MS-CHAPv2 / Digest), or liveness; the full four-item enumeration with citations lives in Section 10. Microsoft documents one corner of the limit verbatim: Credential Guard &lt;em&gt;&quot;doesn&apos;t prevent an attacker with malware on the PC from using the privileges associated with any credential&quot;&lt;/em&gt; [@msdocs-credential-guard].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The published roster stops at Trustlet IDs 0-3 from 2015. The actual roster on a 2026 box is bigger. How much bigger Microsoft hasn&apos;t said. That is one of the open problems Section 9 will pick up.&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches&lt;/h2&gt;
&lt;p&gt;Microsoft is not alone. The same threat model -- &quot;protect user-mode code from a compromised OS kernel&quot; -- has been answered six other ways. None is strictly better than a trustlet. None is strictly worse. The right answer depends on what platform you are on, what threat model you have, and what workload you are trying to protect.&lt;/p&gt;

A hardware-enforced or hypervisor-enforced execution context whose memory and state are inaccessible to the surrounding host operating system, including its kernel. The Open Mobile Terminal Platform (OMTP) first defined the term, and GlobalPlatform now publishes the standard APIs (TEE Client API for the host, TEE Internal Core API for the trusted code). Windows trustlets, Intel SGX enclaves, ARM TrustZone Trusted Applications, AMD SEV-SNP confidential VMs, Apple&apos;s Secure Enclave, and seL4 user-mode security servers are all variants of TEE [@wiki-tee].
&lt;h3&gt;Intel SGX&lt;/h3&gt;
&lt;p&gt;Software Guard Extensions launched with the sixth-generation Intel Core processors (Skylake) in 2015 [@wiki-sgx]. SGX adds two CPU instructions with different privilege requirements: &lt;code&gt;ENCLS&lt;/code&gt; (ring 0; the OS issues leaves like &lt;code&gt;ECREATE&lt;/code&gt; on behalf of a user-mode application) and &lt;code&gt;ENCLU&lt;/code&gt; (ring 3; the application issues leaves like &lt;code&gt;EENTER&lt;/code&gt; and &lt;code&gt;EEXIT&lt;/code&gt; to enter and leave its enclave) [@intel-sdm-sgx]. The result is a user-mode-controllable enclave whose memory is encrypted on the way out of the CPU&apos;s Enclave Page Cache to DRAM. The CPU microcode itself, plus the Quoting Enclave, is the TCB. Neither the OS kernel nor the hypervisor sits in the trust path.&lt;/p&gt;
&lt;p&gt;That sounded ideal in 2015. It has not aged well. Foreshadow (USENIX Security 2018, Van Bulck et al.) demonstrated that transient-execution attacks could extract not only enclave memory but the platform&apos;s attestation key [@foreshadow-usenix]. The Foreshadow team&apos;s site states the consequence:&lt;/p&gt;

Foreshadow demonstrates how speculative execution can be exploited for reading the contents of SGX-protected memory as well as extracting the machine&apos;s private attestation key... due to SGX&apos;s privacy features, an attestation report cannot be linked to the identity of its signer. Thus, it only takes a single compromised SGX machine to erode trust in the entire SGX system. -- Foreshadow project site [@foreshadow-attack-eu]
&lt;p&gt;SGAxe (attestation-key extraction) [@sgaxe], Plundervolt (software-controlled undervolting to fault SGX computations) [@plundervolt], SgxPectre (branch-target injection across the enclave boundary) [@sgxpectre], and others followed. Intel deprecated SGX on 11th-generation Core and later client CPUs, which incidentally removed Ultra HD Blu-ray playback on officially licensed software including PowerDVD [@wiki-sgx]. SGX continues on Xeon for confidential cloud workloads but is no longer a target architects pick on Windows clients.The Ultra HD Blu-ray collapse is the closest the SGX deprecation has come to mainstream visibility. PowerDVD&apos;s SGX dependency meant that a client SGX deprecation broke a consumer product line, and Cyberlink had to ship updates rerouting around the dropped CPU feature.&lt;/p&gt;
&lt;h3&gt;AMD SEV-SNP and Intel TDX&lt;/h3&gt;
&lt;p&gt;AMD&apos;s Secure Encrypted Virtualization with Secure Nested Paging (SEV-SNP), introduced on EPYC 7003 (Milan, launched 15 March 2021) [@wiki-amd-epyc], and Intel&apos;s Trust Domain Extensions (TDX), introduced on 4th-generation Xeon Scalable (Sapphire Rapids, launched 10 January 2023) [@wiki-sapphire-rapids], provide &lt;em&gt;whole-VM&lt;/em&gt; confidential computing [@amd-sev-overview] [@intel-tdx-overview]. AMD&apos;s verbatim claim: &lt;em&gt;&quot;SEV-SNP adds strong memory integrity protection to help prevent malicious hypervisor-based attacks like data replay, memory re-mapping, and more to create an isolated execution environment&quot;&lt;/em&gt; [@amd-sev-overview]. Intel&apos;s verbatim claim about TDX: &lt;em&gt;&quot;A CPU-measured Intel TDX module enables Intel TDX. This software module runs in a new CPU Secure Arbitration Mode (SEAM) as a peer virtual machine manager (VMM)&quot;&lt;/em&gt; [@intel-tdx-overview]. The AMD SEV-SNP whitepaper &quot;Strengthening VM Isolation with Integrity Protection and More&quot; is the canonical technical reference [@amd-sev-snp-whitepaper].&lt;/p&gt;
&lt;p&gt;The granularity is different from a trustlet. SEV-SNP and TDX isolate an entire virtual machine from its hypervisor and host. They do not isolate a process from its own VM&apos;s kernel. For &quot;this user-mode process should be protected from a SYSTEM kernel write primitive on the same OS,&quot; a trustlet is the primitive; for &quot;this entire VM should be protected from a compromised cloud provider,&quot; a CVM is the primitive. Use the right one.&lt;/p&gt;
&lt;h3&gt;ARM TrustZone and OP-TEE&lt;/h3&gt;
&lt;p&gt;The two-world hardware split that has shipped on every Cortex-A processor since the mid-2000s -- the Wikipedia ARM architecture article states verbatim that &lt;em&gt;&quot;the Security Extensions, marketed as TrustZone Technology, is in ARMv6KZ and later application profile architectures,&quot;&lt;/em&gt; the lineage every Cortex-A core inherits [@wiki-arm-architecture]. The CPU enforces a Non-Secure World and a Secure World; switching between the two is mediated by a Secure Monitor Call (&lt;code&gt;SMC&lt;/code&gt;) instruction. OP-TEE is the canonical open-source secure-world OS for Cortex-A TrustZone, with Trusted Applications running as user-mode binaries in Secure World EL-0 and the OP-TEE OS itself running at EL-1 [@optee-about]. The OP-TEE about page describes the design: &lt;em&gt;&quot;OP-TEE is a Trusted Execution Environment (TEE) designed as companion to a non-secure Linux kernel running on Arm; Cortex-A cores using the TrustZone technology&quot;&lt;/em&gt; [@optee-about].&lt;/p&gt;
&lt;p&gt;TrustZone is the closest non-Windows analogue to a trustlet at the architectural level. The vocabulary maps one for one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Windows VBS / IUM&lt;/th&gt;
&lt;th&gt;ARM TrustZone / OP-TEE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Isolation primitive&lt;/td&gt;
&lt;td&gt;Hyper-V hypervisor + SLAT&lt;/td&gt;
&lt;td&gt;TrustZone Address Space Controller; CPU NS/S bit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secure-side kernel&lt;/td&gt;
&lt;td&gt;Secure Kernel (VTL1 ring 0)&lt;/td&gt;
&lt;td&gt;OP-TEE OS (Secure World EL-1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secure-side user mode&lt;/td&gt;
&lt;td&gt;IUM (VTL1 ring 3)&lt;/td&gt;
&lt;td&gt;Trusted Applications (Secure World EL-0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent / supplicant&lt;/td&gt;
&lt;td&gt;The trustlet&apos;s VTL0 agent (e.g., &lt;code&gt;lsass.exe&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tee-supplicant&lt;/code&gt; and TEE Client API on the Linux side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trust gate&lt;/td&gt;
&lt;td&gt;Microsoft EKUs + Signature Level 12&lt;/td&gt;
&lt;td&gt;OP-TEE TA signing key configured at build time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Apple Secure Enclave Processor (SEP)&lt;/h3&gt;
&lt;p&gt;Apple&apos;s answer is a dedicated on-die security subsystem. SEP is a separate processor core, isolated from the Application Processor on the same SoC, with its own boot ROM, its own AES engine, and its own random number generator. It has been in every iPhone since iPhone 5s (2013), every Apple Silicon Mac, every Apple Watch from Series 1 [@apple-sep]. Apple&apos;s verbatim description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Secure Enclave Processor runs an Apple-customized version of the L4 microkernel. It&apos;s designed to operate efficiently at a lower clock speed that helps to protect it against clock and power attacks [@apple-sep].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SEP is the strongest counter to microarchitectural side channels among the production options, because the cores genuinely do not share microarchitectural state with the Application Processor. The price is that everything is firmware-class: patching a SEP bug means rolling SEP firmware on every Apple device, not pushing an OS update. The cycle is slower and more centralised.&lt;/p&gt;
&lt;h3&gt;seL4 plus user-mode security servers&lt;/h3&gt;
&lt;p&gt;The academic conscience of the lineage. About 8,700 lines of formally verified C, with machine-checked proofs of functional correctness, confidentiality, and integrity [@sel4-sosp-paper] [@sel4-about]. Sub-microsecond IPC. The price is that seL4 is a separation microkernel, not a desktop OS; building a Credential-Guard-equivalent on seL4 means designing the application architecture from the microkernel up, not retrofitting it onto a Windows-compatible stack. seL4 has shipping deployments in defence (the DARPA HACMS programme), automotive ECUs, and Qualcomm&apos;s Hexagon DSP secure OS.&lt;/p&gt;
&lt;h3&gt;When to pick which&lt;/h3&gt;
&lt;p&gt;A decision table of the kind a colleague would actually use.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Protect a user-mode Windows process from a SYSTEM kernel write primitive&lt;/td&gt;
&lt;td&gt;Trustlet (inbox) or VBS Enclave (third-party) [@msdocs-vbs-enclaves]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protect an entire VM from your cloud provider&apos;s host&lt;/td&gt;
&lt;td&gt;AMD SEV-SNP or Intel TDX [@amd-sev-overview] [@intel-tdx-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protect a user-mode Linux-on-ARM service from a compromised Linux kernel&lt;/td&gt;
&lt;td&gt;TrustZone + OP-TEE Trusted Application [@optee-about]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hold an iPhone owner&apos;s Touch ID / Face ID template safely from iOS&lt;/td&gt;
&lt;td&gt;Apple SEP [@apple-sep]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build a high-assurance system with a machine-checked proof of kernel correctness&lt;/td&gt;
&lt;td&gt;seL4 [@sel4-sosp-paper]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run Intel SGX enclaves on Xeon for confidential cloud&lt;/td&gt;
&lt;td&gt;SGX (modulo Foreshadow-class side channels) [@foreshadow-attack-eu]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Trustlets are the right answer for Windows. They are not the right answer for every platform, every threat model, or every workload. They are also not without limits &lt;em&gt;on Windows itself&lt;/em&gt;. What are those?&lt;/p&gt;
&lt;h2&gt;8. The Floor of the Threat Model&lt;/h2&gt;
&lt;p&gt;By 2020 the trustlet model had been shipping for five years. Two researchers at the Microsoft Security Response Center, Saar Amar and Daniel King, pointed a fuzzer at the secure-call interface for two weeks and reported back with five VTL0-to-VTL1 bugs [@amar-bh2020]. Their Black Hat USA 2020 talk, &quot;Breaking VSM by Attacking Secure Kernel,&quot; is the most important public document on what the trustlet model actually guarantees and what it does not [@amar-publications].&lt;/p&gt;
&lt;p&gt;The talk is honest in a way Microsoft is rarely honest about its own products. The slides enumerate the bugs by CVE number, name the specific Secure Kernel routines they exploited, and -- unusually -- list the hardening changes Microsoft shipped because of what was found. Reading the deck is the closest thing to a Q-and-A with the Secure Kernel team.&lt;/p&gt;
&lt;h3&gt;Bug class 1: the secure-call interface is the floor&lt;/h3&gt;
&lt;p&gt;The Secure Kernel exposes about three dozen &quot;secure services&quot; callable from VTL0 via the &lt;code&gt;IumInvokeSecureService&lt;/code&gt; dispatcher. Each takes a parameter block from VTL0, parses it inside VTL1, and returns. That dispatcher is, by definition, the largest VTL0-controllable input surface in the model. Amar and King retargeted the Hyperseed hypercall fuzzer, originally written by Daniel King and Shawn Denbow for hypercall fuzzing, at &lt;code&gt;securekernel!IumInvokeSecureService&lt;/code&gt; [@amar-bh2020]. Two weeks of fuzzing produced five bugs.&lt;/p&gt;
&lt;p&gt;Two of them shipped with public CVE numbers in 2020. CVE-2020-0917 is an out-of-bounds read in the secure-call surface; CVE-2020-0918 is a design flaw in &lt;code&gt;SkmmUnmapMdl&lt;/code&gt; where a VTL0 caller could pass a fully attacker-controlled Memory Descriptor List to &lt;code&gt;SkmiReleaseUnknownPTEs&lt;/code&gt; [@nvd-cve-2020-0917] [@nvd-cve-2020-0918] [@amar-bh2020]. The NVD entries describe both with the same boilerplate (&quot;Windows Hyper-V Elevation of Privilege Vulnerability&quot;) and classify the CWE as &quot;Insufficient Information&quot;; the technical detail lives in the Amar/King deck.&lt;/p&gt;
&lt;p&gt;Microsoft hardened in response. The Amar/King deck enumerates what changed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Secure Kernel pool moved to segment heap in mid-2019, breaking the heap layout the public exploit depended on.&lt;/li&gt;
&lt;li&gt;Four W+X regions in VTL1 were reduced to +X only, eliminating attacker-controlled code-injection targets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SkpgContext&lt;/code&gt;, a HyperGuard-style control-flow integrity check for the Secure Kernel, was introduced [@amar-bh2020].&lt;/li&gt;
&lt;/ul&gt;

Alex Ionescu&apos;s term for an attacker-controlled trustlet, enabled by a substrate compromise rather than a trustlet bug. If Test Signing is on, or if a production Microsoft signing key leaks, or if Secure Boot can be bypassed, an attacker can sign and load their own &quot;trustlet&quot; that passes the five gates of Section 5 and operates with VTL1 privilege. The trustlet model itself remains intact; the trust roots underneath it are what fail [@ionescu-bh2015].
&lt;h3&gt;Bug class 2: denial of service is not a security boundary&lt;/h3&gt;
&lt;p&gt;Amar&apos;s deck states the rule that excludes liveness from the VBS threat model verbatim:&lt;/p&gt;

VTL0 can DOS VTL1 by design. -- Saar Amar and Daniel King, Black Hat USA 2020 [@amar-bh2020]
&lt;p&gt;The hypervisor schedules VTL1; VTL0 is the agent for almost every communication channel into VTL1; VTL0 can stop talking to VTL1 at any time. None of this is, in Microsoft&apos;s stated model, a security violation. A VTL0 kernel attacker who can prevent Credential Guard from issuing tickets has not stolen any credential; they have, in the language of the threat model, achieved denial of service, which is out of scope. This matters in practice: a defender cannot reason about a trustlet &quot;always being available.&quot; They can only reason about its memory not being readable from VTL0 &lt;em&gt;when it is available&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Bug class 3: the agent RPC surface lives in VTL0&lt;/h3&gt;
&lt;p&gt;The trustlet&apos;s pages are safe even from VTL0 ring 0. The agent process that services the trustlet&apos;s ALPC port is &lt;em&gt;not&lt;/em&gt; safe. The agent is &lt;code&gt;lsass.exe&lt;/code&gt; for Credential Guard, &lt;code&gt;vmwp.exe&lt;/code&gt; for the vTPM, presumably the Hello biometric pipeline for ESS. Every byte of every protocol whose state machine the agent implements is reachable from VTL0. The hash never leaves VTL1; the &lt;em&gt;authentication outcomes&lt;/em&gt; the hash produces can be relayed.&lt;/p&gt;
&lt;p&gt;In December 2022 Oliver Lyak published &quot;Pass-the-Challenge: Defeating Windows Defender Credential Guard&quot; [@lyak-pass-the-challenge]. The technique recovers usable NTLM challenge responses from encrypted credential blobs that &lt;code&gt;LsaIso.exe&lt;/code&gt; returns to &lt;code&gt;lsass.exe&lt;/code&gt; in VTL0:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In this blog post, we present new techniques for recovering the NTLM hash from an encrypted credential protected by Windows Defender Credential Guard. While previous techniques for bypassing Credential Guard focus on attackers targeting new victims who log into a compromised server, these new techniques can also be applied to victims logged on before the server was compromised [@lyak-pass-the-challenge].&lt;/p&gt;
&lt;/blockquote&gt;

A network authentication protocol that uses NTLM works in challenge-response form: the server sends a challenge, the client encrypts it with its NTLM hash, the server (or a domain controller) verifies the response. With Credential Guard, the client&apos;s NTLM hash lives in `LsaIso.exe`; only `LsaIso.exe` can perform the encryption. A VTL0 attacker who can talk to `lsass.exe` can ask `lsass.exe` to ask `LsaIso.exe` to compute an NTLM response for an attacker-supplied challenge. The attacker never sees the hash; they see an authentication response computed with it. Many real-world relay attacks need only the response, not the hash. Lyak&apos;s writeup is the worked example; the architectural fact is that the agent RPC channel is a VTL0 surface even though the hash itself is not.
&lt;p&gt;Microsoft documents one corner of the limit verbatim: Credential Guard &lt;em&gt;&quot;doesn&apos;t prevent an attacker with malware on the PC from using the privileges associated with any credential&quot;&lt;/em&gt; [@msdocs-credential-guard]. The &quot;use&quot; is the agent-side operation; the trustlet is doing the cryptography, and the cryptography is being used by the attacker.&lt;/p&gt;
&lt;h3&gt;Bug class 4: trustlet-to-trustlet via shared Instance GUIDs&lt;/h3&gt;
&lt;p&gt;Trustlets that share an Instance GUID can read and write storage blobs the Secure Kernel scopes per-Instance. The pair &lt;code&gt;vmsp.exe&lt;/code&gt; and the vTPM provisioning trustlet uses exactly this primitive: provisioning writes, &lt;code&gt;vmsp.exe&lt;/code&gt; reads, the Secure Kernel hard-codes which Trustlet IDs may invoke &lt;code&gt;SecureStorageSet&lt;/code&gt; versus &lt;code&gt;SecureStorageGet&lt;/code&gt; on each Instance GUID. The defence is in the &lt;code&gt;SkCapabilities&lt;/code&gt; table; bugs in that table are exploit-class.&lt;/p&gt;
&lt;p&gt;In Ionescu&apos;s vocabulary, a &quot;malwarelet&quot; is the worst case here: an attacker-controlled trustlet -- enabled by a &lt;a href=&quot;https://paragmali.com/blog/secure-boot-in-windows-the-chain-from-sector-zero-to-userini&quot; rel=&quot;noopener&quot;&gt;Secure Boot&lt;/a&gt; or Test Signing compromise -- could request access to the Instance GUIDs of other trustlets, and any missing rule in &lt;code&gt;SkCapabilities&lt;/code&gt; would let it read what those trustlets stored. There are no public exploits in this class as of mid-2026. There also is not a published audit of the table.&lt;/p&gt;
&lt;h3&gt;Bug class 5: substrate compromise (Secure Boot, firmware, signing keys)&lt;/h3&gt;
&lt;p&gt;If Test Signing is on; if a production signing key leaks; if Secure Boot can be bypassed to boot a kernel that accepts attacker-controlled trustlet roots; if the UEFI firmware itself permits a DMA attack against early-boot memory -- the entire trustlet model is moot. Ionescu&apos;s BH2015 deck states the diagnosis: &lt;em&gt;&quot;VBS&apos; key weakness is its reliance on Secure Boot&quot;&lt;/em&gt; [@ionescu-bh2015]. Rafal Wojtczuk&apos;s Black Hat USA 2016 attack-surface analysis empirically validated the warning, demonstrating one non-critical VBS-feature bypass and one critical firmware exploit [@wojtczuk-bh2016]. The firmware below VBS is the substrate trustlets sit on; the trustlet model is no stronger than that substrate.&lt;/p&gt;

flowchart TD
    Attacker[&quot;VTL0 kernel attacker&quot;]
    SK[&quot;Secure Kernel&quot;]
    Trustlet[&quot;Trustlet (VTL1 user)&quot;]
    Agent[&quot;VTL0 agent process (lsass.exe, vmwp.exe...)&quot;]
    Substrate[&quot;Substrate: UEFI firmware, Secure Boot, signing roots&quot;]
    Attacker --&amp;gt;|&quot;1. Secure-call interface bugs&lt;br /&gt;CVE-2020-0917, CVE-2020-0918&quot;| SK
    Attacker --&amp;gt;|&quot;2. DoS by design (out of scope)&quot;| SK
    Attacker --&amp;gt;|&quot;3. Agent RPC surface&lt;br /&gt;Pass-the-Challenge&quot;| Agent
    Agent --&amp;gt;|&quot;authentication outcome&quot;| Trustlet
    Attacker --&amp;gt;|&quot;4. Trustlet-to-trustlet&lt;br /&gt;via shared Instance GUID&quot;| Trustlet
    Substrate --&amp;gt;|&quot;5. Substrate compromise&lt;br /&gt;malwarelets, BootHole-class&quot;| SK
    Substrate --&amp;gt; Trustlet
&lt;p&gt;The Hyperseed fuzzer had a prior life. Daniel King and Shawn Denbow first presented it at OffensiveCon 2019 as a hypercall fuzzer [@amar-bh2020]. The retargeting at the secure-call interface is the same tool, pointed at a different parser. The two-weeks-five-bugs result is therefore not &quot;Microsoft wrote bad code&quot; but &quot;a well-built fuzzer aimed at a complex parser will find bugs in ~2 weeks.&quot; That is the empirical bar for an unverified TCB.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The trustlet model is hypervisor-strong against the VTL0 kernel; it is not stronger than the substrate it sits on. Five attack classes -- secure-call interface bugs, designed-out denial-of-service, the agent RPC residual, trustlet-to-trustlet via shared Instance GUIDs, and substrate compromise -- bound what the model can guarantee. None of them invalidates trustlets; all of them are reasons to deploy trustlets &lt;em&gt;alongside&lt;/em&gt; other controls rather than as a sole defence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The trustlet model has a finite, audited attack surface. The surface is not zero. Liveness is not promised. The firmware and Secure Boot underneath everything still matter. What is new on this surface in 2024 to 2026?&lt;/p&gt;
&lt;h2&gt;9. Open Problems&lt;/h2&gt;
&lt;p&gt;Three things you might expect Microsoft to have published by 2026 -- the current inbox trustlet roster, an architecture diagram of Administrator Protection on par with Credential Guard&apos;s, and a public CVE wave around VBS Enclaves -- are still partial or missing. Here is the frontier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Trustlet enumeration drift.&lt;/strong&gt; Ionescu&apos;s August 2015 enumeration of Trustlet IDs 0 through 3 remains the only authoritative published list. Eleven years later, the ESS biometric matcher has not been named with a Trustlet ID and the Administrator Protection issuer has not been committed to as a trustlet at all. A researcher with a debugger and the Quarkslab IUM-debugging recipe can recover the current roster empirically [@quarkslab-debug-ium]; Microsoft has not republished it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. VBS Enclave trust-boundary hardening.&lt;/strong&gt; Microsoft&apos;s Security Response Center published a blog post in June 2025 -- &quot;Everything Old Is New Again&quot; -- explicitly committing to host-to-enclave pointer validation, copy-before-check discipline, and TOCTOU avoidance as the active hardening surface for VBS Enclaves [@ms-everything-old]. The post is unambiguous that a CVE wave is foreseeable as researchers turn their attention to the host-enclave seam. As of the publication of this article no public CVE has been issued against a VBS Enclave-using product, but Microsoft&apos;s narrowing of supported Windows builds in 2025 (from &quot;Windows 11 24H2 or later&quot; to &quot;Windows 11 Build 26100.2314 or later&quot;) is the kind of build-floor adjustment that historically precedes a documented hardening change [@msdocs-vbs-enclaves].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Side channels against VTL1.&lt;/strong&gt; Transient-execution attacks against VTL1 memory have not been publicly demonstrated end to end. The Foreshadow class of attacks against SGX is the existence proof that a co-resident TEE can leak through microarchitectural side channels, and the threat model explicitly includes them [@foreshadow-attack-eu]. There is no VBS-specific transient-execution mitigation; platform-wide mitigations (Kernel Virtual Address Shadow, Retpoline, Indirect Branch Restricted Speculation) are the only defence. A demonstration of &quot;Foreshadow-against-LsaIso&quot; would not be surprising; its absence to date is, given the research community&apos;s interest, mildly so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Debugging asymmetry.&lt;/strong&gt; Researchers have a working trustlet-debugging recipe; defenders have an explicit &quot;no&quot; from Microsoft. The Quarkslab writeup walks through nested virtualisation to attach to a trustlet under controlled conditions [@quarkslab-debug-ium]; Microsoft&apos;s product-facing page states verbatim that &lt;em&gt;&quot;it is not possible to attach to an IUM process&quot;&lt;/em&gt; and that &lt;em&gt;&quot;other APIs, such as CreateRemoteThread, VirtualAllocEx, and Read/WriteProcessMemory will also not work as expected when used against Trustlets&quot;&lt;/em&gt; [@msdocs-ium]. The asymmetry favours offence: an attacker with the time, hardware, and tooling Quarkslab demonstrates can study trustlet internals in ways a defender on a production box cannot. Live-system trustlet introspection for incident response is the missing capability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Administrator Protection transparency.&lt;/strong&gt; As of 10 May 2026, the Administrator Protection feature has been shipped in preview (KB5067036, 28 October 2025), then reverted in the same update note pending a future re-rollout [@kb5067036] [@msdocs-admin-protection]. There is no architecture diagram on the level of Credential Guard&apos;s &quot;how it works&quot; page. There is no published Trustlet ID. There is no public commitment to whether the token issuer is a trustlet, a VBS Enclave, or something else inside the new security boundary. For a feature that materially changes the local-elevation model of Windows, that is unusual reticence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Cross-architecture portability.&lt;/strong&gt; A workload that wants to run as a trustlet on Windows, a Confidential VM on Linux, a Trusted Application on ARM, and a Secure Enclave Application on Apple silicon must, today, be written four times. GlobalPlatform&apos;s TEE Client API standardises one side of TrustZone, the Open Enclave SDK abstracts a subset of SGX and TrustZone, and VBS Enclaves do their own thing. No universal portable TEE API exists. For workloads where portability matters more than peak isolation, this is the open problem with the most direct commercial pressure behind it.&lt;/p&gt;

Two answers, both incomplete. The defensive answer: an enumerated trustlet list is an attacker&apos;s targeting list, and Microsoft prefers not to publish targeting lists for components whose exact attack surface is still under active study. The historical answer: the 2015 list was a side-effect of Ionescu reverse-engineering Windows 10 RTM. There has been no comparable public reverse-engineering push for any post-2015 Windows release at the same level of completeness, and Microsoft has not chosen to fill the gap with first-party documentation. Empirical enumeration via `NtQuerySystemInformation(SystemIsolatedUserModeInformation)` works on a live system, but doing it on every Windows 11 servicing build is a research programme, not a citation.
&lt;p&gt;These are questions a researcher with a year of grant time could move the field on. The next section is the question a practitioner has today.&lt;/p&gt;
&lt;h2&gt;10. Practitioner Guide&lt;/h2&gt;
&lt;p&gt;What changes in a real workflow once you know what a trustlet is? Four short answers.&lt;/p&gt;
&lt;h3&gt;Windows administrator&lt;/h3&gt;
&lt;p&gt;Verify Credential Guard is actually running before you assume it is. Two ways.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;GUI:&lt;/strong&gt; Run &lt;code&gt;msinfo32&lt;/code&gt; and check &lt;em&gt;Virtualization-based security Services Running&lt;/em&gt;. You should see at least &quot;Credential Guard&quot; and ideally &quot;Hypervisor enforced Code Integrity.&quot; &lt;strong&gt;PowerShell:&lt;/strong&gt; &lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard&lt;/code&gt;. The properties &lt;code&gt;SecurityServicesRunning&lt;/code&gt; and &lt;code&gt;VirtualizationBasedSecurityStatus&lt;/code&gt; are the load-bearing ones; values of 1 and 2 respectively indicate Credential Guard is running with VBS in full enforcement [@msdocs-credential-guard].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Enumerating live trustlets on a 2026 box requires more care than enumerating ordinary processes. Process Explorer&apos;s &lt;em&gt;Image&lt;/em&gt; tab carries an IUM marker for trustlet processes. SysInternals Sigcheck on a candidate binary surfaces the Signing Level. The Microsoft Learn IUM page is explicit that &lt;em&gt;&quot;other APIs, such as CreateRemoteThread, VirtualAllocEx, and Read/WriteProcessMemory will also not work as expected when used against Trustlets&quot;&lt;/em&gt; [@msdocs-ium] -- the same APIs many EDR products rely on for behavioural monitoring will silently fail or report sentinel values when targeted at a trustlet. Plan detections accordingly.&lt;/p&gt;
&lt;h3&gt;Security researcher&lt;/h3&gt;
&lt;p&gt;The Quarkslab blog post &quot;Debugging Windows Isolated User Mode (IUM) Processes&quot; is the canonical recipe for attaching to a trustlet under nested virtualisation [@quarkslab-debug-ium]. The empirical enumeration path is &lt;code&gt;NtQuerySystemInformation&lt;/code&gt; with class &lt;code&gt;SystemIsolatedUserModeInformation&lt;/code&gt;; the structure returned includes a count of running trustlets and their identifying metadata.The driver-side pattern Microsoft documents for &quot;is this process a trustlet?&quot; is &lt;code&gt;IsSecureProcess&lt;/code&gt;, an internal Win32K predicate the IUM page names as the canonical check. Tools that need to behave differently against trustlets (memory scanners, integrity checkers, EDR sensors) should call the supported equivalent rather than parsing process attributes by hand [@msdocs-ium].&lt;/p&gt;
&lt;h3&gt;Application developer (VBS Enclaves)&lt;/h3&gt;
&lt;p&gt;If you are writing third-party code that needs trustlet-class isolation, the primitive you target is a VBS Enclave, not a trustlet. The toolchain is specific:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visual Studio 2022 version 17.9 or later.&lt;/li&gt;
&lt;li&gt;Windows SDK version 10.0.22621.3233 or later (provides &lt;code&gt;veiid.exe&lt;/code&gt;, the VBS Enclave import ID binding utility, and &lt;code&gt;signtool.exe&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A Trusted Signing account for production signing [@msdocs-vbs-enclaves].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The architectural rule is &lt;em&gt;never trust the host&lt;/em&gt;. The host process&apos;s address space is reachable by the enclave; the enclave&apos;s address space is not reachable by the host. Range-validate every pointer the host hands the enclave; copy before you check (so the host cannot mutate the data between your check and your use); avoid TOCTOU windows. Microsoft&apos;s &quot;Everything Old Is New Again&quot; post is explicit that this is the hardening surface researchers are looking at right now [@ms-everything-old].&lt;/p&gt;
&lt;p&gt;The development guide includes a sample with a comment that captures the discipline:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every DLL loaded in an enclave requires a configuration. This configuration is defined using a global const variable named __enclave_config of type IMAGE_ENCLAVE_CONFIG... // DO NOT SHIP DEBUGGABLE ENCLAVES TO PRODUCTION [@msdocs-vbs-enclaves-dev-guide].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;IMAGE_ENCLAVE_POLICY_DEBUGGABLE&lt;/code&gt; flag is for development only. The &lt;code&gt;VbsEnclaveTooling&lt;/code&gt; repository on GitHub provides a NuGet package and a code generator that make the cross-VTL marshalling less error-prone, plus reference documentation including &lt;code&gt;Edl.md&lt;/code&gt;, &lt;code&gt;HelloWorldWalkthrough.md&lt;/code&gt;, and &lt;code&gt;CodeGeneration.md&lt;/code&gt; [@vbs-enclave-tooling].&lt;/p&gt;

1. Confirm OS support: Windows 11 Build 26100.2314+ or Windows Server 2025+ [@msdocs-vbs-enclaves].
2. Install Visual Studio 2022 17.9+ and Windows SDK 10.0.22621.3233+.
3. Acquire a Trusted Signing account; configure `signtool.exe` for it.
4. Define `__enclave_config` as `IMAGE_ENCLAVE_CONFIG`; set family/image/SVN fields.
5. Use `veiid.exe` to bind import IDs.
6. Sign the enclave DLL with `signtool.exe` and the Trusted Signing certificate.
7. Test with `IMAGE_ENCLAVE_POLICY_DEBUGGABLE` set; remove it before production.
8. Range-validate every host-supplied pointer; copy before check.
&lt;h3&gt;Defender&lt;/h3&gt;
&lt;p&gt;Know what Credential Guard does &lt;em&gt;not&lt;/em&gt; protect, because that is where most exposure remains.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The trustlet protects memory-resident NTLM hashes and Kerberos TGTs from a VTL0 kernel attacker. It does not protect: - Supplied credentials at the logon prompt (keyloggers, screen-scrapers, hardware shimming). - The agent RPC channel (Pass-the-Challenge-class relay against &lt;code&gt;lsass.exe&lt;/code&gt; is reachable from VTL0) [@lyak-pass-the-challenge]. - Protocols that require a usable secret in plaintext: CredSSP, NTLMv1, MS-CHAPv2, Digest. These are unsupported with the trustlet-protected token by design [@msdocs-credential-guard]. - Liveness: a VTL0 kernel attacker can stop talking to VTL1 and prevent the trustlet from being available. Denial of service is out of the VBS threat model [@amar-bh2020]. The summary: trustlets shrink the credential-theft attack surface, they do not eliminate it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The trustlet model is finite, audited, and useful. Use the lock; do not assume the lock is the only thing on the door.&lt;/p&gt;
&lt;h2&gt;11. Frequently asked questions&lt;/h2&gt;

No. Protected Process Light (PPL) and trustlets sit in the same lineage but differ at the architectural level. A PPL is enforced by the NT kernel, which is also the attacker&apos;s likely foothold; itm4n&apos;s 2021 PPLdump showed the result over eight years of LSASS-as-PPL deployment [@itm4n-runasppl]. A trustlet is enforced by the Hyper-V hypervisor and the Secure Kernel, both running in a different Virtual Trust Level from the NT kernel; a VTL0 kernel write primitive does not touch the trustlet&apos;s pages [@quarkslab-debug-ium]. The signing-level lattice is similar (both rely on Signature Level 12); the enforcement architecture is not.

Not directly. Inbox trustlets require the Microsoft IUM EKU (`1.3.6.1.4.1.311.10.3.37`), which Microsoft does not grant to third parties [@ionescu-bh2015]. Since Windows 11 24H2, the third-party-shippable equivalent is a VBS Enclave: a DLL signed with a Trusted Signing certificate, loaded into an enclave region of a host process via `CreateEnclave` and `CallEnclave`. The architectural threat model is identical (the host is the attacker, the enclave is the defender); the API surface and the enclave-versus-process model differ. VBS Enclaves require Windows 11 Build 26100.2314 or later, Windows SDK 10.0.22621.3233 or later, Visual Studio 2022 17.9 or later, and a Trusted Signing account [@msdocs-vbs-enclaves].

No. It means that the *memory-resident* NTLM hash or Kerberos TGT cannot be read out of `LsaIso.exe` by a VTL0 kernel attacker. It does not mean credentials are unstealable. Section 10 enumerates the four classes of residual exposure -- typed-in credentials, the agent-side RPC relay (Pass-the-Challenge) [@lyak-pass-the-challenge], plaintext-secret protocols (CredSSP / NTLMv1 / MS-CHAPv2 / Digest are unsupported with the trustlet-protected token), and liveness (denial of service against VTL1 is out of the VBS threat model) -- with citations [@msdocs-credential-guard] [@amar-bh2020].

For that trustlet, yes; for the model, by design. The Secure Kernel plus trustlets are the VBS TCB. Amar and King&apos;s 2020 work demonstrated practical VTL0-to-VTL1 vulnerabilities (CVE-2020-0917, CVE-2020-0918) [@amar-bh2020] [@nvd-cve-2020-0917] [@nvd-cve-2020-0918]; Microsoft hardened in response, moving the Secure Kernel pool to segment heap, reducing four W+X regions to +X only, and introducing `SkpgContext` HyperGuard for VTL1 [@amar-bh2020]. The surface remains finite and audited; the trustlet model is hypervisor-strong against the VTL0 kernel and not stronger than the substrate it sits on.

Not on ESS-capable systems. The Microsoft Learn page is clear that *&quot;when ESS is enabled, the face algorithm is protected using VBS to isolate it from the rest of Windows... The hypervisor is used to specify and protect memory regions, so that they can only be accessed by processes running in VBS&quot;* [@msdocs-ess]. The biometric *template* is encrypted with VBS-only keys and lives in VBS-isolated memory. The TPM still has a role -- it holds the per-user Hello *private keys* that authenticate against the local credential provider -- but the biometric template itself does not live in the TPM [@msdocs-tpm].

No. The Microsoft Learn page describes the new model: an authorised user triggers a Windows Hello-backed prompt; Windows then *&quot;uses a hidden, system-generated, profile-separated user account to create an isolated admin token. This token is issued to the requesting process and is destroyed once the process ends&quot;* [@msdocs-admin-protection]. The in-session prompt is still there; the elevated token&apos;s *origin* is what changed (from a split-token impersonation of the same account to a transient system-generated admin account). The October 2025 preview shipped in KB5067036 and was then reverted in the same update note pending a future rollout [@kb5067036]. As of 10 May 2026 the feature is not generally available.
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;vbs-trustlets-what-actually-runs-in-the-secure-kernel&quot; keyTerms={[
  { term: &quot;Trustlet&quot;, definition: &quot;A user-mode process running in VTL1 user mode, scheduled by the Secure Kernel, isolated from VTL0 by per-VTL SLAT permissions. Defined by passing five load-time gates.&quot; },
  { term: &quot;Virtual Trust Level (VTL)&quot;, definition: &quot;A hypervisor-managed privilege axis added on top of x86 rings. Currently two VTLs are implemented out of an architecturally supported sixteen.&quot; },
  { term: &quot;Isolated User Mode (IUM)&quot;, definition: &quot;Ring 3 of VTL1. The user-mode environment trustlets run in. Restricted to about 48 of NT&apos;s ~480 syscalls.&quot; },
  { term: &quot;Secure Kernel&quot;, definition: &quot;The kernel that runs in VTL1 ring 0. Schedules trustlets, parses .tpolicy sections, enforces SkCapabilities rules on secure-call invocations.&quot; },
  { term: &quot;IUM EKU&quot;, definition: &quot;The Enhanced Key Usage OID 1.3.6.1.4.1.311.10.3.37. Required alongside the Windows System Component Verification EKU for a binary to be loaded as a trustlet at Signature Level 12.&quot; },
  { term: &quot;Trustlet Instance GUID&quot;, definition: &quot;A runtime identifier the Secure Kernel uses to scope per-instance secrets. Set via IumSetTrustletInstance; shared between cooperating trustlets (e.g., vmsp.exe and the vTPM provisioning trustlet) so they can read each other&apos;s storage blobs under SkCapabilities control.&quot; },
  { term: &quot;Malwarelet&quot;, definition: &quot;Ionescu&apos;s term for an attacker-controlled trustlet, enabled by a Test Signing or Secure Boot compromise rather than by a trustlet-internal bug.&quot; },
  { term: &quot;ALPC&quot;, definition: &quot;Asynchronous Local Procedure Call: Windows IPC primitive used by VTL0 agent processes to communicate with their VTL1 trustlet counterparts.&quot; }
]} questions={[
  { q: &quot;Name the five gates a Windows binary must pass at load time to become a trustlet.&quot;, a: &quot;(1) PsAttributeSecureProcess process attribute with a 64-bit Trustlet ID. (2) Two EKUs at Signature Level 12: Windows System Component Verification (1.3.6.1.4.1.311.10.3.6) and IUM (1.3.6.1.4.1.311.10.3.37). (3) A .tpolicy PE section exporting s_IumPolicyMetadata with matching Trustlet ID. (4) A Trustlet Instance GUID bound via IumSetTrustletInstance. (5) The stripped-down LdrpIsSecureProcess loader path.&quot; },
  { q: &quot;Why does a SYSTEM-privilege NT-kernel write primitive on Windows 11 25H2 fail to read LsaIso.exe memory?&quot;, a: &quot;Because the NT kernel runs in VTL0, LsaIso.exe runs in VTL1, and the Hyper-V hypervisor configures per-VTL SLAT entries that refuse VTL0 read access to VTL1-only pages. The attacker&apos;s kernel write primitive can edit NT kernel structures but cannot change the hypervisor-managed SLAT entries.&quot; },
  { q: &quot;What does Pass-the-Challenge demonstrate about the limits of Credential Guard?&quot;, a: &quot;That while the NTLM hash itself never leaves VTL1, the agent process (lsass.exe in VTL0) can be asked to ask the trustlet to compute an authentication response for an attacker-supplied challenge. The resulting response is reachable by the VTL0 attacker and is sufficient for many relay attacks. The hash is protected; the authentication outcomes it produces are not.&quot; },
  { q: &quot;What is the practical floor of the trustlet attack surface that Amar and King exposed at Black Hat USA 2020?&quot;, a: &quot;The secure-call interface (IumInvokeSecureService) parses VTL0-controlled inputs in VTL1. Hyperseed retargeted at it found five VTL0-&amp;gt;VTL1 bugs in two weeks, including CVE-2020-0917 (OOB read in the secure-call surface) and CVE-2020-0918 (SkmmUnmapMdl design flaw). Microsoft responded with segment-heap migration, W+X reduction, and SkpgContext (Secure Kernel HyperGuard).&quot; },
  { q: &quot;What is the third-party equivalent of an inbox trustlet on Windows 11 24H2 and later?&quot;, a: &quot;A VBS Enclave: a DLL signed with a Trusted Signing certificate and loaded into an enclave region of a host process via CreateEnclave / CallEnclave. Requires Windows 11 Build 26100.2314 or later, Windows SDK 10.0.22621.3233 or later, and Visual Studio 2022 17.9 or later.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>vbs</category><category>trustlets</category><category>credential-guard</category><category>hyper-v</category><category>secure-kernel</category><category>isolated-user-mode</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>When SYSTEM Isn&apos;t Enough: The Windows Secure Kernel and the End of Total Kernel Trust</title><link>https://paragmali.com/blog/the-windows-secure-kernel/</link><guid isPermaLink="true">https://paragmali.com/blog/the-windows-secure-kernel/</guid><description>How Windows built a hardware-isolated kernel above Ring 0 using Hyper-V, protecting credentials and code integrity even after full NT kernel compromise.</description><pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate><content:encoded>
**The Windows Secure Kernel (securekernel.exe) is a minimal kernel running in a hardware-isolated environment (VTL1) above the main NT kernel, enforced by the Hyper-V hypervisor.** It protects credentials, code integrity, and application secrets even when an attacker has full control of the standard kernel. Born from the failure of software-only defenses like PatchGuard, it represents the biggest architectural shift in Windows security since the original NT reference monitor. It is not invulnerable -- rollback attacks and side-channel vulnerabilities remain open problems -- but it fundamentally changed what &quot;kernel compromise&quot; means on Windows.
&lt;h2&gt;When SYSTEM Isn&apos;t Enough&lt;/h2&gt;
&lt;p&gt;An attacker has achieved the holy grail: SYSTEM-level access on a domain-joined Windows machine. They load Mimikatz, point it at LSASS, and reach for the domain admin&apos;s Kerberos ticket. The command runs. The output comes back empty. The credentials are there -- the machine uses them every second -- but they&apos;re locked behind a wall that even full kernel access cannot breach.&lt;/p&gt;
&lt;p&gt;Welcome to the world of the Windows Secure Kernel.&lt;/p&gt;
&lt;p&gt;For decades, Windows security rested on a single hard boundary: user mode versus kernel mode. If you crossed that line -- if you achieved Ring 0 execution -- the system was yours. Every credential, every security policy, every secret was accessible. Tools like Benjamin Delpy&apos;s Mimikatz turned this architectural reality into a practical catastrophe, making Pass-the-Hash and Pass-the-Ticket attacks trivially easy across enterprise networks [@mimikatz-github].&lt;/p&gt;
&lt;p&gt;But on a modern Windows 11 machine with Virtualization-Based Security (VBS) enabled, the rules have changed. A new trust boundary exists -- one enforced not by the kernel, but by the hypervisor running &lt;em&gt;above&lt;/em&gt; the kernel. Even SYSTEM-level access in the traditional kernel cannot reach across this boundary [@ms-vbs].&lt;/p&gt;
&lt;p&gt;If kernel mode gives you everything, what could possibly be &lt;em&gt;above&lt;/em&gt; kernel mode? The answer requires a 30-year journey through Windows security.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The All-or-Nothing Kernel: How Windows NT Was Built&lt;/h2&gt;
&lt;p&gt;In 1988, Dave Cutler began designing Windows NT with a security model influenced by military security research -- especially the reference monitor concept, distinct from Bell-LaPadula&apos;s mandatory-access-control model. State-of-the-art for its era. It also contained a fatal assumption.&lt;/p&gt;

The core component of the Windows NT security architecture that mediates all access to securable objects (files, registry keys, processes) by checking Access Control Lists (ACLs) against the caller&apos;s security token. The SRM runs in kernel mode and enforces discretionary access control for every system operation.
&lt;p&gt;The NT kernel drew a hard line between Ring 3 (user mode) and Ring 0 (kernel mode) [@custer-inside-nt]. User-mode processes could not directly access kernel memory. The Security Reference Monitor mediated all access to system objects. For the early 1990s, this was a significant advance over DOS and Windows 9x, where applications and the OS shared the same memory space with no isolation at all.Dave Cutler previously designed VMS at Digital Equipment Corporation (DEC). Many NT design principles -- including the SRM, the object manager, and the layered architecture -- trace directly back to VMS. The letters &quot;WNT&quot; are famously one character ahead of &quot;VMS&quot; in the alphabet.&lt;/p&gt;
&lt;p&gt;But the NT model contained a fatal assumption: &lt;strong&gt;all kernel-mode code is equally trusted&lt;/strong&gt;. Once a driver or exploit gained Ring 0 access, it shared the same address space and privilege level as the kernel itself. It could read and write any memory, modify the System Service Dispatch Table (SSDT), manipulate the Interrupt Descriptor Table (IDT), or unlink processes from the EPROCESS active process list.&lt;/p&gt;
&lt;p&gt;This was the golden age of kernel-mode rootkits. Jamie Butler&apos;s FU rootkit (2004) used Direct Kernel Object Manipulation (DKOM) to unlink processes from the active process list, making malicious processes invisible to Task Manager, antivirus tools, and every other system utility [@hoglund-rootkits]. SSDT hooking allowed rootkits to intercept and redirect any system call, providing total control over OS behavior.&lt;/p&gt;
&lt;p&gt;Mark Russinovich and Bryce Cogswell built the Sysinternals tools to make these kernel internals visible to defenders [@sysinternals-story]. Process Explorer, Filemon, and Regmon became essential diagnostic instruments. But visibility is not protection. Defenders could see the problem; they could not stop it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The NT kernel drew one hard line -- user mode versus kernel mode. When attackers crossed that line, there was nothing left to protect. Every security mechanism, every credential, every policy lived in the same flat address space. Microsoft needed to draw a new line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Software Guards for a Hardware Problem: PatchGuard and Friends&lt;/h2&gt;
&lt;p&gt;What do you do when the prisoners are as powerful as the guards? You send in more guards at the same level. That was Microsoft&apos;s first strategy -- and its fundamental flaw.&lt;/p&gt;

A software-only kernel integrity monitor introduced in 2005 for 64-bit Windows. PatchGuard periodically checks critical kernel structures (SSDT, IDT, GDT, processor MSRs) for unauthorized modifications and forces a Blue Screen of Death (CRITICAL_STRUCTURE_CORRUPTION) if tampering is detected.
&lt;p&gt;PatchGuard arrived in Windows XP x64 and Windows Server 2003 SP1 in 2005 [@wp-patchguard]. It used obfuscated, randomized integrity checks to detect unauthorized modifications to kernel structures. If it caught tampering, it triggered a BSOD. On the surface, this seemed like a strong defense.PatchGuard&apos;s internal implementation uses extensive obfuscation: randomized check intervals, encrypted context blocks, and self-protecting code that resists static analysis. Microsoft never published its internal design, treating security through obscurity as a deliberate delaying tactic against attackers.&lt;/p&gt;
&lt;p&gt;Mandatory kernel-mode code signing followed with Windows Vista x64 in 2007, requiring all kernel drivers to carry a valid &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;Authenticode&lt;/a&gt; signature [@ms-kmcs]. Data Execution Prevention (DEP) marked memory pages as non-executable [@ms-dep]. Address Space Layout Randomization (ASLR) randomized the memory layout of loaded modules [@ms-mitigations]. Supervisor Mode Execution Prevention (SMEP) blocked kernel code from executing user-mode memory pages [@ms-mitigations].&lt;/p&gt;
&lt;p&gt;Each mitigation raised the cost of attack. Together, they made kernel exploitation significantly harder. But each one had a fatal weakness.&lt;/p&gt;

An attack technique where adversaries install a legitimately signed but vulnerable third-party driver, then exploit the driver&apos;s vulnerability to gain arbitrary kernel-mode code execution. Because the driver carries a valid signature, it bypasses kernel-mode code signing enforcement.
&lt;p&gt;&lt;strong&gt;PatchGuard runs at Ring 0 -- the same privilege level as the attackers it monitors.&lt;/strong&gt; In 2019, the InfinityHook project demonstrated how to hook kernel callbacks via the Event Tracing for Windows (ETW) subsystem without patching any kernel structures that PatchGuard checks [@infinityhook-github]. PatchGuard never noticed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kernel-mode code signing stops unsigned drivers but not signed-and-vulnerable ones.&lt;/strong&gt; The BYOVD technique became a staple of advanced persistent threat (APT) groups: install a legitimately signed driver with a known vulnerability, exploit that vulnerability, and gain arbitrary kernel execution while all code signing checks pass [@ms-vuln-drivers].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DEP is bypassed by Return-Oriented Programming (ROP).&lt;/strong&gt; Instead of injecting new code, attackers chain existing executable code snippets (&quot;gadgets&quot;) to achieve arbitrary computation [@wp-rop]. &lt;strong&gt;ASLR has limited entropy&lt;/strong&gt; on 32-bit systems and is defeated by information leaks that reveal randomized base addresses [@wp-aslr].&lt;/p&gt;

Benjamin Delpy released Mimikatz in 2011, and the security world was never the same. What began as a proof-of-concept for extracting plaintext passwords from LSASS memory became the single most-used credential theft tool in real-world attacks. Red teams used it. Nation-state actors used it. Ransomware gangs used it. The tool&apos;s existence -- more than any theoretical argument -- forced Microsoft to confront the fact that LSASS credentials in a flat kernel address space were indefensible. Credential Guard was Mimikatz&apos;s direct response [@mimikatz-github].

PatchGuard was a guard who could be knocked out by the very prisoners it watched. A defense sharing its privilege level with the attacker can always, given sufficient motivation, be subverted.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; No software-only defense can protect against an attacker at the same privilege level. This is not a fixable bug -- it is a structural limitation. PatchGuard delays attacks; it cannot prevent them. Microsoft needed something that kernel-mode code could not even reach.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Building the Foundation: Secure Boot and the Trust Chain&lt;/h2&gt;
&lt;p&gt;If you cannot trust the kernel at runtime, can you at least trust that it started clean? UEFI Secure Boot bet on that premise.&lt;/p&gt;
&lt;p&gt;Windows 8 (October 2012) mandated Secure Boot for certified hardware, establishing a cryptographic chain of trust from firmware through bootloader to OS kernel [@ms-secure-boot]. Only components signed by trusted authorities could execute during the boot process. Measured Boot extended this by hashing each boot component into TPM Platform Configuration Registers (PCRs), creating a verifiable boot log that remote attestation services could check [@ms-trusted-boot].&lt;/p&gt;
&lt;p&gt;This was a real advance. Bootkits like TDL4/Alureon, which operated below the OS and were invisible to all software-based defenses, were effectively blocked [@ms-alureon]. The boot chain was now cryptographically verified.&lt;/p&gt;
&lt;p&gt;But Secure Boot had a critical gap: it protected the boot process, not runtime. Once Windows loaded and started executing, a kernel exploit could compromise the system just as before. PatchGuard was still the only runtime defense, and we have already seen its limitations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In 2023, ESET researchers confirmed BlackLotus -- the first publicly known UEFI bootkit that bypassed Secure Boot on fully updated Windows systems. It exploited CVE-2022-21894, using a legitimately signed but vulnerable Windows boot manager to load malicious code before the OS [@blacklotus-eset]. The attack demonstrated that even boot-time trust chains can be undermined via BYOVD-style techniques applied to the boot stack itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Secure Boot ensured the system started clean but could not keep it clean. Microsoft needed runtime isolation -- and the key technology was already sitting on millions of machines, unused for this purpose: the hypervisor.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Breakthrough: Virtual Trust Levels and the Secure Kernel&lt;/h2&gt;
&lt;p&gt;The insight that changed everything was deceptively simple: if Ring 0 attackers can compromise anything at Ring 0, create a Ring -1. The hypervisor was already there.&lt;/p&gt;
&lt;p&gt;Intel VT-x and AMD-V hardware virtualization extensions, shipping since 2005-2006, gave the hypervisor a privilege level above the OS kernel [@x86-virtualization]. Microsoft&apos;s Hyper-V already used this capability for virtual machines. The breakthrough was recognizing that the same hardware could create a security boundary &lt;em&gt;within a single OS instance&lt;/em&gt; -- not a separate VM, but a hardware-isolated execution context that the kernel could not reach.&lt;/p&gt;

A hardware-enforced execution environment created by the Hyper-V hypervisor using Second Level Address Translation (SLAT). VTL0 is the Normal World where the standard NT kernel, drivers, and applications run. VTL1 is the Secure World where securekernel.exe and security-critical trustlets execute. VTL1 memory is physically inaccessible to all VTL0 code, including the NT kernel.

A hardware feature (Intel Extended Page Tables / AMD Nested Page Tables) that provides a second layer of virtual-to-physical address translation managed by the hypervisor. SLAT enables the hypervisor to control which physical memory pages each VTL can access, making VTL1 memory invisible to VTL0 without any software-level enforcement that could be bypassed.
&lt;p&gt;In May 2015, Brad Anderson announced Virtualization-Based Security, Device Guard, and Credential Guard at Microsoft Ignite [@anderson-ignite-2015]. The initial Windows 10 release, version 1507 (July 2015), shipped with VBS, creating two Virtual Trust Levels: VTL0 (Normal World) and VTL1 (Secure World) [@ms-vbs].&lt;/p&gt;

flowchart TB
    subgraph VTL1[&quot;VTL1 -- Secure World&quot;]
        SK[&quot;securekernel.exe\n(Secure Kernel)&quot;]
        IUM[&quot;Isolated User Mode&quot;]
        LSAISO[&quot;lsaiso.exe\n(Credential Guard)&quot;]
        ENCLAVE[&quot;VBS Enclaves&quot;]
        IUM --- LSAISO
        IUM --- ENCLAVE
    end
    subgraph VTL0[&quot;VTL0 -- Normal World&quot;]
        NT[&quot;ntoskrnl.exe\n(NT Kernel)&quot;]
        DRIVERS[&quot;Kernel Drivers&quot;]
        LSASS[&quot;lsass.exe\n(LSASS broker)&quot;]
        APPS[&quot;User Applications&quot;]
    end
    subgraph HV[&quot;Hyper-V Hypervisor&quot;]
        SLAT[&quot;SLAT Enforcement\n(Intel EPT / AMD NPT)&quot;]
    end
    HV --&amp;gt;|&quot;enforces memory isolation&quot;| VTL1
    HV --&amp;gt;|&quot;enforces memory isolation&quot;| VTL0
    VTL0 -.-&amp;gt;|&quot;Secure Service Calls\n(controlled boundary)&quot;| VTL1
&lt;p&gt;Here is how it works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;At boot, the Hyper-V hypervisor initializes and creates both VTLs.&lt;/li&gt;
&lt;li&gt;The standard NT kernel (ntoskrnl.exe), all drivers, and user-mode applications run in VTL0.&lt;/li&gt;
&lt;li&gt;securekernel.exe loads in VTL1 kernel mode. It is a minimal, purpose-built kernel that handles only security-critical functions [@ionescu-bh2015].&lt;/li&gt;
&lt;li&gt;The hypervisor uses SLAT to make VTL1 memory physically inaccessible to VTL0. No amount of Ring 0 code in VTL0 can read or write VTL1 pages.&lt;/li&gt;
&lt;li&gt;Communication between VTL0 and VTL1 occurs only via Secure Service Calls (SSCs) -- controlled hypercalls that cross the VTL boundary under strict validation [@ms-vbs].&lt;/li&gt;
&lt;/ol&gt;

A process running in VTL1 Isolated User Mode (IUM), protected from all VTL0 access by hypervisor-enforced memory isolation. The canonical example is lsaiso.exe, the Credential Guard trustlet that holds NTLM hashes and Kerberos tickets in VTL1 where even a fully compromised NT kernel cannot reach them.
&lt;p&gt;securekernel.exe is deliberately minimal. While ntoskrnl.exe is a large general-purpose kernel, securekernel.exe is a much smaller, purpose-built VTL1 kernel whose exact size varies by Windows build. A smaller codebase means a smaller attack surface -- every line of code in VTL1 is a potential entry point for attackers, so Microsoft keeps it as small as possible.&lt;/p&gt;
&lt;p&gt;Alex Ionescu&apos;s 2015 Black Hat presentation was the first major public technical teardown of the Secure Kernel Mode (SKM) and Isolated User Mode (IUM) architecture [@ionescu-bh2015]. Rafal Wojtczuk (Bromium) followed in 2016 with the first independent security audit of VBS, mapping the trust boundaries and identifying the secure call interface as the primary attack surface [@wojtczuk-bh2016].&lt;/p&gt;
&lt;p&gt;What can an attacker with full SYSTEM access in VTL0 &lt;em&gt;not&lt;/em&gt; do?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read credentials protected by Credential Guard&lt;/li&gt;
&lt;li&gt;Load unsigned kernel drivers when HVCI is enabled&lt;/li&gt;
&lt;li&gt;Access VTL1 memory or modify Secure Kernel data structures&lt;/li&gt;
&lt;li&gt;Disable VBS without rebooting (and with Secure Boot + UEFI lock, not easily even then)&lt;/li&gt;
&lt;/ul&gt;

For the first time, an attacker with full NT kernel compromise could not access secrets protected in VTL1. This fundamentally changed the Windows threat model.
&lt;p&gt;For the first time, full NT kernel compromise was no longer game over. But what, exactly, does this new architecture protect?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Pillars: What the Secure Kernel Protects&lt;/h2&gt;
&lt;p&gt;The Secure Kernel is not a product -- it is a platform. Five distinct security features stand on its shoulders, each protecting a different class of asset.&lt;/p&gt;
&lt;h3&gt;Credential Guard&lt;/h3&gt;
&lt;p&gt;When Credential Guard is enabled, NTLM password hashes and Kerberos Ticket-Granting Tickets (TGTs) are stored exclusively in lsaiso.exe -- a trustlet running in VTL1 [@ms-credential-guard]. The VTL0 lsass.exe process acts as a broker: authentication requests from VTL0 are forwarded to lsaiso.exe via secure RPC over the VTL boundary. lsaiso.exe performs cryptographic operations (challenge signing, ticket generation) within VTL1 and returns only the result -- never the raw secret.&lt;/p&gt;

sequenceDiagram
    participant App as Application (VTL0)
    participant LSASS as lsass.exe (VTL0)
    participant HV as Hypervisor
    participant LSAISO as lsaiso.exe (VTL1)
    App-&amp;gt;&amp;gt;LSASS: Authentication request
    LSASS-&amp;gt;&amp;gt;HV: Secure Service Call
    HV-&amp;gt;&amp;gt;LSAISO: Forward to VTL1
    LSAISO-&amp;gt;&amp;gt;LSAISO: Sign challenge with stored credential
    LSAISO-&amp;gt;&amp;gt;HV: Return signed response (NOT the raw secret)
    HV-&amp;gt;&amp;gt;LSASS: Forward to VTL0
    LSASS-&amp;gt;&amp;gt;App: Authentication result
    Note over LSASS: Even SYSTEM access here cannot read VTL1 memory
&lt;p&gt;Even a Mimikatz-wielding attacker with SYSTEM access in VTL0 gets nothing -- the raw credentials never exist in VTL0 memory. Credential Guard is enabled by default on domain-joined, non-DC Windows 11 22H2+ systems that meet VBS hardware requirements [@ms-credential-guard].&lt;/p&gt;
&lt;h3&gt;HVCI / Memory Integrity&lt;/h3&gt;

A VBS feature (also called &quot;Memory Integrity&quot;) that enforces kernel-mode code integrity from VTL1. HVCI ensures only signed code executes in the kernel and enforces W^X (Write XOR Execute) policy on all kernel memory pages via SLAT. No kernel memory page can be both writable and executable simultaneously.

A memory protection policy enforcing that a page can be either writable or executable, but never both simultaneously. HVCI enforces W^X across all kernel memory via SLAT page permissions controlled from VTL1, preventing attackers from injecting and executing arbitrary code in the kernel.
&lt;p&gt;HVCI moves code integrity enforcement from VTL0 into VTL1 [@ms-hvci]. Before any kernel-mode driver loads, its signature is verified by VTL1 code integrity services. HVCI enforces W^X on kernel memory pages using SLAT: page table modifications that would create a writable-and-executable page are trapped by the hypervisor and denied. Even if an attacker achieves kernel execution in VTL0, they cannot load unsigned drivers or make arbitrary kernel memory executable.On newer CPUs, Intel Mode-Based Execution Control (MBEC, Kaby Lake / 7th Gen+) and AMD Guest Mode Execute Trap (GMET, Zen 2+) provide hardware-accelerated W^X enforcement. Older CPUs rely on software emulation (&quot;Restricted User Mode&quot;), which increases overhead.&lt;/p&gt;

flowchart TD
    A[&quot;Driver load request\n(VTL0)&quot;] --&amp;gt; B[&quot;Signature check\n(VTL1 code integrity)&quot;]
    B --&amp;gt;|&quot;Valid signature&quot;| C[&quot;Set page permissions:\nExecutable + Read-Only&quot;]
    B --&amp;gt;|&quot;Invalid signature&quot;| D[&quot;BLOCKED\nDriver cannot load&quot;]
    E[&quot;Attacker tries to\nmake page W+X&quot;] --&amp;gt; F{&quot;SLAT check\n(Hypervisor)&quot;}
    F --&amp;gt;|&quot;Violation: W+X&quot;| G[&quot;DENIED\nPage remains Read-Only&quot;]
    F --&amp;gt;|&quot;Valid: W XOR X&quot;| H[&quot;Allowed&quot;]
&lt;h3&gt;VBS Enclaves&lt;/h3&gt;

An isolated memory region backed by VTL1 that allows third-party applications to protect secrets from even admin-level OS compromise. The host application in VTL0 communicates with the enclave via the CallEnclave API. Enclave memory is invisible to all VTL0 code, including the NT kernel. Available since Windows 11 24H2.
&lt;p&gt;Starting with Windows 11 24H2, third-party developers can create their own VTL1-protected enclaves -- isolated memory regions for protecting application-level secrets like encryption keys and authentication tokens [@pulapaka-vbs-enclaves]. Unlike Intel SGX, VBS Enclaves require no specialized hardware beyond a VBS-capable CPU [@ms-vbs-enclaves]. Developers define enclave interfaces using EDL (Enclave Description Language) files and build with the VBS Enclave Tooling SDK [@vbs-enclave-tooling].&lt;/p&gt;

The development model works like this: you create an enclave DLL, sign it with a Trusted Signing certificate, and load it via the host application. The enclave runs in VTL1 user mode with access to a limited API surface -- no general Windows API access. All inputs from the VTL0 host must be validated and copied into VTL1 before use. Microsoft&apos;s developer guide covers the details [@ms-vbs-enclaves-dev], and the VBS Enclave Tooling package provides Rust crate support and Visual Studio 2022+ integration [@vbs-enclave-tooling].
&lt;h3&gt;System Guard Runtime Attestation&lt;/h3&gt;
&lt;p&gt;System Guard extends the trust chain from boot into runtime [@ms-system-guard]. A trustlet running in VTL1 periodically measures the integrity of critical system components -- boot state, kernel integrity, driver signatures -- and signs these measurements using a hardware-backed TPM key. Because the measurement code runs in VTL1, it is protected from tampering by compromised VTL0 code [@ms-system-guard-hw]. Remote attestation services (such as &lt;a href=&quot;https://paragmali.com/blog/the-defenders-dilemma-microsoft-antivirus/&quot; rel=&quot;noopener&quot;&gt;Microsoft Defender for Endpoint&lt;/a&gt;) can verify these signed reports to confirm device health -- enabling zero-trust conditional access decisions.&lt;/p&gt;
&lt;h3&gt;Secured-core PCs&lt;/h3&gt;
&lt;p&gt;Secured-core PCs integrate hardware, firmware, and VBS into a single security platform requirement [@ms-secured-core]. Certified hardware must include a 64-bit CPU with SLAT, IOMMU for DMA protection, &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 2.0&lt;/a&gt;, UEFI with Secure Boot, SMM protection, DRTM support, and VBS/HVCI enabled and firmware-locked. Major OEMs -- Dell, HP, Lenovo, Microsoft Surface -- ship Secured-core PCs for enterprise and government customers.&lt;/p&gt;
&lt;p&gt;VBS also enables additional isolation features beyond these core pillars. Windows Defender Application Guard (WDAG) uses Hyper-V containers to isolate untrusted browser sessions and Office documents, preventing web-based exploits from reaching the host OS. Hyper-V container isolation provides similar protection for containerized workloads.&lt;/p&gt;
&lt;h3&gt;Decision Guide&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommended Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Protect domain credentials from Pass-the-Hash/Ticket&lt;/td&gt;
&lt;td&gt;Enable Credential Guard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prevent unsigned kernel driver loading&lt;/td&gt;
&lt;td&gt;Enable HVCI / Memory Integrity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protect application-level secrets from admin attacks&lt;/td&gt;
&lt;td&gt;Develop a VBS Enclave&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify device integrity for zero-trust&lt;/td&gt;
&lt;td&gt;Enable System Guard Runtime Attestation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum baseline security for new hardware&lt;/td&gt;
&lt;td&gt;Require Secured-core PC certification&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Secure Kernel now protects credentials, code integrity, application secrets, and device health. It is deployed across many millions of Windows 11 and Windows Server machines via VBS-by-default. But is it unbreakable?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;How Others Solve This Problem: Competing Approaches&lt;/h2&gt;
&lt;p&gt;Windows is not alone in this challenge. Intel, AMD, and ARM each built their own answer to the same question: how do you protect secrets from a compromised OS? Each made different trade-offs.&lt;/p&gt;
&lt;h3&gt;Intel SGX&lt;/h3&gt;
&lt;p&gt;Intel Software Guard Extensions provided hardware enclaves at the CPU level without requiring a hypervisor [@wp-sgx]. Application code and data inside an SGX enclave were encrypted in memory and isolated from the OS, hypervisor, and other applications. The idea was compelling: trust nothing but the CPU itself.&lt;/p&gt;
&lt;p&gt;Then side-channel attacks proved the CPU itself was not trustworthy. The Foreshadow attack (2018) exploited L1 Terminal Fault to extract data directly from SGX enclaves via CPU cache side channels [@foreshadow]. Intel deprecated SGX across 11th Gen client CPUs, including Tiger Lake mobile and Rocket Lake desktop, and continued that direction with 12th Gen Alder Lake [@wp-sgx].&lt;/p&gt;
&lt;h3&gt;AMD SEV-SNP&lt;/h3&gt;
&lt;p&gt;AMD Secure Encrypted Virtualization with Secure Nested Paging (SEV-SNP) encrypts VM memory with per-VM keys and enforces page ownership via a Reverse Map Table (RMP) -- a hardware table that records which VM owns each physical page [@amd-sev]. Even the hypervisor cannot read or remap guest memory without the guest&apos;s consent. This is a fundamentally different trust model from VBS: SEV-SNP &lt;em&gt;distrusts&lt;/em&gt; the hypervisor, while VBS &lt;em&gt;trusts&lt;/em&gt; it. SEV-SNP protects VMs in multi-tenant cloud environments (like Azure Confidential VMs) but does not provide intra-OS isolation within a single machine the way VBS does. The two are complementary, not competing.&lt;/p&gt;
&lt;h3&gt;Intel TDX&lt;/h3&gt;
&lt;p&gt;Intel Trust Domain Extensions create hardware-isolated Trust Domains for VMs, excluding the hypervisor from the trusted computing base [@intel-tdx]. The TDX Module runs in a special CPU mode called Secure Arbitration Mode (SEAM) and mediates all interactions between the hypervisor and Trust Domains -- the hypervisor can schedule TD VMs but cannot read their memory or registers. Like SEV-SNP, TDX targets cloud confidential computing rather than intra-OS protection. It complements VBS rather than replacing it.&lt;/p&gt;
&lt;h3&gt;ARM TrustZone&lt;/h3&gt;
&lt;p&gt;ARM TrustZone partitions the CPU into a Secure World and a Normal World using a hardware security state bit, predating VBS by a decade (2004 vs. 2015) [@arm-trustzone]. World transitions happen through a Secure Monitor Call (SMC) instruction, handled by firmware or a trusted OS like OP-TEE. The concept is similar to VBS -- two execution worlds with hardware isolation -- but the mechanism differs. TrustZone has a smaller attack surface (no hypervisor in the path) but is less flexible: it typically supports only two worlds with coarser granularity. TrustZone dominates mobile and embedded devices; Windows on ARM still uses the hypervisor-based VBS model for VTL0/VTL1 separation, the same architecture as VBS on x64.ARM TrustZone predates VBS by over a decade. The concept of hardware-enforced dual execution worlds was well established in the mobile/embedded world long before Microsoft applied the idea to desktop Windows. The insight was not the dual-world concept itself, but using the x86 hypervisor to implement it.&lt;/p&gt;
&lt;h3&gt;Linux&lt;/h3&gt;
&lt;p&gt;No production equivalent of VBS exists in mainline Linux. Linux relies on Mandatory Access Control (SELinux/AppArmor), container isolation (namespaces/cgroups), and VM-level isolation via SEV-SNP or TDX for cloud workloads. Google&apos;s pKVM (Protected KVM) in Android and ChromeOS is the closest parallel -- it uses the hypervisor to isolate a secure VM from the host kernel, similar in spirit to VTL1. Research projects have proposed similar intra-OS isolation for desktop Linux, but none has reached mainline. Linux&apos;s security philosophy favors defense-in-depth via many smaller mechanisms rather than a single architectural boundary.&lt;/p&gt;
&lt;h3&gt;Cross-Platform Comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Windows VBS&lt;/th&gt;
&lt;th&gt;Intel SGX&lt;/th&gt;
&lt;th&gt;AMD SEV-SNP&lt;/th&gt;
&lt;th&gt;Intel TDX&lt;/th&gt;
&lt;th&gt;ARM TrustZone&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Isolation granularity&lt;/td&gt;
&lt;td&gt;OS-level (VTL split)&lt;/td&gt;
&lt;td&gt;Process-level enclaves&lt;/td&gt;
&lt;td&gt;VM-level&lt;/td&gt;
&lt;td&gt;VM-level&lt;/td&gt;
&lt;td&gt;2 worlds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trusts the hypervisor?&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;N/A (no hypervisor)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory encryption&lt;/td&gt;
&lt;td&gt;No (isolation only)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (full VM)&lt;/td&gt;
&lt;td&gt;Yes (full VM)&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary use case&lt;/td&gt;
&lt;td&gt;Desktop/server OS&lt;/td&gt;
&lt;td&gt;Legacy high-assurance&lt;/td&gt;
&lt;td&gt;Cloud confidential VMs&lt;/td&gt;
&lt;td&gt;Cloud confidential VMs&lt;/td&gt;
&lt;td&gt;Mobile/IoT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status (2025)&lt;/td&gt;
&lt;td&gt;Active, expanding&lt;/td&gt;
&lt;td&gt;Deprecated on consumer&lt;/td&gt;
&lt;td&gt;GA on major clouds&lt;/td&gt;
&lt;td&gt;Rolling out&lt;/td&gt;
&lt;td&gt;Widely deployed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Known weakness&lt;/td&gt;
&lt;td&gt;Rollback, side-channels&lt;/td&gt;
&lt;td&gt;Foreshadow, deprecated&lt;/td&gt;
&lt;td&gt;Physical attacks&lt;/td&gt;
&lt;td&gt;Early deployment&lt;/td&gt;
&lt;td&gt;Firmware attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Every platform bets on a different trust anchor. VBS trusts the hypervisor. SEV-SNP trusts only the CPU and its encryption keys. SGX trusted the CPU itself -- until side-channel attacks proved that wrong. The uncomfortable question follows: what &lt;em&gt;cannot&lt;/em&gt; VBS protect against?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Limits: What VBS Cannot Protect Against&lt;/h2&gt;
&lt;p&gt;Every security boundary has an edge. VBS&apos;s edge is more nuanced than most defenders realize.&lt;/p&gt;
&lt;h3&gt;Attacking the Secure Kernel Directly&lt;/h3&gt;
&lt;p&gt;In August 2020, Saar Amar and Daniel King of Microsoft&apos;s own MSRC stood on the Black Hat stage and demonstrated something the community had feared: direct exploitation of securekernel.exe itself [@amar-bh2020]. Using a custom fuzzer called Hyperseed, they found the first five vulnerabilities in the secure call interface within two weeks; combined with continued manual auditing, they ultimately disclosed ten vulnerabilities [@amar-publications]. Memory corruption bugs in pool management and interface validation allowed VTL0 code to achieve code execution inside VTL1 -- breaking the isolation entirely.&lt;/p&gt;
&lt;p&gt;All vulnerabilities were patched before disclosure. Microsoft has since added mitigations: improved KASLR, Control Flow Guard (CFG) in VTL1, and stricter input validation. But the attack proved that VTL1 is not invulnerable -- the secure call interface is a real attack surface, and any bug there defeats all VBS guarantees.&lt;/p&gt;
&lt;h3&gt;Pass-the-Challenge: The Protocol-Level Bypass&lt;/h3&gt;
&lt;p&gt;Oliver Lyak&apos;s &quot;Pass-the-Challenge&quot; research revealed a subtle limitation of Credential Guard [@lyak-pass-the-challenge]. Credential Guard prevents credential &lt;em&gt;extraction&lt;/em&gt; -- but it cannot prevent credential &lt;em&gt;use&lt;/em&gt;. An attacker with SYSTEM access can relay NTLM authentication challenges through lsaiso.exe, using the machine as an &quot;NTLM oracle.&quot; The raw hash never leaves VTL1, but the attacker can still sign challenges on demand.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Credential Guard perfectly isolates secrets in VTL1, but the VTL0 broker (lsass.exe) necessarily provides an interface for using those secrets. Pass-the-Challenge exploits that interface -- not to extract secrets, but to relay them. This is a fundamental design tension: the more useful the isolation boundary, the more attack surface the boundary&apos;s API exposes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Side-Channel Attacks&lt;/h3&gt;
&lt;p&gt;Spectre and Meltdown demonstrated that speculative execution creates information leakage channels across any software-enforced boundary [@spectre-paper]. VTL0 and VTL1 share the same physical CPU, including caches, branch predictors, and TLBs. Microsoft has deployed microcode updates and software mitigations (IBRS, STIBP, retpolines) [@ms-spectre-advisory], but these reduce the risk rather than eliminating it. Complete elimination requires fundamentally different CPU designs that do not share microarchitectural state across trust boundaries.&lt;/p&gt;
&lt;h3&gt;The Formal Verification Gap&lt;/h3&gt;

The seL4 microkernel is formally verified -- mathematically proven correct for approximately 8,700 lines of C code [@sel4-whitepaper]. This means its isolation guarantees are not empirical (&quot;we tested it and found no bugs&quot;) but mathematical (&quot;we proved it cannot have certain classes of bugs&quot;). Hyper-V is orders of magnitude larger and more complex. Formally verifying it with current techniques is infeasible. The gap between &quot;extensively tested&quot; and &quot;mathematically proven&quot; is significant: Hyper-V&apos;s isolation is empirically strong, not provably correct. A single hypervisor bug could allow VTL escape.
&lt;h3&gt;Microsoft&apos;s Own Boundary&lt;/h3&gt;
&lt;p&gt;Microsoft explicitly states in its Security Servicing Criteria that an administrator with physical access is &lt;em&gt;not&lt;/em&gt; a security boundary [@ms-servicing-criteria]. VBS defends against remote kernel exploitation and privilege escalation, but not against an administrator who can modify firmware, attach hardware debuggers, or perform DMA or evil-maid-style physical attacks; Microsoft&apos;s VBS guidance separately calls out IOMMU-backed DMA protection as a distinct hardware requirement [@ms-vbs].&lt;/p&gt;
&lt;p&gt;This boundary declaration has practical consequences: it is why CVE-2024-21302 (Windows Downdate) required an opt-in fix rather than an automatic security update -- the attack requires admin privileges.&lt;/p&gt;
&lt;p&gt;VBS is the strongest runtime isolation Windows has ever had. But it is empirically strong, not mathematically proven. And one attack discovered in 2024 threatened to undo it entirely.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Arms Race: Rollback Attacks and the Ongoing Battle&lt;/h2&gt;
&lt;p&gt;In August 2024, Alon Leviev of SafeBreach Labs stood on the Black Hat stage and demonstrated something terrifying: he could silently roll back a &quot;fully patched&quot; Windows system to a state where all VBS protections were vulnerable -- using Windows Update itself.&lt;/p&gt;

I found several vulnerabilities that let me develop Windows Downdate -- a tool to take over the Windows Update process to craft fully undetectable downgrades. -- Alon Leviev, SafeBreach Labs
&lt;p&gt;The Windows Downdate attack (CVE-2024-21302) works by hijacking the Windows Update mechanism to replace current versions of securekernel.exe, ci.dll, and other VBS components with older, vulnerable versions [@leviev-downdate]. The system continues to report itself as &quot;fully patched&quot; while running code with known, exploitable vulnerabilities [@cve-2024-21302]. The attack requires administrator privileges -- which, as we noted, Microsoft does not consider a security boundary.&lt;/p&gt;

sequenceDiagram
    participant Attacker as Attacker (Admin in VTL0)
    participant WU as Windows Update
    participant FS as File System
    participant Boot as Next Boot
    Attacker-&amp;gt;&amp;gt;WU: Hijack update process
    WU-&amp;gt;&amp;gt;FS: Replace securekernel.exe with old version
    WU-&amp;gt;&amp;gt;FS: Replace ci.dll with old version
    Note over FS: System still reports &quot;fully patched&quot;
    FS-&amp;gt;&amp;gt;Boot: Boot with vulnerable binaries
    Boot-&amp;gt;&amp;gt;Boot: VBS runs with known vulnerabilities
    Note over Boot: All previously patched bugs are re-exposed
&lt;p&gt;Microsoft does not consider admin-to-kernel a security boundary, which is why CVE-2024-21302 required an &quot;opt-in&quot; fix rather than an automatic security update. Organizations must explicitly deploy KB5042562 to enable rollback protection.&lt;/p&gt;
&lt;p&gt;Microsoft responded with KB5042562, publishing a SkuSiPolicy.p7b revocation policy to block loading of outdated VBS-related binaries [@ms-rollback-guidance]. A UEFI variable lock reduces the risk of firmware-level rollback, though Leviev&apos;s research demonstrated it can be bypassed through Windows Update manipulation without physical access [@leviev-downdate-update]. But deployment is opt-in and complex -- applying it incorrectly can cause boot failures. And the underlying mechanism (admin-level control over the update process) remains exploitable [@leviev-downdate-update].&lt;/p&gt;
&lt;p&gt;The weaponization of VBS itself followed shortly. At DEF CON 33 in August 2025, Akamai researchers demonstrated &quot;BYOVE&quot; (Bring Your Own Vulnerable Enclave) and &quot;Mirage&quot; -- techniques for running malware inside a VBS enclave, hidden from EDR and antimalware tools that cannot inspect VTL1 memory [@akamai-vbs-weaponization]. The very isolation that protects legitimate secrets can also protect malicious code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The same VTL1 isolation that makes VBS enclaves secure for legitimate applications makes them invisible to security tools. An attacker who can load a legitimately signed but vulnerable enclave DLL gains a hiding place that no VTL0 security product can inspect. Microsoft is actively hardening the enclave trust boundary [@ms-vbs-enclave-hardening], but the fundamental tension between isolation and visibility persists.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The pattern is clear: VBS raises the cost of attack, attackers find creative bypasses, Microsoft hardens further. The question is no longer &quot;is VBS breakable?&quot; but &quot;where does the research go next?&quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Open Questions: Where Research Is Heading&lt;/h2&gt;
&lt;p&gt;The Secure Kernel is mature but not finished. Five open problems define the next decade of research.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Complete rollback prevention.&lt;/strong&gt; KB5042562 is a start, but complete protection may require hardware-enforced monotonic version counters -- similar to ARM&apos;s anti-rollback fuse bits -- integrated into platform firmware [@ms-rollback-guidance]. Without hardware support, the administrator-who-controls-updates problem remains fundamentally unsolved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Secure Kernel vulnerability discovery.&lt;/strong&gt; Jonathan Jagt&apos;s 2025 MSc thesis at Radboud University documented the process of setting up a Secure Kernel debugging environment and analyzed patched security bugs to identify vulnerability patterns [@jagt-thesis]. A key finding: the tooling for VTL1 research is scarce. Building a VTL1 debugging environment requires VMware-specific configurations and custom modifications that most researchers do not have access to. Better tooling would accelerate both offensive and defensive research.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VBS Enclave security model.&lt;/strong&gt; The tension between protecting legitimate secrets and preventing malware evasion has no clean solution. Microsoft&apos;s hardening guidance addresses developer mistakes (TOCTOU races, pointer validation, reentrancy risks) [@ms-vbs-enclave-hardening], but the architectural problem -- that VTL1 isolation is equally useful to attackers and defenders -- requires a new approach to enclave attestation and monitoring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Formal verification.&lt;/strong&gt; Can we ever prove Hyper-V correct? The seL4 proof covers approximately 8,700 lines of C [@sel4-whitepaper]. Hyper-V is hundreds of thousands of lines. Current verification technology cannot scale to that size. Partial verification of critical subsystems (the SLAT enforcement logic, the secure call dispatcher) might be feasible and would meaningfully reduce the trusted computing base.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Side-channel elimination.&lt;/strong&gt; Requires fundamentally different CPU designs. Current mitigations (microcode patches, partitioned caches, branch prediction barriers) reduce the leakage rate but cannot close the channel entirely while VTL0 and VTL1 share physical hardware [@spectre-paper]. Some academic designs propose physically separate execution units for different trust levels, but these are years from production.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The theoretically perfect system would combine: a formally verified hypervisor, hardware with no shared microarchitectural state between trust levels, a complete binary revocation mechanism preventing all rollback attacks, and zero performance overhead. Each requirement is individually infeasible today. The Secure Kernel is the best available approximation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Windows Secure Kernel is the most significant architectural change to Windows security since the NT reference monitor. It does not make Windows invulnerable -- no technology does. But it changed what &quot;kernel compromise&quot; means.&lt;/p&gt;

gantt
    title Windows Kernel Security Evolution
    dateFormat YYYY
    axisFormat %Y
    section Gen 0
    NT Kernel (flat trust)       :1993, 2005
    section Gen 1
    PatchGuard (KPP)             :2005, 2012
    KMCS (driver signing)        :2007, 2012
    DEP                          :2004, 2012
    ASLR                         :2007, 2012
    SMEP                         :2011, 2015
    section Gen 2
    UEFI Secure Boot             :2012, 2015
    Measured Boot + TPM           :2012, 2015
    section Gen 3
    VBS + Secure Kernel           :2015, 2026
    Credential Guard              :2015, 2026
    HVCI / Memory Integrity       :2015, 2026
    System Guard Attestation      :2018, 2026
    Secured-core PCs              :2019, 2026
    section Gen 3.5
    VBS Enclaves                  :2024, 2026
&lt;p&gt;Modern Windows runs all three generations simultaneously -- PatchGuard still watches for kernel tampering, Secure Boot still verifies the boot chain, and VBS adds hardware-enforced isolation on top. Newer defenses supplement rather than replace earlier ones.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Theory is valuable; practice pays the bills. Here is how to enable, verify, and troubleshoot VBS on your systems.&lt;/p&gt;
&lt;h3&gt;Hardware Requirements&lt;/h3&gt;
&lt;p&gt;VBS requires: a 64-bit CPU with hardware virtualization (Intel VT-x or AMD-V), Second Level Address Translation (Intel EPT or AMD NPT), TPM 2.0, and UEFI firmware with Secure Boot [@ms-vbs]. For optimal HVCI performance, Intel Kaby Lake (7th Gen) or newer (for MBEC) or AMD Zen 2 or newer (for GMET) is recommended [@ms-hvci].&lt;/p&gt;
&lt;h3&gt;Enabling VBS&lt;/h3&gt;
&lt;p&gt;VBS can be enabled through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Group Policy:&lt;/strong&gt; Computer Configuration &amp;gt; Administrative Templates &amp;gt; System &amp;gt; Device Guard &amp;gt; Turn On Virtualization Based Security&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intune/MDM:&lt;/strong&gt; Use the DeviceGuard CSP or endpoint security policies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Registry:&lt;/strong&gt; Set &lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\EnableVirtualizationBasedSecurity&lt;/code&gt; to 1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HVCI/Memory Integrity can be enabled separately via Windows Security &amp;gt; Device Security &amp;gt; Core Isolation &amp;gt; Memory Integrity.&lt;/p&gt;
&lt;h3&gt;Verifying VBS Status&lt;/h3&gt;
&lt;p&gt;{`
// Simulates Get-CimInstance -ClassName Win32_DeviceGuard
// -Namespace root/Microsoft/Windows/DeviceGuard&lt;/p&gt;
&lt;p&gt;const vbsStatus = {
  VirtualizationBasedSecurityStatus: 2, // 0=Not enabled, 1=Enabled but not running, 2=Running
  RequiredSecurityProperties: [1, 2],   // 1=Hypervisor support, 2=Secure Boot
  AvailableSecurityProperties: [1, 2, 3, 5, 6], // What hardware supports
  SecurityServicesConfigured: [1, 2],   // 1=CredentialGuard, 2=HVCI
  SecurityServicesRunning: [1, 2],      // Which services are active
};&lt;/p&gt;
&lt;p&gt;const statusNames = { 0: &quot;Not enabled&quot;, 1: &quot;Enabled (not running)&quot;, 2: &quot;Running&quot; };
const serviceNames = { 1: &quot;Credential Guard&quot;, 2: &quot;HVCI / Memory Integrity&quot;, 3: &quot;System Guard&quot; };&lt;/p&gt;
&lt;p&gt;console.log(&quot;VBS Status:&quot;, statusNames[vbsStatus.VirtualizationBasedSecurityStatus]);
console.log(&quot;\nConfigured Security Services:&quot;);
vbsStatus.SecurityServicesConfigured.forEach(s =&amp;gt;
  console.log(&quot;  -&quot;, serviceNames[s] || &quot;Unknown (&quot; + s + &quot;)&quot;)
);
console.log(&quot;\nRunning Security Services:&quot;);
vbsStatus.SecurityServicesRunning.forEach(s =&amp;gt;
  console.log(&quot;  -&quot;, serviceNames[s] || &quot;Unknown (&quot; + s + &quot;)&quot;)
);
console.log(&quot;\nTo check on your system, run in PowerShell:&quot;);
console.log(&quot;Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root/Microsoft/Windows/DeviceGuard&quot;);
`}&lt;/p&gt;
&lt;p&gt;You can also verify VBS status via:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;msinfo32.exe:&lt;/strong&gt; Look for &quot;Virtualization-based security&quot; in the System Summary&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Windows Security app:&lt;/strong&gt; Device Security &amp;gt; Core Isolation details&lt;/li&gt;
&lt;/ul&gt;

**Driver compatibility:** Some older drivers violate W^X policy and fail to load with HVCI enabled. Check the Windows Event Log (CodeIntegrity events) for blocked drivers. Microsoft&apos;s Hardware Lab Kit (HLK) provides HVCI compatibility testing.&lt;p&gt;&lt;strong&gt;Performance impact:&lt;/strong&gt; VBS/HVCI adds roughly 5-10% overhead in CPU-bound workloads, especially gaming benchmarks [@vbs-perf]. On modern CPUs with MBEC/GMET, the overhead is lower. For gaming workloads, you may see reduced frame rates in CPU-bound scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credential Guard and NLA:&lt;/strong&gt; Network Level Authentication can fail if Credential Guard is enabled but the domain controller does not support the required Kerberos extensions. Ensure domain controllers are running Windows Server 2016 or later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cannot enable VBS:&lt;/strong&gt; Verify that virtualization is enabled in BIOS/UEFI settings, Secure Boot is on, and TPM 2.0 is present and enabled. Some older systems lack SLAT support.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. Open msinfo32.exe and confirm &quot;Virtualization-based security: Running&quot; 2. Check that &quot;Credential Guard&quot; and &quot;Hypervisor enforced Code Integrity&quot; appear under running services 3. Run &lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root/Microsoft/Windows/DeviceGuard&lt;/code&gt; in PowerShell for detailed status 4. Verify Secure Boot is enabled and TPM 2.0 is present&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Windows Secure Kernel is the most important Windows security feature most people have never heard of. It does not make the headlines that zero-days do. But it quietly changed the fundamental question of Windows security -- from &quot;can we keep attackers out of the kernel?&quot; to &quot;what can we protect even after they get in?&quot; The secrets behind the VTL1 wall remain safe. At least until the next chapter of the arms race.&lt;/p&gt;
&lt;hr /&gt;

VBS and HVCI add roughly 5-10% overhead in CPU-bound workloads, with gaming seeing the most noticeable impact [@vbs-perf]. For typical business usage (email, documents, web browsing), the impact is negligible. Modern CPUs with Intel MBEC (Kaby Lake / 7th Gen+) or AMD GMET (Zen 2+) significantly reduce this overhead through hardware-accelerated W^X enforcement.

No. securekernel.exe coexists with ntoskrnl.exe. The NT kernel handles all general OS operations -- process management, file systems, networking, device drivers. The Secure Kernel handles only security-critical functions: credential isolation, code integrity enforcement, enclave management. They run in parallel in separate VTLs.

No. VBS protects specific assets (credentials, code integrity, application secrets) from a compromised kernel. The NT kernel itself can still be exploited -- an attacker can still gain SYSTEM access, install rootkits in VTL0, and control the standard OS environment. What they cannot do is access VTL1-protected secrets or load unsigned kernel drivers (with HVCI enabled).

No. VBS uses the Hyper-V *hypervisor*, not traditional VMs. You can run VBS without creating any virtual machines. The hypervisor runs as a thin layer beneath both VTLs to enforce memory isolation. If you also use Hyper-V VMs, VBS coexists with them.

No. Credential Guard protects stored credentials (NTLM hashes, Kerberos TGTs) from extraction, but it does not eliminate the need for strong authentication. It does not protect against phishing, password reuse, or credential relay attacks (as demonstrated by Pass-the-Challenge [@lyak-pass-the-challenge]). Credential Guard is one layer in a defense-in-depth strategy.

Not without rebooting. And with Secure Boot and a UEFI lock, VBS cannot be easily disabled even across reboots. However, the Windows Downdate attack demonstrated that VBS *components* can be silently downgraded to vulnerable versions without disabling VBS itself [@leviev-downdate]. Deploying KB5042562 rollback protection mitigates this risk.

No. VBS creates isolated execution environments within a single OS instance, not separate VMs. VTL0 and VTL1 share the same OS, the same desktop, the same processes (with the exception of trustlets in VTL1). The isolation is at the memory level via SLAT, not at the OS level. It is more like having a secure safe inside your house than having two separate houses.
&lt;hr /&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;secure-kernel-windows&quot; keyTerms={[
  { term: &quot;VBS&quot;, definition: &quot;Virtualization-Based Security -- uses Hyper-V hypervisor to create hardware-isolated Virtual Trust Levels within a single OS instance&quot; },
  { term: &quot;VTL0&quot;, definition: &quot;Normal World -- where the standard NT kernel, drivers, and applications run&quot; },
  { term: &quot;VTL1&quot;, definition: &quot;Secure World -- where securekernel.exe and security-critical trustlets like lsaiso.exe run, isolated by SLAT&quot; },
  { term: &quot;SLAT&quot;, definition: &quot;Second Level Address Translation (Intel EPT / AMD NPT) -- hardware feature enabling hypervisor-enforced memory isolation between VTLs&quot; },
  { term: &quot;HVCI&quot;, definition: &quot;Hypervisor-Protected Code Integrity -- enforces W^X and code signing from VTL1&quot; },
  { term: &quot;Credential Guard&quot;, definition: &quot;VBS feature isolating NTLM hashes and Kerberos TGTs in VTL1 via lsaiso.exe&quot; },
  { term: &quot;BYOVD&quot;, definition: &quot;Bring Your Own Vulnerable Driver -- attack using signed-but-vulnerable drivers to bypass code signing&quot; },
  { term: &quot;PatchGuard&quot;, definition: &quot;Software-only kernel integrity monitor that runs at Ring 0 -- same level as attackers&quot; },
  { term: &quot;W^X&quot;, definition: &quot;Write XOR Execute -- memory policy preventing pages from being both writable and executable&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A process running in VTL1 Isolated User Mode, protected from all VTL0 access&quot; }
]} questions={[
  { q: &quot;Why can&apos;t PatchGuard provide the same security guarantees as VBS?&quot;, a: &quot;PatchGuard runs at Ring 0 -- the same privilege level as the attackers it monitors. Any Ring 0 code can find and disable PatchGuard given sufficient effort. VBS uses the hypervisor (Ring -1) to enforce isolation from a higher privilege level.&quot; },
  { q: &quot;What is the fundamental difference between VBS and AMD SEV-SNP?&quot;, a: &quot;VBS trusts the hypervisor and uses it to protect OS components from a compromised kernel. SEV-SNP distrusts the hypervisor and encrypts VM memory to protect guests from a compromised hypervisor. They address different threat models.&quot; },
  { q: &quot;Why can&apos;t Credential Guard prevent Pass-the-Challenge attacks?&quot;, a: &quot;Credential Guard isolates raw credentials in VTL1 but must provide an interface for using them (via lsaiso.exe). Pass-the-Challenge relays authentication challenges through this interface without extracting the secret -- exploiting the necessary API rather than breaking the isolation.&quot; },
  { q: &quot;What would it take to formally verify Hyper-V&apos;s isolation guarantees?&quot;, a: &quot;seL4 was verified for approximately 8,700 lines of C. Hyper-V is hundreds of thousands of lines. Current formal verification tools cannot scale to this size. Partial verification of critical subsystems (SLAT enforcement, secure call dispatch) might be feasible.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>secure-kernel</category><category>virtualization-based-security</category><category>credential-guard</category><category>hvci</category><category>kernel-security</category><category>hypervisor</category><category>operating-systems</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>