<?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: vbs</title><description>Posts tagged vbs.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:07 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/vbs/rss.xml" rel="self" type="application/rss+xml"/><item><title>Windows Downdate: When the Update Itself Is the Attack</title><link>https://paragmali.com/blog/windows-downdate-when-the-update-itself-is-the-attack/</link><guid isPermaLink="true">https://paragmali.com/blog/windows-downdate-when-the-update-itself-is-the-attack/</guid><description>How Alon Leviev turned Windows Update into a downgrade primitive, rolling fully-patched Windows 11 back to vulnerable VBS components while every signature still verified.</description><pubDate>Sat, 23 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Windows Update was designed to verify the integrity of files, not the monotonicity of versions.** In August 2024 at Black Hat USA, Alon Leviev (SafeBreach Labs) showed that an Administrator-context process can hijack Windows Update&apos;s own post-reboot servicing path by writing a single registry value, and use it to roll fully-patched Windows 11 system files back to historically vulnerable but legitimately Microsoft-signed versions [@safebreach-2024-aug]. Once the components VBS, HVCI, Credential Guard, and the Secure Kernel rely on have been replaced by their own past selves, the protections built on top of them quietly fail open. Microsoft has shipped a per-component revocation policy (`SkuSiPolicy.p7b` in KB5042562) and the substantive CVE-2024-38202 fix (KB5044284, October 2024), but maintains that the underlying primitive is not a security vulnerability because the Windows Security Servicing Criteria does not enumerate Administrator-to-kernel as a security boundary [@kb5042562; @kb5044284; @safebreach-2024-oct; @msft-servicing-criteria].
&lt;h2&gt;1. &quot;Up to Date&quot; Means Less Than It Says&lt;/h2&gt;
&lt;p&gt;Imagine a Windows 11 machine that has installed every cumulative update Microsoft has released this year. Settings says &lt;strong&gt;You&apos;re up to date&lt;/strong&gt;. The Authenticode signature on every system DLL validates against Microsoft&apos;s root. HVCI is on. Credential Guard is on. VBS is on with the UEFI lock engaged. Disk Cleanup is empty. The Servicing Stack reports a healthy state. And somewhere in &lt;code&gt;C:\Windows\System32&lt;/code&gt;, a two-year-old &lt;code&gt;ci.dll&lt;/code&gt; is happily enforcing the code-integrity policy on a kernel that thinks it is current.&lt;/p&gt;
&lt;p&gt;This machine was the demo on the SafeBreach blog in October 2024, and it is not a misconfiguration [@safebreach-2024-oct; @thehackernews-downdate]. The version on disk is &lt;code&gt;10.0.22621.1376&lt;/code&gt;, a build from before May 2024, when Microsoft patched Gabriel Landau&apos;s &lt;em&gt;False File Immutability&lt;/em&gt; race in &lt;code&gt;ci.dll&lt;/code&gt; [@elastic-ffi; @landau-itsnotasecurityboundary-repo]. The signature on that older build is legitimately Microsoft&apos;s. The hash matches a Microsoft-issued security catalog. Windows is perfectly happy to load it.&lt;/p&gt;
&lt;p&gt;The Driver Signature Enforcement policy, the &lt;a href=&quot;https://paragmali.com/blog/authenticode-and-catalog-files-the-crypto-foundation-under-w/&quot; rel=&quot;noopener&quot;&gt;Authenticode chain&lt;/a&gt;, the catalog trust path, the WinSxS component store, and the post-reboot servicing engine were all built on the same shared assumption. Windows Downdate is what happens when you stop assuming it.&lt;/p&gt;
&lt;p&gt;The author of that demo is Alon Leviev, a researcher then at SafeBreach Labs. On August 7, 2024 he presented &lt;em&gt;Windows Downdate: Downgrade Attacks Using Windows Updates&lt;/em&gt; at Black Hat USA, followed by a more detailed walk-through at DEF CON 32 four days later [@safebreach-2024-aug; @bh-leviev-slides].&lt;/p&gt;
&lt;p&gt;The technique he published does one thing and does it well: it takes Administrator-level access on a fully-patched Windows machine and converts it into Microsoft-signed historical code, running in the kernel, inside the Secure Kernel, inside the hypervisor, inside Credential Guard&apos;s isolated user-mode process. The OS does not notice. EDR does not notice. &lt;code&gt;sfc /scannow&lt;/code&gt; does not notice. Settings reports the system as patched, because in every sense Windows can express, it is.&lt;/p&gt;
&lt;p&gt;Leviev framed his goal as a four-property objective. The attack had to be &lt;strong&gt;undetectable&lt;/strong&gt; to endpoint security, &lt;strong&gt;invisible&lt;/strong&gt; to the user, &lt;strong&gt;persistent&lt;/strong&gt; across future updates, and &lt;strong&gt;irreversible&lt;/strong&gt; by repair tooling. The rest of this article will measure each piece of the attack against those four properties, but it is worth pausing on what they imply. They do not require defeating a single Microsoft mitigation. They require defeating &lt;em&gt;all of them simultaneously&lt;/em&gt;, and Leviev&apos;s claim is that one registry write is enough.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every Microsoft mitigation since 2015 implicitly assumed that the OS being protected was the current one. None of them declared &quot;the current one&quot; as a security boundary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That sentence is the spine of the article. To understand why nobody noticed for so long, we have to start somewhere unexpected: with a TLS bug from 2014.&lt;/p&gt;
&lt;h2&gt;2. A History of Downgrade Attacks (Before Windows Knew the Name)&lt;/h2&gt;
&lt;p&gt;If you can convince a system to do something old, you can convince it to do something dangerous. Bodo Möller, Thai Duong, and Krzysztof Kotowicz figured that out first, at least in the public literature. In October 2014 their &lt;em&gt;This POODLE Bites&lt;/em&gt; advisory described an attack on the way browsers retry failed TLS handshakes [@google-poodle-pdf; @nvd-poodle]. A man-in-the-middle could induce a connection failure, the browser would silently retry at a lower protocol version, and the server would accept SSL 3.0, where a CBC padding oracle let the attacker decrypt session cookies one byte at a time. SSL 3.0 had been broken for years, but it remained in the negotiation envelope for backwards compatibility, and the negotiation envelope was where the protocol was weakest.&lt;/p&gt;
&lt;p&gt;POODLE established the pattern. A protocol that retains legacy modes for compatibility creates a downgrade primitive &lt;em&gt;unless the protocol explicitly enforces &quot;highest version available.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Five months later, in March 2015, Karthikeyan Bhargavan and the miTLS team at INRIA found a near-identical pattern with FREAK: a stripped-down &quot;export-grade&quot; RSA cipher suite from the 1990s was still negotiable, and a fast attacker could factor the 512-bit key during the handshake [@freak-attack-site]. That same April, Möller and Adam Langley shipped RFC 7507 to standardise the first explicit in-band signal that a TLS client was deliberately falling back, so that the server could refuse [@rfc7507]. Three years after that, Eric Rescorla&apos;s TLS 1.3 (RFC 8446) baked downgrade resistance directly into the &lt;code&gt;ServerHello.random&lt;/code&gt; nonce -- a structural fix, not a hint [@rfc8446]. The same period gave us SLOTH from Bhargavan and Gaétan Leurent: a transcript-collision attack on TLS, IKE, and SSH whose mitigation pushed TLS 1.3 to &lt;em&gt;bind&lt;/em&gt; downgrade resistance into the transcript hash, making it impossible to rewrite the negotiation without breaking the integrity check [@sloth-ndss].&lt;/p&gt;
&lt;p&gt;The Microsoft UEFI CA 2023 rollout began in February 2024 with a phased deployment that runs through 2026, replacing the Windows Production 2011 CA in firmware databases worldwide [@msft-uefi-ca-2023]. This rollout is the firmware-layer analogue of TLS 1.3&apos;s binding: each rotation is intended to retire trust in the older signer, but the rotation only matters if the &lt;em&gt;consumer&lt;/em&gt; enforces it.&lt;/p&gt;
&lt;p&gt;Meanwhile, four years before POODLE, a small group of NYU and Tor researchers wrote the academic-canonical paper on what happens when an attacker controls a software update repository instead of a network. Justin Samuel, Nick Mathewson, Justin Cappos, and Roger Dingledine published &lt;em&gt;Survivable Key Compromise in Software Update Systems&lt;/em&gt; at ACM CCS 2010. They formalised three update-specific threats nobody had named before: &lt;strong&gt;rollback attacks&lt;/strong&gt; (the repository serves an older, vulnerable copy of metadata), &lt;strong&gt;freeze attacks&lt;/strong&gt; (the repository serves the same copy forever, preventing a client from ever learning about patches), and &lt;strong&gt;replay attacks&lt;/strong&gt; (the repository serves a stale snapshot to a victim selected by network position) [@tuf-spec; @tuf-security].&lt;/p&gt;
&lt;p&gt;The companion specification, now stewarded by the CNCF, says it plainly: &lt;em&gt;&quot;An attacker presents files to a software update system that are older than those the client has already seen. With no way to tell it is an obsolete version that may contain vulnerabilities, the user installs the software&quot;&lt;/em&gt; [@tuf-security]. That is The Update Framework. Sigstore, Docker Notary, PyPI&apos;s PEP 458, and in-toto all inherit its threat model.&lt;/p&gt;
&lt;p&gt;So by 2015 the academic and protocol communities had named the problem, given it a vocabulary, written a specification, and started shipping standards. Three years later the mobile world followed.&lt;/p&gt;
&lt;h3&gt;From protocols to operating systems&lt;/h3&gt;
&lt;p&gt;In August 2017, Android 8.0 shipped Verified Boot 2.0 (AVB), the first widely-deployed &lt;em&gt;operating-system&lt;/em&gt; rollback defence. AVB stamps a &lt;code&gt;rollback_index&lt;/code&gt; into each signed partition and stores per-slot maxima in TrustZone or in RPMB-backed storage; the bootloader refuses any image whose index is below the stored maximum [@aosp-avb]. The Android source page summarises the design goal: &lt;em&gt;&quot;AVB&apos;s key features include delegating updates for different partitions, a common footer format for signing partitions, and protection from attackers rolling back to a vulnerable version of Android&quot;&lt;/em&gt; [@aosp-avb].&lt;/p&gt;
&lt;p&gt;Three years after Android, Apple shipped the Signed System Volume on macOS Big Sur (November 2020). SSV seals the entire system volume into a single Merkle tree whose root is signed by Apple; on iOS and iPadOS the user cannot disable it [@apple-ssv]. The IETF Software Updates for Internet of Things working group standardised the same threat model in RFC 9019 (April 2021) for embedded firmware: &lt;em&gt;&quot;The firmware image is authenticated and integrity protected. Attempts to flash a maliciously modified firmware image or an image from an unknown, untrusted source must be prevented&quot;&lt;/em&gt; [@rfc9019].&lt;/p&gt;
&lt;p&gt;By 2022, every major mobile platform, every IoT firmware standard, and every modern image-based update system had named rollback as a primary threat and shipped a structural fix. Then came BlackLotus.&lt;/p&gt;

gantt
    title Downgrade attacks and defences, 2010-2024
    dateFormat YYYY-MM
    axisFormat %Y
    section Protocol downgrade
    POODLE (SSL 3.0)            :done, 2014-10, 60d
    FREAK (RSA_EXPORT)          :done, 2015-03, 30d
    RFC 7507 (TLS Fallback SCSV):done, 2015-04, 30d
    SLOTH (transcript collision):done, 2016-01, 30d
    TLS 1.3 (RFC 8446)          :done, 2018-08, 30d
    section Update systems
    TUF / CCS 2010              :done, 2010-10, 30d
    RFC 9019 (IETF SUIT)        :done, 2021-04, 30d
    section OS rollback defence
    Android AVB 2.0             :done, 2017-08, 30d
    Apple Sealed System Volume  :done, 2020-11, 30d
    section Windows precedent
    BlackLotus in the wild      :crit, 2022-10, 150d
    BlackLotus public           :crit, 2023-03, 30d
    Windows Downdate disclosure :crit, 2024-08, 30d
&lt;h3&gt;The Windows precedent&lt;/h3&gt;
&lt;p&gt;Martin Smolar&apos;s &lt;em&gt;BlackLotus UEFI Bootkit: Myth Confirmed&lt;/em&gt; arrived in March 2023, and it was the direct precedent Leviev would cite. BlackLotus was a UEFI bootkit that had been on sale on hacking forums since October 2022 [@welivesecurity-blacklotus]. Its key trick was to ship its own copy of a legitimately Microsoft-signed but vulnerable &lt;code&gt;bootmgfw.efi&lt;/code&gt; -- specifically, a build still affected by CVE-2022-21894, the &quot;Baton Drop&quot; &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; bypass that Microsoft had patched in January 2022.&lt;/p&gt;
&lt;p&gt;Smolar wrote: &lt;em&gt;&quot;Although the vulnerability was fixed in Microsoft&apos;s January 2022 update, its exploitation is still possible as the affected, validly signed binaries have still not been added to the UEFI revocation list. BlackLotus takes advantage of this, bringing its own copies of legitimate -- but vulnerable -- binaries to the system in order to exploit the vulnerability&quot;&lt;/em&gt; [@welivesecurity-blacklotus]. The NSA shipped a &lt;em&gt;BlackLotus Mitigation Guide&lt;/em&gt; in June 2023 [@nsa-blacklotus-guide]; Microsoft began the laborious process of populating &lt;code&gt;dbx&lt;/code&gt;, the UEFI Secure Boot revocation list, with the offending hashes [@uefi-revocation-list].&lt;/p&gt;
&lt;p&gt;The point that anchors this section: Microsoft &lt;em&gt;did&lt;/em&gt; patch downgrade extensively at the firmware and boot-loader layer in response to BlackLotus. They updated &lt;code&gt;dbx&lt;/code&gt;. They rolled the UEFI Production CA in February 2024 [@msft-uefi-ca-2023]. The architectural lesson -- &lt;em&gt;if you have not declared which version of a signed binary is current, your signature is not enough&lt;/em&gt; -- had been internalised at the bottom of the stack. Whether anybody closed the same gap at the OS-component layer was a question only Leviev seems to have asked.&lt;/p&gt;
&lt;h2&gt;3. The Vista Bargain -- Component-Based Servicing and the Fourth Principal&lt;/h2&gt;
&lt;p&gt;If you sit down at a Windows 11 machine right now, open an elevated PowerShell as a local Administrator, and try to overwrite &lt;code&gt;C:\Windows\System32\ntoskrnl.exe&lt;/code&gt;, Windows will refuse. The error is &lt;em&gt;Access is denied&lt;/em&gt;. That is unexpected, because you are an Administrator, and on every Windows since NT 3.1 Administrators have been the highest principal on the box. The reason has a date.&lt;/p&gt;
&lt;p&gt;In November 2006, Windows Vista shipped a fourth Windows security principal: &lt;code&gt;NT SERVICE\TrustedInstaller&lt;/code&gt;. Its well-known SID is the long numeric string &lt;code&gt;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464&lt;/code&gt;, and its job is to be the only identity permitted to write into most of &lt;code&gt;System32&lt;/code&gt; [@safebreach-2024-aug; @ms-learn-servicing-stack-updates]. Administrators can take ownership of files there and grant themselves write access, but the default ACL excludes them. The change accompanied two other Vista deliverables that, taken together, became the contract that Windows servicing has obeyed for two decades.&lt;/p&gt;

A Windows security principal introduced in Vista that owns most of the system files under `C:\Windows\System32`. Its job is to mediate component-based servicing operations: when you install a Windows Update, the work runs in TrustedInstaller&apos;s context, not the Administrator&apos;s. Direct writes to TrustedInstaller-owned files by other principals (including Administrators) are denied at the ACL.
&lt;p&gt;The first deliverable was &lt;strong&gt;Component-Based Servicing (CBS)&lt;/strong&gt;, the replacement for the self-extracting &lt;code&gt;Update.exe&lt;/code&gt; installers that had defined patch delivery from Windows NT 4.0 through Windows XP. CBS reshaped a Windows update from &quot;a small executable that scribbles into your system directory&quot; into &quot;a manifest-driven transaction over a versioned component store.&quot; The second deliverable was &lt;strong&gt;WinSxS&lt;/strong&gt; -- the side-by-side store under &lt;code&gt;C:\Windows\WinSxS\&lt;/code&gt; that holds every version of every CBS-managed component the system has ever installed [@safebreach-2024-aug; @ms-learn-servicing-stack-updates].&lt;/p&gt;

The Windows servicing architecture introduced in Vista that replaced self-extracting update installers. A CBS package contains a Microsoft-signed security catalog (`.cat`) whose hashes cover the package&apos;s manifest files (`.mum`, `.manifest`). The manifests, transitively trusted via the signed catalog, describe which files belong to which component and how those files should be installed. CBS operations are mediated by the TrustedInstaller service.
&lt;p&gt;The third deliverable was the &lt;strong&gt;manifest-and-catalog signing model&lt;/strong&gt; that knit the first two together. A CBS package contains a security catalog (&lt;code&gt;.cat&lt;/code&gt;) signed directly by Microsoft. The catalog&apos;s hashes cover the package&apos;s manifest files (&lt;code&gt;.mum&lt;/code&gt; and &lt;code&gt;.manifest&lt;/code&gt;); the manifests, in turn, name the package&apos;s payload files and describe their installation. The manifest files are &lt;em&gt;not&lt;/em&gt; signed individually, but their hashes appear in the signed catalog, so they are &lt;em&gt;transitively trusted&lt;/em&gt; [@safebreach-2024-aug]. The payload files are also not individually signed; their hashes appear in the manifests, which are themselves catalog-covered. The chain of custody runs catalog -&amp;gt; manifest -&amp;gt; payload, and at the root is Microsoft&apos;s signing key.&lt;/p&gt;
&lt;p&gt;What this gives you is an elegant, declarative contract for system integrity. Microsoft signs a catalog. The catalog vouches for a manifest. The manifest vouches for a file. The file lands on disk. TrustedInstaller is the only principal allowed to write it, and TrustedInstaller has its own protected service that runs the install transactionally.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;strong&gt;Signed file + TrustedInstaller-only write = system integrity.&lt;/strong&gt; Microsoft built the Vista servicing stack around this contract in 2006-2007. The contract is true on its face. It is also silent about one thing: &lt;em&gt;which version&lt;/em&gt; of a signed file is allowed to land on disk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That silence is older than CBS. It traces back through the related 2005-2007 file-integrity work. Kernel Patch Protection, marketed as PatchGuard, shipped in x64 Windows Server 2003 SP1 in March 2005 and watches for tampering with running kernel structures [@msft-patchguard-advisory]. KMCS, the Kernel-Mode Code Signing Walkthrough Microsoft published in July 2007, defined the &lt;a href=&quot;https://paragmali.com/blog/windows-kernel-code-integrity-2006-2026/&quot; rel=&quot;noopener&quot;&gt;&lt;em&gt;Driver Signature Enforcement&lt;/em&gt;&lt;/a&gt; policy that kernel-mode code on x64 Vista and later had to satisfy [@kmcs-walkthrough; @msdocs-kmcs-policy].&lt;/p&gt;
&lt;p&gt;The Microsoft Learn descendant page is more direct: &lt;em&gt;&quot;The kernel-mode driver signing policy for 64-bit versions of Windows Vista and later versions of Windows specifies that a kernel-mode driver must be signed for the driver to load&quot;&lt;/em&gt; [@msdocs-driver-signing]. Each of these primitives bound trust to &lt;em&gt;a Microsoft signature&lt;/em&gt;. None of them bound trust to &lt;em&gt;a Microsoft-asserted version&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This was reasonable in 2007. Update.exe had been the threat: tampering with system files mid-flight, racing the installer, replacing a DLL while the system was rebooting. Vista&apos;s reply was to put the entire operation behind a principal that admins could not impersonate. The threat model said &lt;em&gt;&quot;the attacker is some Administrator-context tool that will try to overwrite system files.&quot;&lt;/em&gt; The reply said &lt;em&gt;&quot;only TrustedInstaller writes system files, and TrustedInstaller will only write files the catalog says are theirs.&quot;&lt;/em&gt; It was a complete answer to the question that had been asked.&lt;/p&gt;
&lt;p&gt;It was an incomplete answer to a question nobody asked: &lt;em&gt;which version of which file goes through that door, and is &quot;which version&quot; a property anyone actually checks?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Eighteen years later, the answer was: no, &quot;which version&quot; is not a property anyone checks at the file layer. The catalog says &quot;this file belongs to this package.&quot; It does not say &quot;this file is the current member of this component family.&quot;&lt;/p&gt;
&lt;p&gt;The Vista bargain locked the door. It signed the keys. It named a single person who could turn the lock. What it did not do -- and was not designed to do -- was care whether the box behind the door was on the latest update or on the build from two years ago. That decision would land on three later generations of Windows integrity walls, and none of them caught it.&lt;/p&gt;
&lt;h2&gt;4. Generation by Generation -- The Walls That Weren&apos;t Walls of Time&lt;/h2&gt;
&lt;p&gt;Between 2007 and 2022, Microsoft built four more integrity walls on top of the Vista bargain. Each one was a generation forward. None of them added the dimension Windows Downdate needed them to add.&lt;/p&gt;
&lt;h3&gt;Generation 1: Kernel-Mode Code Signing / DSE (Vista x64, 2007)&lt;/h3&gt;
&lt;p&gt;The first wall. The kernel refused to load any driver that was not Authenticode-signed by a Microsoft-cross-signed CA [@kmcs-walkthrough; @msdocs-kmcs-policy; @msdocs-driver-signing]. DSE was enforced at driver load time by the kernel loader; non-signed drivers failed to load with an unmissable error. This was the first architectural assertion that &quot;a Microsoft-signed binary is the unit of trust at the kernel boundary.&quot;&lt;/p&gt;
&lt;p&gt;What it said: a kernel driver must be signed by Microsoft.&lt;/p&gt;
&lt;p&gt;What it did not say: &lt;em&gt;which&lt;/em&gt; Microsoft-signed driver. The catalog-trust model treats any Microsoft-signed version of a file as equally legitimate. That assumption is the one Windows Downdate exploits seventeen years later: signature validity is preserved across version rollback, because the catalog of the older version is still a Microsoft-signed catalog and the hash chain still resolves.&lt;/p&gt;
&lt;h3&gt;Generation 2: UEFI Secure Boot (Windows 8, 2012)&lt;/h3&gt;
&lt;p&gt;The second wall pushed the same idea down into firmware. The platform firmware refused to load a boot manager that was not signed by a key in the UEFI signature database (&lt;code&gt;db&lt;/code&gt;), and refused to load any binary whose hash was in the forbidden-signature database (&lt;code&gt;dbx&lt;/code&gt;) [@welivesecurity-blacklotus; @msft-uefi-ca-2023]. For the first time, Windows had a &lt;em&gt;version-specific revocation primitive at the platform layer&lt;/em&gt;: &lt;code&gt;dbx&lt;/code&gt; could enumerate specific binaries known to be unsafe.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;dbx&lt;/code&gt; had two problems. The first was rollout latency: BlackLotus demonstrated in 2023 that vulnerable, validly-signed &lt;code&gt;bootmgfw.efi&lt;/code&gt; binaries were still trusted by firmware a full year after Microsoft patched them in source [@welivesecurity-blacklotus]. The second was scope: &lt;code&gt;dbx&lt;/code&gt; covered boot-time binaries, not run-time OS components. A revocation primitive that only fires before &lt;code&gt;ntoskrnl.exe&lt;/code&gt; loads is not a defence against rolling back &lt;code&gt;ntoskrnl.exe&lt;/code&gt; itself.&lt;/p&gt;
&lt;p&gt;The Microsoft UEFI CA 2023 rollout is on a multi-year phased schedule starting February 13, 2024 and running into 2026 [@msft-uefi-ca-2023]. The phased rollout exists precisely because retiring trust in older signers is slow and operationally risky -- the same shape of problem that &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; now faces at the OS layer.&lt;/p&gt;
&lt;h3&gt;Generation 3: VBS + HVCI + Credential Guard (Windows 10, 2015)&lt;/h3&gt;
&lt;p&gt;The third wall changed the &lt;em&gt;threat model itself&lt;/em&gt;. Virtualization-Based Security used the Hyper-V hypervisor to create a higher-privilege isolation domain, called &lt;em&gt;Virtual Trust Level 1&lt;/em&gt; (VTL1), beneath the NT kernel&apos;s normal VTL0. Microsoft&apos;s own documentation states the new assumption directly: &lt;em&gt;&quot;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&quot;&lt;/em&gt; [@msdocs-vbs].&lt;/p&gt;

Virtual Trust Level 1 is the higher-privilege half of the Hyper-V-managed split that VBS introduces. VTL0 holds the normal NT kernel and user-mode processes. VTL1 holds the Secure Kernel (`securekernel.exe`), the kernel-mode Code Integrity policy enforcement (`skci.dll`), and Isolated User Mode trustlets such as the LSA isolation process (`LsaIso.exe`). VTL0 cannot read VTL1 memory; transitions between the two go through a narrow set of hypercalls.
&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; moved the kernel-mode code integrity check inside VTL1: a malicious kernel could no longer disable the check, because the check ran in a memory space the kernel could not write [@msdocs-vbs-hvci]. &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; moved LSA secrets into an Isolated User Mode trustlet, &lt;code&gt;LsaIso.exe&lt;/code&gt;, so a kernel-level attacker could not directly read NTLM hashes or Kerberos TGTs from LSASS memory [@msdocs-credguard]. The explicit, written threat model said: &lt;em&gt;assume the NT kernel can be compromised, and provide a higher-privilege isolation domain for security-critical state.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That sentence is doing all the work. It says VBS is a defence &lt;em&gt;against&lt;/em&gt; a compromised kernel, which means VBS is a defence against an attacker who has reached kernel code execution by any means. And one of the ways an attacker reaches kernel code execution -- one of the obvious ones, on a single-user Windows machine -- is to be an Administrator. The whole point of VBS was that Administrator code execution is the threat. That fact will matter again in section eight.&lt;/p&gt;
&lt;p&gt;The unsaid assumption in 2015 was that VTL1 components -- &lt;code&gt;securekernel.exe&lt;/code&gt;, &lt;code&gt;skci.dll&lt;/code&gt;, &lt;code&gt;LsaIso.exe&lt;/code&gt;, and the hypervisor binaries &lt;code&gt;hvix64.exe&lt;/code&gt; and &lt;code&gt;hvax64.exe&lt;/code&gt; -- were loaded from on-disk files using CBS+catalog trust, and that CBS+catalog trust was version-agnostic. Microsoft was building a higher trust boundary, but the integrity check for the binaries that lived on the other side of that boundary still ran through the Vista contract.&lt;/p&gt;
&lt;h3&gt;Generation 4: The Microsoft Vulnerable Driver Blocklist (2020 opt-in, default-on November 2022)&lt;/h3&gt;
&lt;p&gt;The fourth wall finally introduced a &lt;em&gt;generic version-revocation primitive&lt;/em&gt; for kernel-loaded code. The Microsoft Vulnerable Driver Blocklist was the answer to a class of attacks that had emerged in the 2010s: &lt;em&gt;bring-your-own-vulnerable-driver&lt;/em&gt;, where a malware loader installed a legitimately-signed, third-party driver with a known kernel exploit and used it as a bridge to kernel execution [@msft-driver-blocklist-blog]. The blocklist&apos;s Microsoft Learn page is direct about scope: the policy targets &lt;em&gt;non-Microsoft-developed drivers across the Windows software environment&lt;/em&gt;, and since the Windows 11 2022 update the blocklist is enabled by default for all devices [@msdocs-driver-blocklist].&lt;/p&gt;
&lt;p&gt;Read that sentence again, slowly. &lt;em&gt;Non-Microsoft-developed drivers.&lt;/em&gt; The blocklist is the right &lt;em&gt;mechanism&lt;/em&gt; -- a Microsoft-signed list of hashes of known-vulnerable signed binaries that the kernel refuses to load -- but it is pointed at the wrong &lt;em&gt;inventory&lt;/em&gt;. First-party Microsoft binaries, including the very VBS components VBS depends on, are out of scope. The same Microsoft team that built the only generic version-revocation primitive Windows ships chose, by policy, not to apply it to themselves.&lt;/p&gt;

flowchart TD
    A[&quot;Vista CBS + TrustedInstaller (2007)&lt;br /&gt;Signed file + restricted writer&quot;] --&amp;gt; B[&quot;KMCS / DSE (2007)&lt;br /&gt;Kernel rejects unsigned drivers&quot;]
    B --&amp;gt; C[&quot;UEFI Secure Boot (2012)&lt;br /&gt;Firmware rejects unsigned boot binaries&lt;br /&gt;dbx revokes specific hashes&quot;]
    C --&amp;gt; D[&quot;VBS + HVCI + Credential Guard (2015)&lt;br /&gt;VTL1 isolation, assume-kernel-compromised&lt;br /&gt;CI policy enforced inside Secure Kernel&quot;]
    D --&amp;gt; E[&quot;Vulnerable Driver Blocklist (2020-2022)&lt;br /&gt;Microsoft-signed hash revocation&lt;br /&gt;Third-party drivers only&quot;]
    E --&amp;gt; F[&quot;Gap: First-party VBS components&lt;br /&gt;still load by catalog signature alone&quot;]

The shape of `dbx` and the shape of `SkuSiPolicy.p7b` are the same: a Microsoft-signed list of hashes a loader refuses. `dbx` lives in UEFI firmware variables and is consulted by the platform boot manager. `SkuSiPolicy.p7b` is a Microsoft-signed Code Integrity policy that lives in the EFI System Partition (when the opt-in UEFI lock is applied) or in the boot session (the default-enabled variant), and is consulted by the Windows kernel loader. The conceptual lineage runs *firmware-layer hash revocation in 2012 -&amp;gt; OS-layer hash revocation in 2024*. The intervening twelve years were spent assuming the OS layer did not need it.
&lt;p&gt;By 2022, Microsoft had built every primitive a Downdate defence would have used. A Microsoft-signed hash-revocation list (the Driver Blocklist). A firmware-rooted enforcement chain (Secure Boot + &lt;code&gt;dbx&lt;/code&gt;). A hypervisor-isolated integrity check (HVCI inside VTL1). What had not been built was a &lt;em&gt;first-party&lt;/em&gt; hash-revocation list -- one that named the historical versions of &lt;code&gt;ci.dll&lt;/code&gt;, &lt;code&gt;ntoskrnl.exe&lt;/code&gt;, &lt;code&gt;securekernel.exe&lt;/code&gt;, &lt;code&gt;hvix64.exe&lt;/code&gt;, and &lt;code&gt;LsaIso.exe&lt;/code&gt; and refused to load them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Recall the thesis from §1: every Microsoft mitigation since 2015 implicitly assumes the OS being protected is the current one. The mechanism for declaring it -- hash revocation -- had existed since 2012, but it was always pointed at &lt;em&gt;somebody else&apos;s code&lt;/em&gt;. The Driver Blocklist proves Microsoft can ship a first-party hash-revocation list. It just had not been pointed inward.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So Microsoft had built every primitive it needed by 2022: a hash-revocation list, a firmware-rooted enforcement chain, a hypervisor-isolated integrity check. Why, in 2024, is a fully-patched Windows 11 machine still capable of loading a 2022 &lt;code&gt;ci.dll&lt;/code&gt;?&lt;/p&gt;
&lt;h2&gt;5. The Breakthrough -- Where the Integrity Boundary Moves&lt;/h2&gt;
&lt;p&gt;Leviev started with a simple specification. He wanted a downgrade that satisfied four properties [@safebreach-2024-aug]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Undetectable&lt;/strong&gt; by endpoint security tooling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invisible&lt;/strong&gt; in &lt;code&gt;winver&lt;/code&gt;, Settings, and the system&apos;s own self-reported state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistent&lt;/strong&gt; across future Windows Update installations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Irreversible&lt;/strong&gt; by &lt;code&gt;sfc /scannow&lt;/code&gt;, &lt;code&gt;DISM /Online /Cleanup-Image /RestoreHealth&lt;/code&gt;, and other repair tooling.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;undetectable&quot; requirement disqualified almost every obvious approach. Disabling Authenticode checking is detectable. Replacing the catalog signing root is detectable. Booting into Safe Mode and overwriting files is detectable. Loading a vulnerable driver is detectable. Whatever the attack ended up looking like, it had to run through &lt;em&gt;the legitimate Windows Update path&lt;/em&gt;, because that path is the one EDR is least suspicious of.&lt;/p&gt;
&lt;p&gt;Reading Leviev&apos;s August 2024 SafeBreach write-up is a study in patient state-machine reverse engineering. He had to discover the architecture of CBS, where TrustedInstaller fits into it, how &lt;code&gt;pending.xml&lt;/code&gt; action lists are written, where the integrity boundary of each phase lies, and which registry values are TrustedInstaller-protected versus which are merely Administrator-protected. Most of the answer turned out to be hidden in plain sight.&lt;/p&gt;
&lt;h3&gt;The Windows Update state machine&lt;/h3&gt;
&lt;p&gt;A Windows Update flows through a small state machine, and Leviev&apos;s contribution is to draw it precisely.&lt;/p&gt;
&lt;p&gt;A client process in Administrator context calls into the Windows Update Agent COM interfaces. Those interfaces transfer the update folder -- a Microsoft-signed package containing a &lt;code&gt;.cat&lt;/code&gt;, several &lt;code&gt;.mum&lt;/code&gt; and &lt;code&gt;.manifest&lt;/code&gt; files, and the new payload binaries -- to a TrustedInstaller-context server (&lt;code&gt;TrustedInstaller.exe&lt;/code&gt;). The server verifies the catalog signature, walks the manifests, and constructs an &lt;em&gt;action list&lt;/em&gt;. The action list is the work order that explains exactly which files will be renamed, hardlinked, deleted, or written, and which registry values will be set, when the system reboots. Microsoft stores it in a file called &lt;code&gt;pending.xml&lt;/code&gt; under a TrustedInstaller-only directory (&lt;code&gt;C:\Windows\WinSxS\pending.xml&lt;/code&gt;) [@safebreach-2024-aug; @ms-learn-servicing-stack-updates].&lt;/p&gt;
&lt;p&gt;On reboot, before the user logs in, a small program named &lt;code&gt;poqexec.exe&lt;/code&gt; reads &lt;code&gt;pending.xml&lt;/code&gt; and applies it. POQ stands for &quot;Primitive Operations Queue.&quot; The program is the post-reboot transactional engine that performs work the running OS could not safely do while it was running (such as overwriting &lt;code&gt;ntoskrnl.exe&lt;/code&gt;).&lt;/p&gt;

The post-reboot primitive-operations-queue executor. Reads the action list (`pending.xml`) at next boot, before normal services start, and applies its verbs -- hardlinks, file moves, registry writes -- to complete the previous boot&apos;s pending update operations. `poqexec.exe` has no notion of &quot;current version&quot; versus &quot;older version&quot;; it executes whatever action list its configuration points it at.
&lt;p&gt;So far, nothing is wrong. The catalog is signed. The manifests are catalog-covered. The action list lives in a TrustedInstaller-only directory. The executor that consumes it is part of the Windows servicing stack. The chain of custody runs from Microsoft&apos;s signing key through to the on-disk binaries the executor produces.&lt;/p&gt;
&lt;h3&gt;The action list integrity model -- and where it breaks&lt;/h3&gt;
&lt;p&gt;The catch is this. &lt;em&gt;The pointer to &lt;code&gt;pending.xml&lt;/code&gt; is not in a TrustedInstaller-only registry key.&lt;/em&gt; It is in &lt;code&gt;HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\PoqexecCmdline&lt;/code&gt;. The DACL on that value allows Administrator write. There is a parallel value, &lt;code&gt;HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PendingXmlIdentifier&lt;/code&gt;, that carries a nonce binding the action list to the boot-session identity; that value is also Administrator-writable [@safebreach-2024-aug; @splunk-downdate-detection].&lt;/p&gt;

The XML work order that describes the file and registry operations a Windows Update will apply at next boot. It uses a small set of POQ verbs (`HardlinkFile`, `MoveFile`, `CreateFile`, `SetFileInformation`, `DeleteFile`, `CreateDirectory`, `CreateKey`, `SetKeyValue`, `SetKeySecurity`, `DeleteKeyValue`, `DeleteKey`). The default copy lives in a TrustedInstaller-only directory. Which copy `poqexec.exe` parses on next boot is determined by an Administrator-writable registry value, `PoqexecCmdline`.
&lt;p&gt;The Administrator who initiates an update can choose &lt;em&gt;which action list &lt;code&gt;poqexec.exe&lt;/code&gt; parses&lt;/em&gt;. The integrity check on the update folder happened at the start of the transaction, in a different phase, with &lt;code&gt;TrustedInstaller&lt;/code&gt; doing the parsing. Once the action list has been produced, the chain of custody depends on Windows believing that &lt;code&gt;pending.xml&lt;/code&gt; came from a Microsoft-signed package. The mechanism by which Windows believes that is a registry value that an Administrator can rewrite.&lt;/p&gt;
&lt;p&gt;Differential update files are not individually signed -- their hashes appear in the catalog-covered manifest, so they inherit catalog trust by reference. This is a perfectly sensible design &lt;em&gt;if you also assert that the manifest you are using is the manifest for the latest update&lt;/em&gt;, which Windows does not.&lt;/p&gt;
&lt;p&gt;That is the architectural error, and it has a name. &lt;strong&gt;The integrity boundary moves between phases of the update.&lt;/strong&gt; The update folder is verified pre-action-list-creation. The action list is verified by being in a TrustedInstaller directory. &lt;em&gt;But the pointer to the action list is in admin-writable territory.&lt;/em&gt; The same identity (Administrator) that can legitimately initiate an update can choose which action list &lt;code&gt;poqexec.exe&lt;/code&gt; parses, and &lt;code&gt;poqexec.exe&lt;/code&gt; was never built to ask &quot;is this list the one I made?&quot;&lt;/p&gt;

sequenceDiagram
    participant Admin as Admin process
    participant TI as TrustedInstaller
    participant Reg as Registry (PoqexecCmdline)
    participant POQ as poqexec.exe (next boot)
    participant FS as System32 files
    Note over Admin,FS: Legitimate Windows Update
    Admin-&amp;gt;&amp;gt;TI: Submit signed update folder over COM
    TI-&amp;gt;&amp;gt;TI: Verify catalog and manifests
    TI-&amp;gt;&amp;gt;FS: Write pending.xml to WinSxS (TI-only)
    TI-&amp;gt;&amp;gt;Reg: Set PoqexecCmdline to default pending.xml
    Admin-&amp;gt;&amp;gt;Admin: Reboot
    POQ-&amp;gt;&amp;gt;Reg: Read PoqexecCmdline
    POQ-&amp;gt;&amp;gt;FS: Read default pending.xml
    POQ-&amp;gt;&amp;gt;FS: Apply verbs, install new files
    Note over Admin,FS: Windows Downdate
    Admin-&amp;gt;&amp;gt;FS: Write crafted pending.xml to attacker dir
    Admin-&amp;gt;&amp;gt;Reg: Overwrite PoqexecCmdline to crafted path
    Admin-&amp;gt;&amp;gt;Reg: Overwrite PendingXmlIdentifier to matching nonce
    Admin-&amp;gt;&amp;gt;Admin: Reboot
    POQ-&amp;gt;&amp;gt;Reg: Read PoqexecCmdline (now attacker path)
    POQ-&amp;gt;&amp;gt;FS: Read crafted pending.xml
    POQ-&amp;gt;&amp;gt;FS: Hardlink older Microsoft-signed binaries over current ones
&lt;p&gt;Once you can choose which action list &lt;code&gt;poqexec.exe&lt;/code&gt; parses, and &lt;code&gt;poqexec.exe&lt;/code&gt; was never built to ask &quot;is this list the one I made?&quot;, the consequences write themselves. The crafted &lt;code&gt;pending.xml&lt;/code&gt; can issue any verb the executor supports. It can hardlink an older &lt;code&gt;ci.dll&lt;/code&gt; over the current one. It can hardlink an older &lt;code&gt;ntoskrnl.exe&lt;/code&gt; over the current one. It can hardlink an older &lt;code&gt;securekernel.exe&lt;/code&gt; over the current one. The hashes of those older files appear in the Microsoft-signed catalogs of their original packages, which are still on disk in WinSxS. Every signature the kernel loader and the Secure Kernel will ever check resolves to a Microsoft key.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The bug is structural: the integrity boundary moves between phases of the update. The catalog signature verifies one phase; the directory ACL verifies the next; the registry pointer crosses the boundary in the wrong direction. The fix has to declare a new boundary that does not move.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;6. The Downdate Attack End-to-End&lt;/h2&gt;
&lt;p&gt;What does &lt;code&gt;python windows_downdate.py --config-xml downgrade.xml&lt;/code&gt; actually do on the wire? The tool&apos;s GitHub repository, &lt;code&gt;SafeBreach-Labs/WindowsDowndate&lt;/code&gt;, ships a documented schema and eight example chains, from a generic &lt;code&gt;ItsNotASecurityBoundary-Patch-Downgrade&lt;/code&gt; to a fully-formed &lt;code&gt;VBS-UEFI-Locks-Bypass&lt;/code&gt; [@windowsdowndate-repo]. Read alongside Leviev&apos;s blog, the procedure is, in machine terms, embarrassingly small. Eight steps.&lt;/p&gt;
&lt;h3&gt;6.1 The attack sequence&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Parse the config XML.&lt;/strong&gt; Each &lt;code&gt;&amp;lt;UpdateFile source=&quot;...&quot; destination=&quot;...&quot;/&amp;gt;&lt;/code&gt; element names one file to downgrade. If the source file does not exist locally, the tool retrieves the base version from the WinSxS component store [@windowsdowndate-repo].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build a crafted pending.xml.&lt;/strong&gt; For each target, emit a &lt;code&gt;&amp;lt;HardlinkFile&amp;gt;&lt;/code&gt; verb that creates a hardlink from the older file&apos;s location to the current file&apos;s location, plus the other POQ verbs needed to set ACLs, register the new file with the component store, and update the on-disk manifest hash where needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deposit pending.xml in an attacker-writable directory.&lt;/strong&gt; The Administrator does not need TrustedInstaller-write privilege to do this; the tool stores the crafted action list outside the TrustedInstaller-only directories.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compute a matching PendingXmlIdentifier nonce.&lt;/strong&gt; This is the value that &lt;code&gt;poqexec.exe&lt;/code&gt; cross-checks against the action list at parse time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write the two registry values.&lt;/strong&gt; &lt;code&gt;PoqexecCmdline&lt;/code&gt; is set to point at the attacker&apos;s &lt;code&gt;pending.xml&lt;/code&gt;. &lt;code&gt;PendingXmlIdentifier&lt;/code&gt; is set to the nonce computed in step 4.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trigger a reboot.&lt;/strong&gt; This can be a graceful &lt;code&gt;shutdown /r /t 0&lt;/code&gt; or any reboot-causing event.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;At next boot, &lt;code&gt;poqexec.exe&lt;/code&gt; reads PoqexecCmdline and parses the attacker pending.xml.&lt;/strong&gt; It applies the verbs in order. The current &lt;code&gt;ci.dll&lt;/code&gt; is replaced (via hardlink) with &lt;code&gt;10.0.22621.1376&lt;/code&gt;. The current &lt;code&gt;ntoskrnl.exe&lt;/code&gt; is replaced with whichever version the operator chose. The current &lt;code&gt;securekernel.exe&lt;/code&gt; is replaced. The current &lt;code&gt;hvix64.exe&lt;/code&gt; is replaced. The current &lt;code&gt;LsaIso.exe&lt;/code&gt; is replaced.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistence and irreversibility.&lt;/strong&gt; Two further verbs replace &lt;code&gt;poqexec.exe&lt;/code&gt; with a patched copy that NOPs future updates, and replace &lt;code&gt;sfc.exe&lt;/code&gt; with a patched copy that does not flag the downgraded files. Leviev&apos;s claim in the SafeBreach blog is that &lt;code&gt;poqexec.exe&lt;/code&gt; and &lt;code&gt;sfc.exe&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt; Authenticode-signed in the affected builds, so substituting modified versions does not require a code-signing bypass [@safebreach-2024-aug].&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The full set of POQ XML verbs that &lt;code&gt;poqexec.exe&lt;/code&gt; understands, taken from Leviev&apos;s documentation: &lt;code&gt;HardlinkFile&lt;/code&gt;, &lt;code&gt;MoveFile&lt;/code&gt;, &lt;code&gt;CreateFile&lt;/code&gt;, &lt;code&gt;SetFileInformation&lt;/code&gt;, &lt;code&gt;DeleteFile&lt;/code&gt;, &lt;code&gt;CreateDirectory&lt;/code&gt;, &lt;code&gt;CreateKey&lt;/code&gt;, &lt;code&gt;SetKeyValue&lt;/code&gt;, &lt;code&gt;SetKeySecurity&lt;/code&gt;, &lt;code&gt;DeleteKeyValue&lt;/code&gt;, and &lt;code&gt;DeleteKey&lt;/code&gt;. The verb that does most of the work in a Downdate is &lt;code&gt;HardlinkFile&lt;/code&gt;, because it lets the attacker replace a file in &lt;code&gt;System32&lt;/code&gt; without ever calling &lt;code&gt;WriteFile&lt;/code&gt; against a TrustedInstaller-owned path.&lt;/p&gt;

flowchart TD
    A[&quot;Operator config XML&lt;br /&gt;UpdateFile source dest pairs&quot;] --&amp;gt; B[&quot;Fetch source files&lt;br /&gt;from WinSxS or attacker storage&quot;]
    B --&amp;gt; C[&quot;Emit crafted pending.xml&lt;br /&gt;HardlinkFile + ACL verbs&quot;]
    C --&amp;gt; D[&quot;Write pending.xml&lt;br /&gt;to attacker dir&quot;]
    D --&amp;gt; E[&quot;Compute PendingXmlIdentifier nonce&quot;]
    E --&amp;gt; F[&quot;Write PoqexecCmdline registry value&lt;br /&gt;point at crafted pending.xml&quot;]
    F --&amp;gt; G[&quot;Write PendingXmlIdentifier&quot;]
    G --&amp;gt; H[&quot;Reboot&quot;]
    H --&amp;gt; I[&quot;poqexec.exe reads PoqexecCmdline&quot;]
    I --&amp;gt; J[&quot;Apply HardlinkFile verbs:&lt;br /&gt;ci.dll, ntoskrnl.exe, securekernel.exe,&lt;br /&gt;hvix64.exe, LsaIso.exe replaced&quot;]
    J --&amp;gt; K[&quot;Optional: patch poqexec.exe NOP&lt;br /&gt;and sfc.exe to NOP&quot;]
    K --&amp;gt; L[&quot;System boots: every signature valid,&lt;br /&gt;every component historic&quot;]
&lt;h3&gt;6.2 What got downgraded&lt;/h3&gt;
&lt;p&gt;Each Downdate target is a different layer of the threat model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Afd.sys&lt;/code&gt;&lt;/strong&gt; is the Ancillary Function Driver -- a kernel-mode networking driver. In the Black Hat USA demo, Leviev paired the Downdate of &lt;code&gt;Afd.sys&lt;/code&gt; with CVE-2023-21768 to demonstrate Administrator-to-kernel code execution on a fully patched Windows 11 system [@windowsdowndate-repo].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ntoskrnl.exe&lt;/code&gt;&lt;/strong&gt; is the NT kernel image itself. Downgrade to a build with a public elevation-of-privilege chain and the resulting kernel is still Microsoft-signed but is also still vulnerable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;securekernel.exe&lt;/code&gt;&lt;/strong&gt; is the VTL1 &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel&lt;/a&gt;. It is the keystone of VBS: the Secure Kernel is what HVCI and Credential Guard rely on for isolation. Replace it with an older build that contains a kernel-side bug, and every protection that runs in VTL1 is now running on top of compromised infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hvix64.exe&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;hvax64.exe&lt;/code&gt;&lt;/strong&gt; are the Intel and AMD Hyper-V hypervisor binaries. Downgrade the hypervisor and the entire VBS trust root has moved beneath you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;LsaIso.exe&lt;/code&gt;&lt;/strong&gt; is the Credential Guard Isolated User Mode trustlet [@msdocs-credguard]. It holds the LSA secrets that Credential Guard protects. An older &lt;code&gt;LsaIso.exe&lt;/code&gt; is, by Microsoft&apos;s own threat model, a known-bad binary running inside the security-feature-of-record.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ci.dll&lt;/code&gt;&lt;/strong&gt; is the keystone of the October 2024 follow-up. The kernel-mode Code Integrity module enforces DSE: it is the gate that asks &quot;is this driver signed?&quot; Roll it back to &lt;code&gt;10.0.22621.1376&lt;/code&gt; and Gabriel Landau&apos;s False File Immutability bypass works again on a fully-patched Windows 11.&lt;/p&gt;
&lt;h3&gt;6.3 Bypassing VBS UEFI locks without physical access&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s &quot;VBS UEFI lock&quot; feature, intended to be the strongest configuration of VBS, copies the VBS configuration registry settings into a UEFI non-volatile, boot-services-only variable called &lt;code&gt;VbsPolicy&lt;/code&gt; [@msdocs-vbs-hvci]. Once set, the lock survives reboots, reinstalls, and most ordinary attacks against the registry, because the firmware re-applies it on every boot. Before Windows Downdate, the canonical advice for the highest-security configuration was: turn on VBS with the UEFI lock. The lock was the moat.&lt;/p&gt;
&lt;p&gt;Leviev&apos;s framing of what he showed was direct: &lt;em&gt;&quot;to my knowledge, this is the first time VBS&apos;s UEFI locks have been bypassed without physical access&quot;&lt;/em&gt; [@safebreach-2024-aug].&lt;/p&gt;

To my knowledge, this is the first time VBS&apos;s UEFI locks have been bypassed without physical access. -- Alon Leviev, SafeBreach Labs, August 2024 [@safebreach-2024-aug]
&lt;p&gt;The mechanism is the cleanest possible illustration of the architectural error. The UEFI lock pins &lt;em&gt;configuration&lt;/em&gt; (&lt;code&gt;VbsPolicy&lt;/code&gt;). It does not pin &lt;em&gt;implementation&lt;/em&gt; (&lt;code&gt;securekernel.exe&lt;/code&gt;, &lt;code&gt;hvix64.exe&lt;/code&gt;, &lt;code&gt;LsaIso.exe&lt;/code&gt;, &lt;code&gt;ci.dll&lt;/code&gt;). Downgrade the implementation and the configuration is still happy. From Windows&apos;s point of view, VBS is on, the lock is engaged, the configuration variable is in firmware, everything checks out. The components doing the actual work are simply not the ones the configuration was checked against. Nobody asked it to check.&lt;/p&gt;
&lt;h3&gt;6.4 ItsNotASecurityBoundary, revived&lt;/h3&gt;
&lt;p&gt;On May 14, 2024, Microsoft shipped KB5037771 for Windows 11 22H2 and 23H2 [@landau-itsnotasecurityboundary-repo]. The preview build had landed on April 23, 2024 as KB5036980. The fix closed a False File Immutability TOCTOU on &lt;code&gt;ci.dll&lt;/code&gt; that Gabriel Landau of Elastic Security Labs had disclosed in February [@elastic-ffi]. Landau&apos;s exploit, which he titled &lt;em&gt;ItsNotASecurityBoundary&lt;/em&gt;, used the FFI race to swap an Authenticode catalog mid-verification, getting an unsigned driver loaded with Microsoft&apos;s blessing.&lt;/p&gt;

A bug class identified by Gabriel Landau (Elastic Security Labs) in 2024. Windows treats files mapped as `SEC_IMAGE` as immutable while a view exists, but the kernel does not always honor that immutability across separate reads of the same file. A verifier that reads the file, then re-reads it after a working-set flush, can be served different bytes the second time. On Authenticode catalogs, this becomes a TOCTOU race that lets the attacker swap the catalog between the verifier&apos;s read and the loader&apos;s load.
&lt;p&gt;The October 26, 2024 SafeBreach follow-up [@safebreach-2024-oct], titled &lt;em&gt;An Update on Windows Downdate&lt;/em&gt;, combined the two. It used Windows Downdate to roll &lt;code&gt;ci.dll&lt;/code&gt; back to the pre-May build (&lt;code&gt;10.0.22621.1376&lt;/code&gt;) and re-enabled the FFI bypass on a fully patched Windows 11 23H2 machine [@thehackernews-downdate]. &lt;em&gt;The Hacker News&lt;/em&gt; confirmed the chain: &lt;em&gt;&quot;The DSE bypass is achieved by making use of the downgrade tool to replace the &apos;ci.dll&apos; library with an older version (10.0.22621.1376) to undo the patch put in place by Microsoft&quot;&lt;/em&gt; [@thehackernews-downdate]. The name of Landau&apos;s exploit became, in retrospect, the most pointed commentary on Microsoft&apos;s servicing policy that anyone has written.&lt;/p&gt;

ItsNotASecurityBoundary&apos;s name is an homage to MSRC&apos;s policy that &apos;Administrator-to-kernel is not a security boundary.&apos; -- Gabriel Landau, Elastic Security Labs [@landau-itsnotasecurityboundary-repo]
&lt;h3&gt;6.5 What Microsoft shipped, and when&lt;/h3&gt;
&lt;p&gt;Microsoft&apos;s response unfolded over roughly eleven months. Here is the cadence, anchored to the canonical KB and CVE pages.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&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;Aug 7, 2024&lt;/td&gt;
&lt;td&gt;CVE-2024-21302 and CVE-2024-38202 published; Black Hat USA 2024 talk&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2024-21302; @nvd-cve-2024-38202; @safebreach-2024-aug]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aug 11, 2024&lt;/td&gt;
&lt;td&gt;DEF CON 32 talk&lt;/td&gt;
&lt;td&gt;[@safebreach-2024-aug]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aug 13, 2024&lt;/td&gt;
&lt;td&gt;KB5042562: opt-in &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; revocation policy with optional UEFI lock, plus default-enabled boot-session CI policy on Win10 1507+&lt;/td&gt;
&lt;td&gt;[@kb5042562]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oct 8, 2024&lt;/td&gt;
&lt;td&gt;KB5044284: substantive code fix for CVE-2024-38202 in Windows 11 24H2 (OS Build 26100.2033); per-SKU equivalents on the same date&lt;/td&gt;
&lt;td&gt;[@kb5044284; @nvd-cve-2024-38202]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oct 26, 2024&lt;/td&gt;
&lt;td&gt;SafeBreach follow-up &quot;An Update on Windows Downdate&quot; -- ItsNotASecurityBoundary revival via &lt;code&gt;ci.dll&lt;/code&gt; downgrade&lt;/td&gt;
&lt;td&gt;[@safebreach-2024-oct; @thehackernews-downdate]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jul 8-10, 2025&lt;/td&gt;
&lt;td&gt;CVE-2024-21302 mitigations completed across Windows 10 1507, 1607, 1809, Windows Server 2016, and Windows Server 2018&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2024-21302]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;KB5042562 is the more interesting of the two artifacts. It introduces two mechanisms.&lt;/p&gt;
&lt;p&gt;The first is an &lt;em&gt;opt-in&lt;/em&gt; &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; policy: an administrator copies the Microsoft-signed &lt;code&gt;.p7b&lt;/code&gt; file from &lt;code&gt;%windir%\System32\SecureBootUpdates\&lt;/code&gt; to the EFI System Partition&apos;s &lt;code&gt;\EFI\Microsoft\Boot\&lt;/code&gt; directory; on boot, Windows reads the policy and refuses to load any binary whose version is listed as revoked [@kb5042562].&lt;/p&gt;
&lt;p&gt;The second is a &lt;em&gt;default-enabled&lt;/em&gt; boot-session CI policy that ships to every Windows 10 1507+ device and, per the KB, &lt;em&gt;&quot;will be loaded during boot and the enforcement of this policy will prevent rollback of VBS system files during that boot session&quot;&lt;/em&gt; [@kb5042562]. On Windows 11 24H2 and Server 2022/23H2, DRTM (Dynamic Root of Trust for Measurement) binds the VBS-protected encryption keys to the policy version, so a downgraded boot does not unseal the keys.&lt;/p&gt;

A Microsoft-signed Code Integrity policy file shipped in KB5042562 that lists revoked versions of VBS system files (`securekernel.exe`, `hvix64.exe`/`hvax64.exe`, `LsaIso.exe`, `ci.dll`, and others). When deployed to the EFI System Partition with the optional UEFI lock, it survives reformats and binds version-revocation enforcement to a Microsoft signature in firmware-stored state.

A trusted-launch mechanism, available on Windows 11 24H2 and Server 2022/23H2, that uses CPU SMI / SKINIT instructions to establish a measured execution environment after the OS has begun booting. In KB5042562&apos;s context, DRTM binds Virtual Secure Mode&apos;s protected encryption keys to the version of the active CI policy, so a rolled-back boot session cannot unseal the keys.
&lt;p&gt;{`
// Simulate the construction of the WindowsDowndate config XML for a ci.dll downgrade.
// This shows the structure the tool consumes, not the action list it emits.
// Nothing here writes to a real system or runs a real attack.&lt;/p&gt;
&lt;p&gt;const configEntries = [
  {
    source: &quot;C:\\Windows\\WinSxS\\amd64_microsoft-windows-codeintegrity_31bf3856ad364e35_10.0.22621.1376_none\\ci.dll&quot;,
    destination: &quot;C:\\Windows\\System32\\ci.dll&quot;,
    component: &quot;Code Integrity (kernel DSE enforcement)&quot;,
    targetVersion: &quot;10.0.22621.1376&quot;,
    rationale: &quot;Pre-May-2024 build, before the FFI/ItsNotASecurityBoundary fix&quot;
  }
];&lt;/p&gt;
&lt;p&gt;function buildConfigXml(entries) {
  const lines = [&apos;&apos;, &apos;&apos;];
  for (const e of entries) {
    lines.push(
      &apos;  &amp;lt;UpdateFile source=&quot;&apos; + e.source + &apos;&quot;&apos;,
      &apos;              destination=&quot;&apos; + e.destination + &apos;&quot; /&amp;gt;&apos;
    );
  }
  lines.push(&apos;&apos;);
  return lines.join(&apos;\n&apos;);
}&lt;/p&gt;
&lt;p&gt;const xml = buildConfigXml(configEntries);
console.log(xml);&lt;/p&gt;
&lt;p&gt;// What the tool would emit into the crafted pending.xml on next boot:
console.log(&apos;\nResulting POQ verb (illustrative):&apos;);
console.log(&apos;  &amp;lt;HardlinkFile source=&quot;&apos; + configEntries[0].source + &apos;&quot;&apos;);
console.log(&apos;                destination=&quot;&apos; + configEntries[0].destination + &apos;&quot; /&amp;gt;&apos;);
`}&lt;/p&gt;
&lt;p&gt;The mitigation does not patch the primitive. It patches &lt;em&gt;the components Leviev demonstrated against&lt;/em&gt;, one at a time, with a Microsoft-signed list of historical hashes. That choice is deliberate, and the next two sections are about why.&lt;/p&gt;
&lt;h2&gt;7. Competing Approaches -- How Other Platforms Closed the Gap&lt;/h2&gt;
&lt;p&gt;Android made the opposite design decision in 2017. Apple did so in 2020. The TLS working group did so in 2018. The IETF SUIT working group did so in 2021. By the time Leviev presented at Black Hat USA 2024, every major adjacent platform had treated rollback as a primary threat and shipped a structural fix. Windows was the outlier.&lt;/p&gt;
&lt;h3&gt;Android Verified Boot 2.0: per-partition rollback indices&lt;/h3&gt;
&lt;p&gt;AVB stamps a 64-bit &lt;code&gt;rollback_index&lt;/code&gt; into the signed footer of each partition. On each successful boot of a partition image, the bootloader updates a per-slot stored maximum in TrustZone or in eMMC Replay Protected Memory Block storage. On the next boot, the bootloader refuses any image whose &lt;code&gt;rollback_index&lt;/code&gt; is below the stored maximum [@aosp-avb; @avb-readme].&lt;/p&gt;
&lt;p&gt;The check happens in firmware, before the kernel loads. There is no opt-in. There is no enterprise toggle. There is no operational risk warning about the lock being irreversible. The rollback index is a &lt;em&gt;structural&lt;/em&gt; part of the trust architecture, not a policy file that ships through the same update channel that an attacker would compromise.&lt;/p&gt;
&lt;h3&gt;Apple Sealed System Volume: a Merkle seal over the OS&lt;/h3&gt;
&lt;p&gt;Apple&apos;s Signed System Volume (Big Sur, November 2020) takes the Android approach and pushes it further. SSV computes a SHA-256 hash of every file in the system volume, builds a Merkle tree over those hashes, and signs the root with an Apple key [@apple-ssv].&lt;/p&gt;
&lt;p&gt;The Apple Platform Security guide describes it precisely: &lt;em&gt;&quot;SSV features a kernel mechanism that verifies the integrity of the system content at runtime and rejects any data -- code and noncode -- without a valid cryptographic signature from Apple&quot;&lt;/em&gt; and &lt;em&gt;&quot;Each SSV SHA-256 hash is stored in the main file-system metadata tree, which is itself hashed. Because each node of the tree recursively verifies the integrity of the hashes of its children -- similar to a binary hash (Merkle) tree -- the root node&apos;s hash value, called a seal, encompasses every byte of data in the SSV&quot;&lt;/em&gt; [@apple-ssv]. On iOS and iPadOS, &lt;em&gt;&quot;Users aren&apos;t allowed to turn off the protection of a signed system volume&quot;&lt;/em&gt; [@apple-ssv]. The check is structural and mandatory.&lt;/p&gt;
&lt;h3&gt;IETF SUIT: rollback in the IoT firmware threat model&lt;/h3&gt;
&lt;p&gt;RFC 9019 standardised the firmware-update threat model the IoT industry now treats as canonical. The document does not mince words: &lt;em&gt;&quot;The firmware image is authenticated and integrity protected. Attempts to flash a maliciously modified firmware image or an image from an unknown, untrusted source must be prevented&quot;&lt;/em&gt; [@rfc9019]. The Update Framework&apos;s CCS 2010 paper and its present-day specification share the same vocabulary: &lt;em&gt;&quot;Rollback attacks. An attacker presents files to a software update system that are older than those the client has already seen. With no way to tell it is an obsolete version that may contain vulnerabilities, the user installs the software&quot;&lt;/em&gt; [@tuf-security]. TUF, now a CNCF graduated project, is the academic-canonical reference [@tuf-spec].&lt;/p&gt;
&lt;h3&gt;TLS 1.3: rollback baked into the protocol&lt;/h3&gt;
&lt;p&gt;The protocol world&apos;s answer is in RFC 8446 section 4.1.3 [@rfc8446]. A TLS 1.3 server that detects a downgrade attempt -- a client that supports TLS 1.3 but is being routed through a man-in-the-middle that strips it back to TLS 1.2 -- writes a specific magic constant into the last 8 bytes of &lt;code&gt;ServerHello.random&lt;/code&gt;. A genuine TLS 1.3 client, completing the handshake, checks those bytes and aborts the connection if the magic is present. The integrity check is bound into the transcript hash, so a network attacker cannot rewrite it without breaking the handshake. The mitigation is part of the protocol, not a guideline operators can apply.&lt;/p&gt;

flowchart LR
    A[&quot;Android AVB 2.0&quot;] --&amp;gt; A1[&quot;TrustZone / RPMB&lt;br /&gt;per-slot rollback_index&quot;]
    B[&quot;Apple SSV&quot;] --&amp;gt; B1[&quot;Secure Enclave / T2&lt;br /&gt;signed Merkle root&quot;]
    C[&quot;IETF SUIT (RFC 9019)&quot;] --&amp;gt; C1[&quot;Spec-defined&lt;br /&gt;device-side state&quot;]
    D[&quot;TLS 1.3 (RFC 8446)&quot;] --&amp;gt; D1[&quot;In-protocol&lt;br /&gt;ServerHello.random bytes&quot;]
    E[&quot;TUF&quot;] --&amp;gt; E1[&quot;Snapshot + timestamp roles&lt;br /&gt;monotonic version numbers&quot;]
    F[&quot;Windows SkuSiPolicy.p7b&quot;] --&amp;gt; F1[&quot;EFI System Partition&lt;br /&gt;opt-in UEFI lock&quot;]
    F --&amp;gt; F2[&quot;Boot session only&lt;br /&gt;default-enabled CI policy&quot;]
&lt;p&gt;The differences between these designs are not cosmetic. They are decisions about &lt;em&gt;where the rollback state lives&lt;/em&gt; and &lt;em&gt;who is authorised to write it&lt;/em&gt;. Read the table below row by row and the contrast is uncomfortable.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Windows &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Android AVB 2.0&lt;/th&gt;
&lt;th&gt;Apple SSV&lt;/th&gt;
&lt;th&gt;IETF SUIT&lt;/th&gt;
&lt;th&gt;TUF&lt;/th&gt;
&lt;th&gt;TLS 1.3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Initiation&lt;/td&gt;
&lt;td&gt;Opt-in (strong) / default-enabled (boot-session)&lt;/td&gt;
&lt;td&gt;Mandatory&lt;/td&gt;
&lt;td&gt;Mandatory&lt;/td&gt;
&lt;td&gt;Adopter-defined&lt;/td&gt;
&lt;td&gt;Adopter-defined&lt;/td&gt;
&lt;td&gt;Mandatory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protected unit&lt;/td&gt;
&lt;td&gt;Per-component hash list&lt;/td&gt;
&lt;td&gt;Per-partition signed image&lt;/td&gt;
&lt;td&gt;Whole system volume&lt;/td&gt;
&lt;td&gt;Per-firmware image&lt;/td&gt;
&lt;td&gt;Per-package metadata&lt;/td&gt;
&lt;td&gt;Per-handshake nonce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version-state storage&lt;/td&gt;
&lt;td&gt;EFI System Partition + optional UEFI lock&lt;/td&gt;
&lt;td&gt;TEE / RPMB rollback index&lt;/td&gt;
&lt;td&gt;Secure Enclave / signed root&lt;/td&gt;
&lt;td&gt;Device-side spec&lt;/td&gt;
&lt;td&gt;Snapshot + timestamp roles&lt;/td&gt;
&lt;td&gt;In-protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware-root binding&lt;/td&gt;
&lt;td&gt;Optional via UEFI lock; DRTM on Win11 24H2+&lt;/td&gt;
&lt;td&gt;TrustZone / RPMB&lt;/td&gt;
&lt;td&gt;Apple silicon / T2&lt;/td&gt;
&lt;td&gt;Spec abstract&lt;/td&gt;
&lt;td&gt;Spec abstract&lt;/td&gt;
&lt;td&gt;None required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage gaps&lt;/td&gt;
&lt;td&gt;First-party components not in the policy still load&lt;/td&gt;
&lt;td&gt;Slots not covered by AVB&lt;/td&gt;
&lt;td&gt;None on iOS/iPadOS; SSV must remain on macOS&lt;/td&gt;
&lt;td&gt;Adopter-defined&lt;/td&gt;
&lt;td&gt;Out-of-spec metadata roles&lt;/td&gt;
&lt;td&gt;None within scope&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every other major platform&apos;s modern update architecture treats rollback as a primary threat baked into the trust architecture. Windows treats it as a privilege-boundary question -- and the answer it picked, &quot;Administrator-to-kernel is not a security boundary,&quot; excludes the most common attacker.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If Apple, Google, and the IETF have all figured out the answer, why hasn&apos;t Microsoft?&lt;/p&gt;
&lt;h2&gt;8. Theoretical Limits -- &quot;Admin-to-Kernel Is Not a Boundary&quot;&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s answer is that they have no need to.&lt;/p&gt;
&lt;h3&gt;8.1 The Microsoft position&lt;/h3&gt;
&lt;p&gt;The Windows Security Servicing Criteria is the public document where Microsoft enumerates which Windows interfaces it treats as security boundaries [@msft-servicing-criteria]. The document defines the concept: a security boundary provides a logical separation between the code and data of security domains with different levels of trust, with kernel-mode versus user-mode as the canonical example.&lt;/p&gt;
&lt;p&gt;It then asks the servicing test: &lt;em&gt;&quot;Does the vulnerability violate the goal or intent of a security boundary or a security feature?&quot;&lt;/em&gt; [@msft-servicing-criteria]. If the answer is yes, Microsoft commits to ship a security update. If the answer is no, the issue can still be fixed -- in a quality update, in a refactor, in a future feature -- but it does not get a CVE and the standardised servicing cadence does not apply.&lt;/p&gt;
&lt;p&gt;The boundaries Microsoft enumerates in that document include network boundaries (machine-to-machine), kernel-mode-to-user-mode separation, hypervisor-to-VM separation, and several others. &lt;strong&gt;Administrator-to-kernel is not on the list.&lt;/strong&gt; By the document&apos;s own logic, an Administrator who reaches kernel code execution has not crossed a boundary, because the document does not declare a boundary there for them to cross. That is the policy position Landau&apos;s exploit title was named after.&lt;/p&gt;
&lt;p&gt;The two CVEs that &lt;em&gt;were&lt;/em&gt; assigned are the boundary-crossing parts of the chain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2024-21302&lt;/strong&gt; is the Secure Kernel Mode Elevation of Privilege (VTL0-to-VTL1) -- a downgrade-induced compromise of &lt;code&gt;securekernel.exe&lt;/code&gt; does cross a defined boundary, because the kernel-to-Secure-Kernel separation is on the list [@nvd-cve-2024-21302]. &lt;strong&gt;CVE-2024-38202&lt;/strong&gt; is the basic-user-to-Administrator elevation via the restore-point flow -- a basic user induced into authorising a system restore can be parked into a state that triggers a downgrade, which crosses the user-to-admin boundary [@nvd-cve-2024-38202]. Both CVEs were assigned and patched from August 7, 2024 onward; CVE-2024-38202 received its substantive code fix on October 8, 2024 [@kb5044284; @nvd-cve-2024-38202].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft assigned CVE-2024-21302 (Secure Kernel EoP) and CVE-2024-38202 (basic-user-induced restore-point EoP) on August 7, 2024 and patched both. What Microsoft has &lt;em&gt;not&lt;/em&gt; committed to fix as a security vulnerability is the underlying Downdate primitive itself -- the Administrator-context modification of &lt;code&gt;PoqexecCmdline&lt;/code&gt;. Per the Servicing Criteria, that primitive does not cross a declared boundary [@safebreach-2024-oct; @msft-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Leviev quoted Microsoft&apos;s framing of this distinction in his October 2024 follow-up:&lt;/p&gt;

CVE-2024-21302 was patched because it crossed a defined security boundary, the Windows Update takeover which was reported to Microsoft as well, has remained unpatched, as it did not cross a defined security boundary. Gaining kernel code execution as an Administrator is not considered as crossing a security boundary (not a vulnerability). -- Alon Leviev, summarising the Microsoft position, October 2024 [@safebreach-2024-oct]
&lt;h3&gt;8.2 The internal tension&lt;/h3&gt;
&lt;p&gt;That position has an obvious problem. The VBS documentation says VBS &lt;em&gt;assumes the kernel can be compromised&lt;/em&gt; [@msdocs-vbs]. The Secure Kernel exists because the NT kernel is, in the threat model VBS publishes, untrusted. If the kernel is the attacker, then anyone who can compromise the kernel is the attacker VBS is designed to mitigate. On a single-user Windows machine, the obvious path to kernel compromise is to be an Administrator and load a vulnerable signed driver, or to be an Administrator and exploit a kernel race, or to be an Administrator and downgrade &lt;code&gt;ci.dll&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Leviev makes the point directly in the same blog post: &lt;em&gt;&quot;the reason VBS was created is because the kernel is assumed compromised, and there was a need for a secure place to implement security features&quot;&lt;/em&gt; [@safebreach-2024-aug]. If the kernel is &lt;em&gt;assumed&lt;/em&gt; compromised in VBS&apos;s threat model, then the Administrator who can compromise the kernel is precisely the attacker VBS was built to mitigate -- which makes Microsoft&apos;s servicing-criteria position and VBS&apos;s threat model load-bearing on opposite sides of the same boundary.&lt;/p&gt;
&lt;p&gt;This is the article&apos;s most argumentative sentence: the position is not a &lt;em&gt;security&lt;/em&gt; decision (the primitive is not a vulnerability) but a &lt;em&gt;resourcing&lt;/em&gt; decision (we will not CVE the primitive, but we will harden it). The per-component &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; rollout, the default-enabled boot-session CI policy, DRTM on Win11 24H2+, and the multi-quarter cleanup across Windows 10 1507 through Windows Server 2018 are exactly what one would expect from an organisation patching a &lt;em&gt;class&lt;/em&gt; one component at a time, while declining to declare the class.&lt;/p&gt;
&lt;h3&gt;8.3 What a hardened position would look like&lt;/h3&gt;
&lt;p&gt;The fixes are not conceptually hard. Microsoft could:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Sign &lt;code&gt;poqexec.exe&lt;/code&gt; and &lt;code&gt;sfc.exe&lt;/code&gt; with HVCI-enforced integrity.&lt;/strong&gt; That removes the persistence and irreversibility steps of the chain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Move &lt;code&gt;PoqexecCmdline&lt;/code&gt; under a TrustedInstaller-only DACL with a UEFI-bound mirror.&lt;/strong&gt; That removes the registry pivot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Introduce a monotonic update-generation counter in the TPM, bound to a transcript hash of the cumulative-update history, consulted by the boot manager and the Secure Kernel.&lt;/strong&gt; That is the architectural fix -- the version of the answer Apple and Android shipped.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The current &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; mechanism is the &lt;em&gt;first step&lt;/em&gt; on the third path. It is per-component and opt-in for the strong variant, but the conceptual shape is right: a Microsoft-signed list of historical hashes, consulted by the kernel loader, with a UEFI-bound anchor for the strong configuration [@kb5042562]. The work is real, and it is well-executed within the constraints Microsoft has set itself. The question is whether the constraints will give. Whether the policy will eventually cover every Microsoft-shipped binary with a known EoP. Whether the strong variant will become the default. Whether Administrator-to-kernel will be declared a security boundary in the published criteria.&lt;/p&gt;

The one VBS configuration that Leviev has not bypassed is the &quot;Mandatory&quot; flag (the `HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Mandatory` REG_DWORD value, mirrored into the `VbsPolicy` UEFI variable on next boot). When set in combination with the UEFI lock, the flag causes boot failure if any VBS-protected binary is corrupted -- so the &quot;invalidate `securekernel.exe`, boot without VBS, downgrade `ci.dll`&quot; trick that defeats the ordinary UEFI lock no longer works. Leviev&apos;s October 2024 follow-up is blunt: *&quot;I have not found a way around this&quot;* [@safebreach-2024-oct].&lt;p&gt;The catches are operational. The Mandatory flag is not set by default when the UEFI lock is enabled; it has to be set manually. Once set with the UEFI lock, the VBS configuration cannot be modified -- the lock must be deleted via &lt;code&gt;SecConfig.efi&lt;/code&gt;, the flag set, and the lock re-enabled.&lt;/p&gt;
&lt;p&gt;There is also a real boot-reliability risk: any update that corrupts a VBS-protected binary on a Mandatory-flagged machine will brick the boot, with no error displayed beyond the firmware silently moving to the next boot option [@safebreach-2024-oct; @kb5042562]. Microsoft documented the Mandatory flag in September 2024, after Leviev&apos;s findings, but has not made it the default [@msdocs-vbs-hvci]. Few production machines run with it.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;These are not conceptually hard. They are organisationally hard, because they require Microsoft to ship a &lt;em&gt;new&lt;/em&gt; security boundary, declared as such, after declining to do so for nearly two decades.&lt;/p&gt;
&lt;h2&gt;9. Open Problems -- What the August 2024 Cadence Left Open&lt;/h2&gt;
&lt;p&gt;If you are reading this in 2026, the parts of Windows Downdate that Microsoft chose to call vulnerabilities have been patched. The parts they chose not to call vulnerabilities are exactly as exploitable today as they were on August 7, 2024.&lt;/p&gt;
&lt;p&gt;The general primitive remains. The Administrator-context modification of &lt;code&gt;PoqexecCmdline&lt;/code&gt; is, by Microsoft&apos;s stated policy, intentionally unpatched [@safebreach-2024-oct]. Every cumulative update Microsoft ships will continue to flow through the same servicing-stack path that Leviev hijacked, because that path is the path everything else depends on. The fix has to come from somewhere else.&lt;/p&gt;
&lt;h3&gt;Components not yet in the revocation policy&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; covers the VBS-protected components Leviev demonstrated against -- &lt;code&gt;securekernel.exe&lt;/code&gt;, &lt;code&gt;hvix64.exe&lt;/code&gt;, &lt;code&gt;hvax64.exe&lt;/code&gt;, &lt;code&gt;LsaIso.exe&lt;/code&gt;, &lt;code&gt;ci.dll&lt;/code&gt;, and others. It does not cover every Microsoft-shipped DLL or driver with a public EoP history [@kb5042562]. Each Microsoft binary outside the policy that has a known kernel-relevant vulnerability is, in principle, a Downdate target. The inventory is open. Microsoft does not publish &quot;the set of historical hashes of &lt;code&gt;ntoskrnl.exe&lt;/code&gt; that we consider unsafe to load&quot; -- and the absence of that list is the absence of the version-monotonicity boundary at scale.&lt;/p&gt;
&lt;h3&gt;Hot Patching as a parallel servicing surface&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://paragmali.com/blog/from-hotpatch-to-150-a-core-the-live-patch-pipeline-microsof/&quot; rel=&quot;noopener&quot;&gt;Hot Patching&lt;/a&gt; is the Windows servicing variant that applies code-level updates to running processes without a reboot. It reached general availability on Windows Server 2022 Datacenter: Azure Edition in February 2022 (Server Core) and July 2023 (Desktop Experience), and on Windows 11 Enterprise 24H2 in April 2025 via Microsoft Autopatch and Intune [@msdocs-hotpatch-server; @msdocs-hotpatch-win11].&lt;/p&gt;
&lt;p&gt;Its threat model is &lt;em&gt;forward-delta application&lt;/em&gt;: how do we apply a code patch to a running binary safely? It does not consider &lt;em&gt;rollback prevention&lt;/em&gt; as a separate concern. Whether the hot-patch path admits its own rollback primitive -- whether you can roll back a hot patch, restoring the older code into the running process, by abusing the hot-patch infrastructure the same way Downdate abuses CBS -- is an open question that nobody has publicly answered.&lt;/p&gt;
&lt;h3&gt;WinRE as adjacent surface&lt;/h3&gt;
&lt;p&gt;Leviev&apos;s Black Hat USA 2025 talk, with Netanel Ben Simon of Microsoft&apos;s MORSE team, did not extend Downdate. It went sideways. &lt;em&gt;BitUnlocker: Leveraging Windows Recovery to Extract BitLocker Secrets&lt;/em&gt; targeted 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;Windows Recovery Environment&lt;/a&gt;, demonstrating four CVEs that together permit a physical-access attacker to extract BitLocker keys from the WinRE servicing surface [@itnews-bitunlocker; @infocondb-defcon33-bitunlocker]. The bugs were patched in the July 2025 Patch Tuesday cumulative updates.&lt;/p&gt;

The corrected CVE-to-file mapping, per the iTnews coverage and the independent garatc/BitUnlocker proof-of-concept, is:
- **CVE-2025-48804**: SDI / `Boot.sdi` parsing -- the boot-manager downgrade keystone that garatc&apos;s PoC chains to access BitLocker-encrypted disks in under five minutes on fully patched Windows 11 [@itnews-bitunlocker; @garatc-bitunlocker].
- **CVE-2025-48800**: Offline Scanning -- abuses the legitimately-signed time-travel debugger `tttracer.exe` to proxy-execute `cmd.exe` against BitLocker-encrypted volumes without triggering the recovery-mode re-lock.
- **CVE-2025-48003**: `SetupPlatform.exe` and the Shift+F10 path via `ReAgent.xml`.
- **CVE-2025-48818**: BCD-store complete-chain exploit.&lt;p&gt;BitUnlocker is not a continuation of Windows Downdate. It is the same meta-pattern in a different servicing surface: WinRE is a servicing path inherited from a less hostile era, and Microsoft is now patching its threat model. The shape of the work is identical.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Alon Leviev now works on the Microsoft Offensive Research and Security Engineering (MORSE) team alongside Netanel Ben Simon. Leviev&apos;s institutional follow-up to Downdate is therefore happening from inside Microsoft -- a notable signal about how seriously Microsoft is taking the surface even as it declines to declare the boundary [@infocondb-defcon33-bitunlocker].&lt;/p&gt;
&lt;h3&gt;Two revocation policies, one product&lt;/h3&gt;
&lt;p&gt;The Microsoft Vulnerable Driver Blocklist (for third-party kernel code) and &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; (for first-party VBS system files) are &lt;em&gt;two separate revocation policies&lt;/em&gt; that ship on different cadences, in different formats, and through different update channels. The Driver Blocklist updates quarterly and via monthly cumulative updates [@msdocs-driver-blocklist]; &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; is shipped as part of major mitigation rollouts and is opt-in for the strong variant [@kb5042562]. Whether Microsoft unifies them -- whether the eventual answer is one unified hash-revocation policy covering all kernel-loaded code, Microsoft-shipped or not -- is an open architectural question.&lt;/p&gt;
&lt;h3&gt;Linux desktop coverage&lt;/h3&gt;
&lt;p&gt;The image-based Linux distributions (Fedora Silverblue, Ubuntu Core, openSUSE MicroOS) have all moved toward AVB-style or SSV-style architectures. Classical &lt;code&gt;dpkg&lt;/code&gt;- and &lt;code&gt;rpm&lt;/code&gt;-based distributions have not. Apt&apos;s package authentication is signature-based and largely version-aware via the &lt;code&gt;Release&lt;/code&gt; file&apos;s &lt;code&gt;Date&lt;/code&gt; and &lt;code&gt;Valid-Until&lt;/code&gt; headers, but the security guarantees rely on a trusted repository and a TUF-style snapshot role that most distributions do not yet ship. The Windows lesson generalises: any update mechanism that can write into a higher-privilege domain has to enforce version monotonicity in the same domain that performs the write.&lt;/p&gt;
&lt;p&gt;There is one open problem the rest depend on. &lt;em&gt;Will Microsoft declare a version-monotonicity security boundary?&lt;/em&gt; The answer to that question -- whether by a future revision of the Windows Security Servicing Criteria, by a default-on Mandatory flag, by an exhaustive first-party Driver Block List equivalent, or by something nobody has prototyped yet -- is the substantive resolution of the story. The August 2024 patches were not it.&lt;/p&gt;
&lt;h2&gt;10. A Practical Guide for Defenders, Detection Engineers, and System Designers&lt;/h2&gt;
&lt;p&gt;Three audiences, three concrete tracks.&lt;/p&gt;
&lt;h3&gt;10.1 Defenders&lt;/h3&gt;
&lt;p&gt;If you operate Windows 10 or 11 endpoints, the first thing to do is apply the cumulative updates that contain the substantive code fix for CVE-2024-38202. On Windows 11 24H2, that is KB5044284 (October 8, 2024, OS Build 26100.2033) [@kb5044284]. On older SKUs, the equivalent updates landed on the same date or in the multi-quarter sweep that completed July 8-10, 2025 across Windows 10 1507, 1607, 1809, Server 2016, and Server 2018 [@nvd-cve-2024-21302]. Apply them in your normal patch ring with no special handling.&lt;/p&gt;
&lt;p&gt;The second thing to do is keep HVCI / memory integrity enabled so the default-enabled boot-session CI policy and the Vulnerable Driver Blocklist both fire [@msdocs-driver-blocklist; @msdocs-vbs-hvci]. On Windows 11 22H2 and later, both are on by default. On older SKUs, they are not, and the gap is meaningful.&lt;/p&gt;
&lt;p&gt;The third thing -- the one that requires care -- is to consider deploying &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; with the optional UEFI lock where your operational risk tolerance allows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s own KB is unambiguous about what happens if you apply the UEFI lock and later try to roll back: &lt;em&gt;&quot;If the UEFI lock is applied and the policy is removed or replaced with an older version, the Windows boot manager will not start, and the device will not start... Even reformatting the disk will not remove the UEFI lock of the mitigation if it has already been applied&quot;&lt;/em&gt; [@kb5042562]. Disable Secure Boot to remove the lock. Test on a pilot ring before deploying broadly. Back up BitLocker recovery keys first. Verify that the Windows Recovery Environment is updated to the latest Safe OS Dynamic Update (released July 8, 2025) before applying [@kb5042562].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A safe deployment plan: (1) pick a pilot ring of representative hardware; (2) verify each pilot machine has the July 8, 2025 WinRE Safe OS Dynamic Update applied; (3) back up BitLocker recovery keys to a secondary store you control; (4) deploy &lt;code&gt;SkuSiPolicy.p7b&lt;/code&gt; from &lt;code&gt;%windir%\System32\SecureBootUpdates\&lt;/code&gt; to the EFI System Partition&apos;s &lt;code&gt;\EFI\Microsoft\Boot\&lt;/code&gt; directory &lt;em&gt;without&lt;/em&gt; the UEFI lock first; (5) verify boot integrity for several reboot cycles; (6) apply the UEFI lock; (7) confirm no other CI policy is being shipped that conflicts; (8) graduate the policy to the wider fleet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally: the VBS &quot;Mandatory&quot; flag (&lt;code&gt;HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Mandatory&lt;/code&gt;) is the only configuration Leviev has not bypassed [@safebreach-2024-oct]. Set it where boot reliability is acceptable and you have rehearsed the recovery procedure (&lt;code&gt;SecConfig.efi&lt;/code&gt; to delete the lock, the flag set, the lock re-enabled). Inventory the count of Administrator accounts on each machine -- the Downdate primitive&apos;s blast radius is bounded by the number of identities that can write &lt;code&gt;PoqexecCmdline&lt;/code&gt;. Every reduction in that count is a direct reduction in the attack surface.&lt;/p&gt;
&lt;h3&gt;10.2 Detection engineers&lt;/h3&gt;
&lt;p&gt;The detection signature is the registry pivot. Authenticode-based file-integrity tooling will &lt;em&gt;not&lt;/em&gt; catch Windows Downdate, because the downgraded files are legitimately Microsoft-signed [@safebreach-2024-aug]. The Splunk Security Content &lt;code&gt;windows_downdate_registry_activity&lt;/code&gt; analytic is the canonical reference detection [@splunk-downdate-detection]. The logic is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consume Sysmon EventIDs 12, 13, and 14 (Registry creation, set-value, and rename).&lt;/li&gt;
&lt;li&gt;Match &lt;code&gt;TargetObject&lt;/code&gt; against &lt;code&gt;*PoqexecCmdline&lt;/code&gt; or &lt;code&gt;*COMPONENTS\PendingXmlIdentifier&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Suppress writes whose calling &lt;code&gt;ProcessPath&lt;/code&gt; is under &lt;code&gt;*:\Windows\WinSxS\*&lt;/code&gt; (the legitimate-update path).&lt;/li&gt;
&lt;li&gt;Map to MITRE ATT&amp;amp;CK T1112 (Modify Registry, Defense Impairment) and T1689 (Downgrade Attack, Persistence/Exploitation/Installation).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Splunk detection is &lt;em&gt;disabled by default&lt;/em&gt; in Splunk Enterprise Security. Operators must enable it explicitly [@splunk-downdate-detection]. The point of attack on the EDR side is the registry pivot, not the file substitution -- the substitution looks like a normal update because, by every check Windows performs, it is one.&lt;/p&gt;
&lt;p&gt;{`
// Demonstrates the decision logic of the windows_downdate_registry_activity detection.
// Not a real Sysmon parser -- the inputs would be Event 12/13/14 records in production.&lt;/p&gt;
&lt;p&gt;function isLegitimateUpdatePath(processPath) {
  // Legitimate Windows Update operations run under WinSxS.
  return processPath.toLowerCase().includes(&apos;\\windows\\winsxs\\&apos;);
}&lt;/p&gt;
&lt;p&gt;function classifyRegistryWrite(event) {
  const sensitiveValues = [
    &apos;PoqexecCmdline&apos;,
    &apos;COMPONENTS\\PendingXmlIdentifier&apos;
  ];&lt;/p&gt;
&lt;p&gt;  const matchesSensitive = sensitiveValues.some(v =&amp;gt;
    event.TargetObject.endsWith(v)
  );&lt;/p&gt;
&lt;p&gt;  if (!matchesSensitive) return &apos;ignore&apos;;
  if (isLegitimateUpdatePath(event.ProcessPath)) return &apos;allow&apos;;
  return &apos;alert&apos;;
}&lt;/p&gt;
&lt;p&gt;const sample = [
  { TargetObject: &apos;HKLM\\...\\PoqexecCmdline&apos;, ProcessPath: &apos;C:\\Windows\\WinSxS\\amd64_x\\TrustedInstaller.exe&apos; },
  { TargetObject: &apos;HKLM\\...\\PoqexecCmdline&apos;, ProcessPath: &apos;C:\\Users\\alice\\Desktop\\windows_downdate.exe&apos; },
  { TargetObject: &apos;HKLM\\...\\COMPONENTS\\PendingXmlIdentifier&apos;, ProcessPath: &apos;C:\\tools\\suspicious.exe&apos; }
];&lt;/p&gt;
&lt;p&gt;for (const ev of sample) {
  console.log(classifyRegistryWrite(ev), &apos;&amp;lt;-&apos;, ev.ProcessPath);
}
`}&lt;/p&gt;

The Splunk detection only watches the two registry pivots. A more aggressive variant also watches for unexpected `pending.xml` files appearing outside `C:\Windows\WinSxS\` and for file integrity changes against expected hashes of `poqexec.exe` and `sfc.exe`. The trade-off is false positives: enterprise patch tooling and configuration-management agents touch the servicing path more often than you would expect, and an aggressive variant requires tuning before it is fleet-ready.
&lt;h3&gt;10.3 System designers&lt;/h3&gt;
&lt;p&gt;If you are building a new operating system in 2026, you do not have an excuse. The architectural takeaway from Windows Downdate is general: &lt;em&gt;any update mechanism that can write into a higher-privilege domain must enforce version monotonicity in the same domain that performs the write.&lt;/em&gt; If the update is processed by a TrustedInstaller-context service, version monotonicity has to be enforced by TrustedInstaller (or by something even further from the attacker -- the boot manager, the firmware, the TPM). If the version-state pointer lives in a registry value an Administrator can rewrite, the boundary moves and the design is broken.&lt;/p&gt;
&lt;p&gt;Concrete reference patterns are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TPM-stored generation counters.&lt;/strong&gt; Bind the counter to a transcript hash of the cumulative-update history; the boot manager and Secure Kernel refuse to load components older than the stored counter [@tuf-spec]. This is the Apple SSV / Android AVB pattern translated into Windows-shaped trust roots.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monotonic catalog versions.&lt;/strong&gt; Sign the per-component catalog with an explicit &lt;code&gt;&amp;lt;min-version&amp;gt;&lt;/code&gt; field; the kernel loader refuses to load any catalog whose &lt;code&gt;&amp;lt;min-version&amp;gt;&lt;/code&gt; is below the loader&apos;s stored maximum. This is the TUF snapshot-role pattern [@tuf-spec].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In-protocol monotonicity at the update edge.&lt;/strong&gt; Use the IETF SUIT envelope format and the &lt;code&gt;seq-num&lt;/code&gt; field defined in RFC 9019 [@rfc9019]. The receiver tracks the highest sequence number it has seen and refuses lower ones at the spec level, not the policy level.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reference designs exist. TUF [@tuf-spec], IETF SUIT [@rfc9019], and AOSP AVB [@aosp-avb] are open. Pick one. Adapt it. Ship it. The hard part is not the engineering. The hard part is the institutional commitment to declaring a security boundary you did not declare last year.&lt;/p&gt;
&lt;p&gt;If you are building a new OS in 2026, you do not have an excuse.&lt;/p&gt;
&lt;h2&gt;11. Misconceptions, Corrections, and What Comes Next&lt;/h2&gt;
&lt;p&gt;Windows Downdate spawned a press cycle that got several things wrong. Here is what is actually true.&lt;/p&gt;

No. The substantive code fix for CVE-2024-38202 (the basic-user-induced restore-point variant) shipped on **October 8, 2024** as KB5044284 for Windows 11 24H2 and OS Build 26100.2033, with per-SKU equivalents on the same date [@kb5044284; @nvd-cve-2024-38202]. The earlier mitigation guidance, KB5042562 (the opt-in `SkuSiPolicy.p7b` policy and the default-enabled boot-session CI policy), shipped on August 13, 2024 [@kb5042562]. There is no November 2024 anchor. The multi-quarter cleanup across older SKUs completed July 8-10, 2025 [@nvd-cve-2024-21302].

No. *Secure Boot* bypass via downgrade is BlackLotus (CVE-2022-21894, &quot;Baton Drop&quot;), which used a vulnerable Microsoft-signed `bootmgfw.efi` that was not in the UEFI `dbx` revocation list [@welivesecurity-blacklotus]. Windows Downdate bypasses *VBS UEFI locks* and downgrades the VBS-protected components (`securekernel.exe`, `hvix64.exe`, `LsaIso.exe`, `ci.dll`) along with the NT kernel itself [@safebreach-2024-aug]. The two attacks operate at different layers: BlackLotus at the firmware/boot manager, Downdate at the OS component layer. The mechanism shape is similar; the targets are distinct.

No. *ItsNotASecurityBoundary* is Gabriel Landau&apos;s (Elastic Security Labs) exploit name for a False File Immutability TOCTOU on `ci.dll`, disclosed in early 2024 and patched in **May 14, 2024 (KB5037771)** with a preview build on April 23, 2024 (KB5036980) [@landau-itsnotasecurityboundary-repo; @elastic-ffi]. Leviev&apos;s October 26, 2024 SafeBreach follow-up *revived* Landau&apos;s exploit by using Windows Downdate to roll `ci.dll` back to the pre-May build [@safebreach-2024-oct]. Leviev&apos;s actual Black Hat USA 2025 talk, with Netanel Ben Simon, was **BitUnlocker**, on Windows Recovery Environment attacks -- patched in July 2025 Patch Tuesday [@itnews-bitunlocker; @infocondb-defcon33-bitunlocker].

No. Microsoft assigned and patched both CVEs from disclosure day (August 7, 2024) onward [@nvd-cve-2024-21302; @nvd-cve-2024-38202]. The position that Microsoft *has* taken is narrower: the underlying *primitive* (the Administrator-context modification of `PoqexecCmdline` that the Downdate technique relies on) has remained unpatched because it does not cross a defined security boundary in the published Windows Security Servicing Criteria [@safebreach-2024-oct; @msft-servicing-criteria]. The two assigned CVEs are the *boundary-crossing parts* of the chain. The unassigned primitive is the part that runs on each side of the boundary that nobody declared.

No. Authenticode does what it says: it verifies that a binary was signed by a specific certificate (and that the certificate chains to a trusted root). The older `ci.dll` that Windows Downdate installs is legitimately signed by Microsoft. Authenticode never claimed to assert &quot;and is the current version&quot; -- it is a *signature* check, not a *staleness* check [@safebreach-2024-aug; @msdocs-driver-signing]. The mistake is in the design above Authenticode that treats signature validity as equivalent to current-version-validity, not in Authenticode itself.

Per Leviev&apos;s claim in the August 2024 SafeBreach blog, `poqexec.exe` is not Authenticode-signed in the affected Windows builds, and neither is `sfc.exe` [@safebreach-2024-aug]. The persistence step of Windows Downdate exploits this directly: replacing `poqexec.exe` with a patched copy that NOPs future updates does not require a code-signing bypass. The hardening suggested in section 8 -- sign both binaries, enforce HVCI on them -- removes the persistence and irreversibility steps, but signing alone is not sufficient: the `PoqexecCmdline` registry pivot survives signing, because the pivot points the *legitimately signed* `poqexec.exe` at an attacker-chosen action list.

EDR coverage focuses on the known indicators: registry writes to `PoqexecCmdline` and `PendingXmlIdentifier` by processes that are not under `C:\Windows\WinSxS\`, and unexpected `pending.xml` files outside the TrustedInstaller-only directories [@splunk-downdate-detection]. The downgrade itself, once executed, is by design indistinguishable from a legitimate update at the file-signature layer. Whether a given EDR product has shipped a detection for the registry pivot is product-specific; the Splunk Security Content analytic referenced above is the cleanest published reference signature [@splunk-downdate-detection]. Microsoft Defender for Endpoint operators should verify with their account team that an equivalent detection is enabled in their tenant.
&lt;p&gt;Microsoft built a security boundary in 2007 that depended on the assumption that updates only move forward. We now know they do not. The work of declaring the new boundary -- one component, one SKU, one cumulative update at a time -- is what Microsoft is doing right now. Whether the boundary will eventually be declared in the Windows Security Servicing Criteria, rather than implemented quietly as a per-component policy, is the question whose answer we will know in 2027.&lt;/p&gt;
&lt;p&gt;For now, the lesson is portable. The shape of Windows Downdate generalises: every signed-update system needs a version-monotonicity primitive co-located with the trust root that enforces signatures. The reason it took until 2024 to demonstrate this on Windows is not that the bug was deep. It is that nobody, in eighteen years of Windows servicing engineering, had been asked to declare the boundary the bug crossed. Once Leviev asked the question, the answer wrote itself.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;windows-downdate-when-the-update-itself-is-the-attack&quot; keyTerms={[
  { term: &quot;TrustedInstaller&quot;, definition: &quot;A Windows security principal introduced in Vista that owns most system files. ACLs deny direct write to other principals, including Administrators.&quot; },
  { term: &quot;Component-Based Servicing (CBS)&quot;, definition: &quot;The Vista-era Windows servicing architecture that replaced self-extracting installers with manifest-and-catalog-driven transactions over a versioned component store (WinSxS).&quot; },
  { term: &quot;poqexec.exe&quot;, definition: &quot;The post-reboot Primitive Operations Queue executor. Reads pending.xml at next boot and applies its verbs (HardlinkFile, MoveFile, ...).&quot; },
  { term: &quot;PoqexecCmdline&quot;, definition: &quot;The Administrator-writable registry value that tells poqexec.exe which pending.xml to parse on next boot. The Windows Downdate primitive.&quot; },
  { term: &quot;SkuSiPolicy.p7b&quot;, definition: &quot;A Microsoft-signed Code Integrity policy that revokes specific versions of VBS system files. Shipped in KB5042562, August 2024.&quot; },
  { term: &quot;VBS UEFI lock&quot;, definition: &quot;A configuration mode for Virtualization-Based Security that pins the VBS configuration into a UEFI non-volatile variable. Pins configuration, not implementation.&quot; },
  { term: &quot;DRTM&quot;, definition: &quot;Dynamic Root of Trust for Measurement. On Win11 24H2+, binds Virtual Secure Mode protected keys to the active CI policy version.&quot; },
  { term: &quot;False File Immutability (FFI)&quot;, definition: &quot;Gabriel Landau&apos;s bug class. Windows treats SEC_IMAGE-mapped files as immutable, but the kernel does not consistently honor that immutability across separate reads -- enabling TOCTOU on catalogs.&quot; }
]} questions={[
  { q: &quot;Why does Leviev&apos;s attack succeed even though every binary Windows loads is legitimately Microsoft-signed?&quot;, a: &quot;Because Authenticode and the CBS catalog-trust model assert signature validity, not version currency. A 2022 ci.dll is signed by the same Microsoft key as a 2024 ci.dll.&quot; },
  { q: &quot;Which registry value is the pivot at the heart of Windows Downdate, and what is its ACL?&quot;, a: &quot;HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide\Configuration\PoqexecCmdline. The DACL allows Administrator write, breaking the TrustedInstaller-only chain of custody for the action list pointer.&quot; },
  { q: &quot;What does the VBS UEFI lock pin, and what does it not pin?&quot;, a: &quot;It pins VBS configuration (the VbsPolicy UEFI variable). It does not pin VBS implementation (securekernel.exe, hvix64.exe, LsaIso.exe, ci.dll). Downgrading the implementation while leaving the configuration alone is the attack.&quot; },
  { q: &quot;How is the rollback-defence story different on Android and Apple platforms?&quot;, a: &quot;Android AVB stores per-partition rollback indices in TrustZone or RPMB. Apple SSV signs a Merkle tree over the whole system volume. Both are structural and mandatory. Windows SkuSiPolicy.p7b is shipped via the same update channel as the components it protects, with an opt-in UEFI lock for the strong variant.&quot; },
  { q: &quot;Why does Microsoft consider the underlying Downdate primitive (modifying PoqexecCmdline) not a security vulnerability?&quot;, a: &quot;Because the Windows Security Servicing Criteria does not enumerate Administrator-to-kernel as a security boundary. Per Microsoft&apos;s published policy, gaining kernel code execution as an Administrator does not violate the goal or intent of any declared boundary, so the primitive falls outside the servicing-CVE process.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>downgrade-attack</category><category>vbs</category><category>hvci</category><category>windows-update</category><category>security-boundary</category><category>patch-management</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Windows Sandbox vs Windows Defender Application Guard: Two Hyper-V Sandboxes, Different Threat Models</title><link>https://paragmali.com/blog/windows-sandbox-vs-wdag/</link><guid isPermaLink="true">https://paragmali.com/blog/windows-sandbox-vs-wdag/</guid><description>Two Hyper-V-backed isolation containers shipped in Windows -- one survived, one was retired. The story of why disposable beat persistent, and what each model was actually for.</description><pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Two Windows features, the same plumbing, opposite fates.** Windows Sandbox (2019) and Windows Defender Application Guard (2017) both spin up a Hyper-V child partition using the Host Compute Service (HCS) API [@learn-microsoft-com-hcs-overview] on top of the same Virtualization-Based Security [@learn-microsoft-com-oem-vbs] substrate. Sandbox is disposable, on-demand, and aimed at running an untrusted executable. WDAG was persistent, automatic, and aimed at rendering an untrusted website inside Microsoft Edge. WDAG was deprecated for Edge [@learn-microsoft-com-application-guard] and then removed entirely in Windows 11 24H2 [@learn-microsoft-com-guard-overview]; Sandbox still ships. The reason is not that one model was wrong -- it is that operational economics and threat models diverged. This article explains the shared substrate, the architectural differences, the deprecation story, and what replaced WDAG in the 2026 Windows isolation stack.
&lt;h2&gt;1. The Hyper-V Isolation Layer Both Features Share&lt;/h2&gt;
&lt;p&gt;Open two Microsoft Learn pages side by side -- the Windows Sandbox architecture page [@learn-microsoft-com-sandbox-architecture] and the Microsoft Defender Application Guard overview [@learn-microsoft-com-guard-overview] -- and the descriptions almost rhyme. The MDAG overview opens by calling its container an &quot;isolated Hyper-V-enabled container&quot;; the Sandbox architecture page describes its guest as a dynamically generated, &quot;kernel-isolated&quot; Windows image that the host can destroy. Two pages, two teams, the same noun and the same verb. The two features are siblings: built by overlapping teams, on top of the exact same compute substrate, and shipped roughly two years apart.&lt;/p&gt;
&lt;p&gt;That substrate is named, and worth naming carefully, because the rest of the article rests on it.&lt;/p&gt;

The Windows API that creates, starts, configures, queries, and destroys Hyper-V &quot;compute systems&quot; -- the umbrella term Microsoft uses for either a virtual machine or a container with its own kernel. The HCS reference docs [@learn-microsoft-com-reference-apioverview] list functions like `HcsCreateComputeSystem`, `HcsStartComputeSystem`, and `HcsGetComputeSystemProperties` -- a kernel32-shaped surface for child partitions, parameterized by JSON.
&lt;p&gt;When Microsoft first documented HCS publicly, it framed it as a kernel32-equivalent for child partitions. The HCS overview [@learn-microsoft-com-hcs-overview] describes the API in terms of &lt;em&gt;compute systems&lt;/em&gt; (the umbrella term for either a virtual machine or a container with its own kernel), with &quot;configurations and properties... stored in a JSON file which will then be passed through the HCS APIs to create the compute system.&quot; The API reference [@learn-microsoft-com-reference-apioverview] notes that the DLL &quot;exports a set of C-style Windows API functions, using JSON schema as configuration&quot;; Microsoft&apos;s &lt;code&gt;hcsshim&lt;/code&gt; repository [@github-com-microsoft-hcsshim] provides the Go binding used by Moby and containerd. The framing matters. HCS is not a sandbox. It is the &lt;em&gt;mechanism&lt;/em&gt; a sandbox feature uses to ask Hyper-V for &quot;a kernel of my own, isolated from yours, please.&quot; What the consumer does with that kernel -- what it boots, what it shares, when it tears it down -- is the threat model. That is where Sandbox and WDAG diverge.&lt;/p&gt;
&lt;p&gt;Underneath HCS sits Hyper-V itself, and underneath Hyper-V sits Virtualization-Based Security (VBS).&lt;/p&gt;

A Windows feature that runs the normal Windows kernel as a Hyper-V guest, then uses a second, smaller secure kernel running at a higher Virtual Trust Level (VTL1) to isolate keys, policies, and code-integrity decisions from the main kernel. The OEM VBS guidance [@learn-microsoft-com-oem-vbs] documents the boot path: the hypervisor launches first, then hosts the NT kernel in a child partition.
&lt;p&gt;VBS itself does not run untrusted user code. Its job is to give Windows a hypervisor that ships in the box on every supported SKU and that is anchored by Secure Boot. Once that hypervisor exists, the cost of &quot;spawn a second Windows guest just for this task&quot; stops being &quot;boot a full VM (minutes, gigabytes)&quot; and starts being &quot;ask HCS for a child partition (seconds, hundreds of megabytes).&quot; Hyper-V on Windows [@learn-microsoft-com-windows-about] is the desktop face of that hypervisor; Hyper-V isolation containers [@learn-microsoft-com-hyperv-container] on Windows Server are the server face. Sandbox and WDAG are two desktop-flavored consumers of the same pipe.&lt;/p&gt;

flowchart TD
    HW[Hardware: VT-x/AMD-V, IOMMU, TPM]
    HV[Hyper-V hypervisor]
    Root[Root partition: host NT kernel]
    HCS[Host Compute Service API]
    WS[Windows Sandbox child partition]
    WDAG[WDAG child partition]
    HVC[Hyper-V Windows Container]
    HW --&amp;gt; HV
    HV --&amp;gt; Root
    Root --&amp;gt; HCS
    HCS --&amp;gt; WS
    HCS --&amp;gt; WDAG
    HCS --&amp;gt; HVC
&lt;p&gt;Notice the diagram&apos;s most important detail: the host NT kernel is &lt;em&gt;also&lt;/em&gt; a Hyper-V guest. It runs in the root partition, which has full physical-device access; the sandbox and WDAG partitions run as L1 guests with no physical-device access at all. The Hyper-V VM boundary -- the membrane between root and L1 -- is what Microsoft commits to defending. That commitment is published: the Microsoft Security Servicing Criteria for Windows [@microsoft-com-servicing-criteria] names the Hyper-V VM as a serviced security boundary, and the Hyper-V Bounty Program [@microsoft-com-hyper-v] pays up to $250,000 for a guest-to-host escape. The boundary has a dollar sign attached to it, which is how you know it counts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Hyper-V VM boundary is the serviced security boundary. Windows Sandbox and WDAG ride on top of that boundary; neither product &lt;em&gt;is&lt;/em&gt; the boundary. Bugs in the host-side broker, the clipboard channel, or the policy engine are not Hyper-V escapes -- they are integration bugs in features that happen to run inside a VM.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This distinction matters operationally. When the Windows Sandbox configuration docs [@learn-microsoft-com-wsb-file] warn that enabling vGPU &quot;can potentially increase the attack surface of the sandbox,&quot; they are talking about widening a brokered channel from the L1 guest into the root partition&apos;s display stack. That channel runs &lt;em&gt;through&lt;/em&gt; the VM boundary; abusing it does not require breaking Hyper-V. The same logic applies to mapped folders, the clipboard, networking, and the Edge-window remoting path WDAG used. Each is a deliberate hole in the boundary, made for a reason, with its own threat model.&lt;/p&gt;
&lt;p&gt;With the substrate established, the next question is what Sandbox does on top of it. The answer turns on a single observation: the host already has a Windows image. Why download another one?&lt;/p&gt;
&lt;h2&gt;2. Windows Sandbox: The Disposable Desktop&lt;/h2&gt;
&lt;p&gt;Windows Sandbox shipped in Windows 10 1903 [@learn-microsoft-com-sandbox-install], the May 2019 update, as an optional Windows feature named &lt;code&gt;Containers-DisposableClientVM&lt;/code&gt; -- the install page documents both the version requirement and the exact PowerShell feature name. The naming is loud about the design goal. A &lt;em&gt;container&lt;/em&gt; (rather than a VM you manage with &lt;code&gt;vmconnect&lt;/code&gt;), &lt;em&gt;disposable&lt;/em&gt; (state is destroyed on close), for &lt;em&gt;client&lt;/em&gt; workloads (interactive desktop apps, not server workloads). Microsoft&apos;s original Windows Sandbox announcement on the Kernel Internals blog [@web-archive-org-p-301849] (preserved on the Internet Archive after Microsoft retired the canonical URL) frames the use cases plainly: trying out an installer, opening a suspicious download, testing an executable from email -- the same use cases the current Sandbox overview [@learn-microsoft-com-sandbox-overview] still enumerates.&lt;/p&gt;
&lt;p&gt;The trick that makes this feel cheap is the &lt;em&gt;dynamic base image&lt;/em&gt;.&lt;/p&gt;

The disk template Windows Sandbox uses to boot its guest. According to the Windows Sandbox architecture page [@learn-microsoft-com-sandbox-architecture], the on-disk package is approximately 30 MB compressed and expands to about 500 MB when installed. The expansion is mostly *pointers* back to the host&apos;s own immutable OS files; pristine private copies exist only for files the guest may legitimately mutate.
&lt;p&gt;A traditional VM ships a 4-8 GB VHDX with its own copy of Windows. The dynamic base image inverts that. Read-only files in the host -- &lt;code&gt;ntdll.dll&lt;/code&gt;, the bulk of &lt;code&gt;System32&lt;/code&gt;, the side-by-side cache -- are reflected into the guest by reference. The guest sees a complete Windows install at boot. The host barely paid for it.&lt;/p&gt;
&lt;p&gt;Memory uses an even sharper trick: &lt;em&gt;direct map&lt;/em&gt;.&lt;/p&gt;

A Hyper-V memory-sharing optimization, described on the Windows Sandbox architecture page [@learn-microsoft-com-sandbox-architecture], in which immutable physical pages are shared read-only between the host and the sandbox guest. When the guest loads `ntdll.dll`, the same physical RAM that already holds `ntdll.dll` on the host is mapped into the guest&apos;s address space rather than duplicated.
&lt;p&gt;The page is read-only from both sides, so a guest exploit cannot scribble into the host&apos;s copy. The win is memory pressure: dozens of megabytes for the guest&apos;s mutable state instead of hundreds of megabytes for a fresh Windows kernel image. The same architecture page describes the memory model directly: &quot;containers collaborate with the host to dynamically determine how host resources are allocated. This method is similar to how processes normally compete for memory on the host... If the host is under memory pressure, it can reclaim memory from the container much like it would with a process.&quot; A sandbox that does little uses little, and a sandbox that does a lot pulls pages from the host the same way a heavy host process would.Direct map is conceptually the same trick Linux uses to share &lt;code&gt;glibc&lt;/code&gt; between processes -- the same physical pages of a read-only binary backing many virtual address spaces. The Windows Sandbox application is to use that primitive across a Hyper-V partition boundary, not just across processes inside one kernel.&lt;/p&gt;
&lt;p&gt;Graphics use a third mechanism. A vGPU runs the guest&apos;s display through WDDM 2.5+, sharing the host GPU much like another process on the host would. When the host GPU lacks a compatible WDDM driver, the guest falls back to WARP, Microsoft&apos;s CPU-backed Direct3D rasterizer. The same Sandbox architecture page [@learn-microsoft-com-sandbox-architecture] cited above documents both branches: &quot;a system with a compatible GPU and graphics drivers (WDDM 2.5 or newer) is required. Incompatible systems render apps in Windows Sandbox with Microsoft&apos;s CPU-based rendering technology, Windows Advanced Rasterization Platform (WARP).&quot; That fallback is slow but means Sandbox starts on essentially any Pro+ Windows 10/11 install, not only on machines with modern discrete GPUs.&lt;/p&gt;

sequenceDiagram
    participant U as User
    participant Host as Host (root partition)
    participant HCS as HCS API
    participant G as Sandbox guest
    U-&amp;gt;&amp;gt;Host: Launch WindowsSandbox.exe (with optional .wsb)
    Host-&amp;gt;&amp;gt;HCS: HcsCreateComputeSystem(JSON)
    HCS-&amp;gt;&amp;gt;G: Allocate partition, mount dynamic base image
    HCS-&amp;gt;&amp;gt;G: Direct-map immutable host pages
    HCS-&amp;gt;&amp;gt;G: Start guest (boot stripped NT, run LogonCommand)
    G--&amp;gt;&amp;gt;Host: RDP-style remoting of desktop
    U-&amp;gt;&amp;gt;G: Drop .exe, run, observe
    U-&amp;gt;&amp;gt;Host: Close Sandbox window
    Host-&amp;gt;&amp;gt;HCS: HcsTerminateComputeSystem
    HCS-&amp;gt;&amp;gt;G: Destroy partition, discard all writable state
&lt;p&gt;What the user &lt;em&gt;configures&lt;/em&gt; is the small set of seams between guest and host. Configuration lives in a &lt;code&gt;.wsb&lt;/code&gt; file, an XML document the user double-clicks to launch a customized sandbox. The Windows Sandbox configuration page [@learn-microsoft-com-wsb-file] enumerates every supported element: &lt;code&gt;&amp;lt;vGPU&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Networking&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;MappedFolders&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;LogonCommand&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;MemoryInMB&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;AudioInput&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;VideoInput&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ProtectedClient&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;PrinterRedirection&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ClipboardRedirection&amp;gt;&lt;/code&gt;. Each line is a knob on the boundary.&lt;/p&gt;
&lt;p&gt;A minimal hostile-binary harness disables almost every shared channel:&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;// Produce a Windows Sandbox configuration that minimizes shared channels. // Run this in Node, save the output as triage.wsb, then double-click it. const sample = &quot;C:\\\\Users\\\\analyst\\\\Samples\\\\suspicious.exe&quot;; const wsb = [   &quot;&amp;lt;Configuration&amp;gt;&quot;,   &quot;  &amp;lt;VGpu&amp;gt;Disable&amp;lt;/VGpu&amp;gt;&quot;,   &quot;  &amp;lt;Networking&amp;gt;Disable&amp;lt;/Networking&amp;gt;&quot;,   &quot;  &amp;lt;AudioInput&amp;gt;Disable&amp;lt;/AudioInput&amp;gt;&quot;,   &quot;  &amp;lt;VideoInput&amp;gt;Disable&amp;lt;/VideoInput&amp;gt;&quot;,   &quot;  &amp;lt;PrinterRedirection&amp;gt;Disable&amp;lt;/PrinterRedirection&amp;gt;&quot;,   &quot;  &amp;lt;ClipboardRedirection&amp;gt;Disable&amp;lt;/ClipboardRedirection&amp;gt;&quot;,   &quot;  &amp;lt;ProtectedClient&amp;gt;Enable&amp;lt;/ProtectedClient&amp;gt;&quot;,   &quot;  &amp;lt;MappedFolders&amp;gt;&quot;,   &quot;    &amp;lt;MappedFolder&amp;gt;&quot;,   &quot;      &amp;lt;HostFolder&amp;gt;C:\\\\Users\\\\analyst\\\\Samples&amp;lt;/HostFolder&amp;gt;&quot;,   &quot;      &amp;lt;SandboxFolder&amp;gt;C:\\\\Samples&amp;lt;/SandboxFolder&amp;gt;&quot;,   &quot;      &amp;lt;ReadOnly&amp;gt;true&amp;lt;/ReadOnly&amp;gt;&quot;,   &quot;    &amp;lt;/MappedFolder&amp;gt;&quot;,   &quot;  &amp;lt;/MappedFolders&amp;gt;&quot;,   &quot;&amp;lt;/Configuration&amp;gt;&quot; ].join(&quot;\\n&quot;); console.log(wsb); console.log(&quot;\\nSample path inside guest: &quot; + sample.replace(&quot;C:\\\\Users\\\\analyst&quot;, &quot;C:&quot;));&lt;/code&gt;}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The default &lt;code&gt;.wsb&lt;/code&gt;-less Windows Sandbox launch enables networking and clipboard redirection. The configuration docs [@learn-microsoft-com-wsb-file] warn that enabled networking &quot;could expose untrusted applications to the internal network.&quot; For malware triage, the explicit &lt;code&gt;&amp;lt;Networking&amp;gt;Disable&amp;lt;/Networking&amp;gt;&lt;/code&gt; form above is the right starting point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A few cost-of-doing-business limits are worth flagging up front. Only one Sandbox can run at a time, per the Sandbox overview [@learn-microsoft-com-sandbox-overview], which also restricts the feature to Pro/Enterprise/Education SKUs (&quot;Windows Sandbox is currently not supported on Windows Home edition&quot;) and inherits the VBS-capable-hardware requirement from the OEM VBS guidance [@learn-microsoft-com-oem-vbs]. And while in-sandbox state survives a &lt;code&gt;shutdown /r&lt;/code&gt; inside the guest (a Windows 11 22H2 refinement called out in the same overview page), state still dies when the host UI window closes -- &quot;disposable&quot; is the contract, not a marketing word.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Containers-DisposableClientVM&lt;/code&gt; partition, then, is essentially a Hyper-V container with a desktop bolted on, a shared OS image, a few configurable channels, and a strict &quot;destroy on close&quot; lifecycle. WDAG, the older sibling, took the same building blocks and arranged them around a completely different question: not &quot;run this executable once&quot; but &quot;render this website transparently.&quot;&lt;/p&gt;
&lt;h2&gt;3. WDAG: The Persistent Browser Container&lt;/h2&gt;
&lt;p&gt;Windows Defender Application Guard shipped in Windows 10 1709 -- the Fall Creators Update [@learn-microsoft-com-build-16299] (Microsoft&apos;s UWP what&apos;s-new page identifies &quot;Windows 10 build 16299 (also known as the Fall Creators Update or version 1709)&quot;), with a GA start date of October 17, 2017 [@learn-microsoft-com-and-education] per the Microsoft Lifecycle page. The WDAG install guide [@learn-microsoft-com-app-guard] still lists standalone-mode support starting at &quot;Windows 10 Enterprise edition, version 1709 and later.&quot; At launch it integrated with the legacy EdgeHTML-based Edge; later it integrated with Chromium-based Edge for Business and, beginning in 2020, with Microsoft 365 Apps for Enterprise to wrap untrusted Office documents -- the MDAG overview [@learn-microsoft-com-guard-overview] explicitly enumerates the file types: &quot;Application Guard helps prevent untrusted Word, PowerPoint, and Excel files from accessing trusted resources.&quot; The product was rebranded from &quot;Windows Defender Application Guard&quot; to &quot;Microsoft Defender Application Guard&quot; along the way -- the &lt;code&gt;isolatedapplauncher.h&lt;/code&gt; header notes [@learn-microsoft-com-api-isolatedapplauncher] state directly that &quot;Windows Defender Application Guard (WDAG) is now Microsoft Defender Application Guard (MDAG). The WDAG name is deprecated, but it is still used in some APIs.&quot; This article uses WDAG for continuity.&lt;/p&gt;
&lt;p&gt;The use case was specific and corporate: in a managed enterprise, an employee may need to follow a customer&apos;s link, open an inbound attachment, or read a marketing site -- content that originates &lt;em&gt;outside&lt;/em&gt; the organization&apos;s network perimeter. WDAG&apos;s job was to render that content in a partition that &lt;em&gt;cannot&lt;/em&gt; talk to the intranet, so that a renderer exploit chained to a kernel LPE inside the guest could not pivot to corporate file shares, Active Directory, or the user&apos;s own home directory.&lt;/p&gt;
&lt;p&gt;The trust boundary was policy-defined.&lt;/p&gt;

The Group Policy mechanism Windows uses to enumerate &quot;what counts as inside the enterprise network,&quot; documented under Configure Microsoft Defender Application Guard [@learn-microsoft-com-app-guard-2]. Administrators populate Enterprise Network Domains, Cloud Resources, Internal Proxies, and IPv4/IPv6 Subnets. Anything inside the list is rendered in the host browser; anything outside is reissued inside the WDAG container.
&lt;p&gt;This is the property Windows Sandbox does not have. Sandbox is a manual tool; WDAG was transparent. Click an external link in Outlook, and a separate Edge window opens hosting the rendered page -- the user did not have to know about, configure, or invoke a sandbox. The host-side broker forwarded the navigation; the in-container Edge rendered the page; an RDP-family remoting path relayed pixels back to the host UI. Microsoft has not publicly named the inner protocol, but its visible behavior -- per-window remoting of a single app onto the host desktop -- is the signature of the Remote Applications Integrated Locally (RAIL) virtual channel specified in &lt;a href=&quot;https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdperp/&quot; rel=&quot;noopener&quot;&gt;[MS-RDPERP]&lt;/a&gt;, the RDP extension that &quot;presents a remote application... as a local user application.&quot; The implementation may differ in detail; the architectural shape is the same.&lt;/p&gt;
&lt;p&gt;Where Sandbox is &quot;destroy on close,&quot; WDAG was &quot;warm at logon.&quot;&lt;/p&gt;

sequenceDiagram
    participant U as User
    participant Logon as Winlogon
    participant Broker as Host WDAG broker
    participant Cont as WDAG container
    participant Edge as Container Edge
    Logon-&amp;gt;&amp;gt;Broker: User signs in
    Broker-&amp;gt;&amp;gt;Cont: HCS pre-warm container (pruned image)
    Cont-&amp;gt;&amp;gt;Edge: Boot, idle, await navigation
    U-&amp;gt;&amp;gt;Broker: Click https://external.example
    Broker-&amp;gt;&amp;gt;Broker: Network Isolation policy check (out of zone)
    Broker-&amp;gt;&amp;gt;Edge: Reissue URL inside container
    Edge--&amp;gt;&amp;gt;Broker: Render via RDP-family remoting (RAIL-shaped)
    Broker--&amp;gt;&amp;gt;U: Display container window on host desktop
&lt;p&gt;The configuration surface was correspondingly broader than Sandbox&apos;s &lt;code&gt;.wsb&lt;/code&gt;. Group Policy settings controlled clipboard direction (upload, download, both, neither), file print to host, microphone and camera access, hardware acceleration, and -- most operationally consequential -- whether downloads escape the container at all. The Microsoft Edge WDAG configuration guidance [@learn-microsoft-com-application-guard] listed knobs like &lt;code&gt;ApplicationGuardUploadBlockingEnabled&lt;/code&gt; and &lt;code&gt;ApplicationGuardPassiveModeEnabled&lt;/code&gt; for security-versus-usability tuning.&lt;/p&gt;
&lt;p&gt;WDAG also exposed a small detection API for applications running inside it, the &lt;code&gt;IsolatedAppLauncher&lt;/code&gt; COM interface [@learn-microsoft-com-api-isolatedapplauncher]. The methods &lt;code&gt;IsProcessInWDAGContainer&lt;/code&gt; and &lt;code&gt;IsProcessInIsolatedContainer&lt;/code&gt; let an app know &quot;am I in the guest?&quot; -- useful for, say, disabling drivers that cannot work inside the partition. The header carries the deprecation notice today.The detection-from-inside API is itself a useful tell about WDAG&apos;s threat model. If the guest needed to &lt;em&gt;know&lt;/em&gt; it was the guest, that means software running inside it could legitimately do guest-specific things -- license activation, optional installers, telemetry. WDAG was meant to host fully functional applications, not a stripped renderer. That breadth is part of what made its operational cost real.&lt;/p&gt;
&lt;p&gt;What it improved over the AppContainer-wrapped Edge of 2016 was substantial. A renderer-to-kernel exploit in the container&apos;s stripped Windows guest landed in a throwaway kernel that had no view of the host filesystem, no route to the corporate intranet, no host clipboard write path, and no persistence across reboot. The kernel attack surface of the partition is, &lt;em&gt;in the limit&lt;/em&gt;, the Hyper-V VM boundary. That is a serviced Microsoft boundary; an AppContainer-wrapped Edge is not.&lt;/p&gt;
&lt;p&gt;So why was WDAG retired and Sandbox kept? Because in the WDAG threat model, the &quot;warm partition for every employee, all day long, on every device&quot; became a tax that the in-browser sandbox could finally outrun.&lt;/p&gt;
&lt;h2&gt;4. The Lifecycle Divergence&lt;/h2&gt;
&lt;p&gt;The clearest way to see why two siblings on the same substrate diverged is to put their lifecycles side by side. Sandbox boots on user gesture, runs as long as one window stays open, dies on close. WDAG booted at user logon, stayed resident the entire session, and discarded state only when the user signed out (or, for the persistent variant, never). The same Hyper-V partition primitive, allocated at very different points in the day, for very different durations, was being asked to solve very different problems.&lt;/p&gt;

The point at which a security primitive&apos;s instance lifetime is anchored. Sandbox is *gesture-bound*: an instance exists because a user explicitly launched it. WDAG was *session-bound*: an instance existed because a user signed in. AppContainer is *process-bound*: an instance exists because a sandboxed binary is running. Each binding implies a different cost model and a different set of failure modes.
&lt;p&gt;Gesture binding is cheap in expectation. Most users open Sandbox seldom -- when a particular file looks suspicious, when an installer wants admin rights for unclear reasons, when an analyst is reproducing a sample. The cost of the partition is paid on demand and only by the user who needed it. The &lt;code&gt;Containers-DisposableClientVM&lt;/code&gt; feature in the Sandbox install docs [@learn-microsoft-com-sandbox-install] ships an &lt;em&gt;option&lt;/em&gt;: enabled but unused, it costs nothing beyond the dynamic base image on disk.&lt;/p&gt;
&lt;p&gt;Session binding has the opposite cost profile. Every employee, on every device, pays for a Hyper-V child partition at every logon, whether or not they ever browse an untrusted URL. The partition holds memory. The host-side broker holds memory. The pre-warmed Edge holds memory. The Network Isolation policy must be evaluated on every navigation. The clipboard, downloads, and print paths require ongoing brokering. Even on a workstation that idles all day in front of an intranet portal, WDAG was a tax line item.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A serviced security boundary is cheap when it is allocated by gesture and expensive when it is allocated by session. WDAG bet that the per-session cost would amortize against frequent untrusted browsing; that bet failed for most enterprise users because the marginal extra protection over an in-browser sandbox (Edge ESM + ACG + CET) was small for the &lt;em&gt;typical&lt;/em&gt; navigation, even though it remained large for the &lt;em&gt;worst-case&lt;/em&gt; navigation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The threat models also point in opposite directions. Sandbox optimizes for a single, contained interaction with an untrusted artifact: drop the &lt;code&gt;.exe&lt;/code&gt;, run it, watch what happens, close the window. Anything the artifact does inside the partition -- registry writes, scheduled-task creation, persistence attempts -- is annihilated when the window closes. WDAG was optimizing for the opposite: many small, transparent interactions with untrusted content (clicks, navigations, document opens), all of which had to feel seamless or the user would route around them.&lt;/p&gt;

gantt
    title Sandbox vs WDAG lifecycle on a typical 8-hour workday
    dateFormat HH:mm
    axisFormat %H:%M
    section Windows Sandbox
    Idle (no cost) :done, ws1, 09:00, 11:00
    Analyst opens suspicious.exe :crit, ws2, 11:00, 11:15
    Idle (no cost) :done, ws3, 11:15, 16:00
    Test installer :crit, ws4, 16:00, 16:10
    Idle (no cost) :done, ws5, 16:10, 17:00
    section WDAG (legacy)
    Pre-warmed partition resident :crit, wd1, 09:00, 17:00
&lt;p&gt;The lifecycle asymmetry also asymmetrically rewards engineering effort. Hardening an in-browser renderer pays off thousands of times per session -- every page load benefits. Hardening a per-employee Hyper-V partition pays off only on the navigations that actually leave the trusted zone, which for most users is a small fraction of clicks. As the in-browser side became dramatically stronger between 2018 and 2023 -- Site Isolation, V8 sandboxing, Arbitrary Code Guard (ACG), Control-flow Enforcement Technology (CET), the new Edge Enhanced Security Mode -- the marginal value of WDAG dropped while its operational cost did not.&lt;/p&gt;
&lt;p&gt;That set up the deprecation decision.&lt;/p&gt;
&lt;h2&gt;5. The Deprecation Decision&lt;/h2&gt;
&lt;p&gt;The retirement happened in two visible steps and a long invisible runway.&lt;/p&gt;
&lt;p&gt;The first visible step was the Edge-side deprecation, announced in 2023. The Microsoft Edge and Microsoft Defender Application Guard [@learn-microsoft-com-application-guard] page now opens with the banner: &quot;Microsoft Defender Application Guard, including the Windows Isolated App Launcher APIs, is deprecated for Microsoft Edge for Business and will no longer be updated.&quot; The same page makes the operational substitute explicit: &quot;The additional security features in Edge make it very secure without needing Application Guard,&quot; then enumerates Defender SmartScreen, Enhanced Security Mode, website typo protection, and Data Loss Prevention as the &lt;em&gt;replacement set&lt;/em&gt; for the WDAG-for-Edge scenario.&lt;/p&gt;
&lt;p&gt;The second visible step was the OS-level removal in Windows 11 version 24H2. The MDAG overview banner [@learn-microsoft-com-guard-overview] is unambiguous: &quot;Starting with Windows 11, version 24H2, Microsoft Defender Application Guard, including the Windows Isolated App Launcher APIs, is no longer available.&quot; The &lt;code&gt;isolatedapplauncher.h&lt;/code&gt; API reference [@learn-microsoft-com-api-isolatedapplauncher] carries the matching deprecation notice for the COM surface. Code paths that called &lt;code&gt;IIsolatedAppLauncher&lt;/code&gt; on a 24H2 box now hit a removed feature; the API names remain in the documentation as historical record.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Edge-side deprecation and the OS-side removal in Windows 11 24H2 are often conflated in coverage. They are different. The Edge-side deprecation stopped updates and the New-Tab-Page entry point; existing fleets on earlier Windows versions retained the underlying feature. The 24H2 removal pulled the kernel-mode plumbing -- the Sandbox install page [@learn-microsoft-com-sandbox-install] even calls out a side-effect: &quot;Beginning in Windows 11, version 24H2, inbox store apps like Calculator, Photos, Notepad and Terminal are not available inside Windows Sandbox,&quot; because the underlying app-isolation broker was reworked as part of the same cleanup.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The invisible runway behind those two banners is the more interesting story. Microsoft&apos;s Security Servicing Criteria for Windows [@microsoft-com-servicing-criteria] page names &quot;Hyper-V VM&quot; as a serviced security boundary but does not name WDAG or Application Guard. WDAG was always a &lt;em&gt;feature&lt;/em&gt; that &lt;em&gt;used&lt;/em&gt; the Hyper-V VM boundary; it was never the boundary itself. A bug in the WDAG broker, the Network Isolation policy evaluator, the clipboard channel, or the host-side window remoting was an integration bug, not a Hyper-V escape, and so was never going to attract the kind of bounty payout -- &quot;up to $250,000 USD&quot; per the Hyper-V Bounty Program [@microsoft-com-hyper-v] -- that the underlying boundary attracts. The economic shape of WDAG&apos;s bug surface always favored deprecation: it was a complex, brokered feature whose worst plausible CVE was a privilege-escalation inside Edge, not a guest-to-host RCE.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; WDAG&apos;s deprecation was overdetermined. (1) The session-bound cost model could not be amortized for most users. (2) The in-browser mitigations (ACG, CET, Edge ESM, Site Isolation) closed the marginal-security gap on the &lt;em&gt;typical&lt;/em&gt; navigation. (3) The integration-bug class -- broker, clipboard, policy -- was never going to be on Microsoft&apos;s serviced security boundary list. Each reason alone could have justified retirement; all three together made it inevitable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What was &lt;em&gt;kept&lt;/em&gt; is just as telling. The Hyper-V VM boundary stayed; the bounty program stayed; the HCS API stayed; Windows Sandbox stayed; Hyper-V isolation containers on Windows Server stayed. Microsoft did not retire any of the things that made WDAG technically possible -- only the specific arrangement of those things into a session-bound, transparent, browser-targeted feature. The mechanism was kept; the productization was retired.&lt;/p&gt;
&lt;h2&gt;6. The WDAG Replacement Stack&lt;/h2&gt;
&lt;p&gt;There is no single replacement for WDAG. There is a stack of complementary features, each of which absorbs a slice of WDAG&apos;s old job. The Edge-deprecation page enumerates the substitute set; what follows pulls each item back to its primary source.&lt;/p&gt;
&lt;h3&gt;6.1 Edge Enhanced Security Mode (in-browser sandbox)&lt;/h3&gt;
&lt;p&gt;WDAG-for-Edge is now Microsoft Edge Enhanced Security Mode (ESM). The browse-safer page [@learn-microsoft-com-browse-safer] is explicit about what changed: &quot;Enhanced security mode in Microsoft Edge mitigates memory-related vulnerabilities by disabling just-in-time (JIT) JavaScript compilation and enabling additional operating system protections for the browser. These protections include Hardware-enforced Stack Protection and Arbitrary Code Guard (ACG).&quot;&lt;/p&gt;
&lt;p&gt;Functionally, ESM gives up the Hyper-V partition boundary and replaces it with a set of process-mitigation policies that make the in-browser sandbox materially harder to escape. The renderer still runs on the host kernel, but with JIT disabled (closing a large class of write-then-execute primitives), CET enforcing shadow stacks, and ACG blocking dynamic code generation. For &lt;em&gt;unfamiliar&lt;/em&gt; sites only, the browser flips into this mode automatically; familiar sites keep JIT on for performance.The trade is explicit on the page: &quot;Developers should be aware that the WebAssembly (WASM) interpreter running in enhanced security mode might not yield the expected level of performance.&quot; ESM is consciously slower in exchange for a smaller attack surface, and it concedes that this trade is only worth making on a subset of navigations. WDAG made the same concession at the partition level; ESM makes it at the mitigation level.&lt;/p&gt;
&lt;h3&gt;6.2 Smart App Control (OS-level binary trust)&lt;/h3&gt;
&lt;p&gt;For downloads -- the other half of &quot;untrusted content reaches the user&quot; -- the replacement is Smart App Control [@learn-microsoft-com-control-overview]. The Microsoft Learn page describes it as &quot;an app execution control feature that combines Microsoft&apos;s app intelligence services and Windows&apos; code integrity features to protect users from untrusted or potentially dangerous code.&quot; The Windows 11 Security Book [@learn-microsoft-com-driver-control] clarifies the mechanism: Smart App Control &quot;blocks untrusted or unsigned applications&quot; by predicting safety from a cloud intelligence service, and &quot;blocks unknown script files and macros from the web.&quot;&lt;/p&gt;
&lt;p&gt;The replacement logic is direct. WDAG protected the host kernel from a malicious download by running the download inside a Hyper-V partition. Smart App Control protects the host kernel from a malicious download by &lt;em&gt;not running it at all&lt;/em&gt; unless app intelligence predicts it is safe or it is signed by a trusted CA. The first approach contains the blast radius after execution; the second prevents execution altogether. For the common case -- a user clicking through a suspicious-looking installer -- prevention strictly dominates containment.&lt;/p&gt;
&lt;h3&gt;6.3 Defender for Endpoint network protection (policy-defined trust boundary)&lt;/h3&gt;
&lt;p&gt;For the policy-defined &quot;enterprise vs not-enterprise&quot; boundary that the Network Isolation policy used to draw for WDAG, the replacement is Defender for Endpoint&apos;s network protection [@learn-microsoft-com-network-protection] feature. The page describes it as &quot;expand[ing] the scope of Microsoft Defender SmartScreen to block all outbound HTTP(S) traffic that attempts to connect to poor-reputation sources (based on the domain or hostname),&quot; operating at the OS level. The same page is precise about which processes it covers on Windows: it enforces against non-Microsoft browsers and non-browser processes (for example, PowerShell), and its own Note states that &quot;on Windows, network protection doesn&apos;t monitor Microsoft Edge. For processes other than Microsoft Edge and Internet Explorer, web protection scenarios use network protection for inspection and enforcement.&quot; For Microsoft Edge on Windows, the same reputational source feed (SmartScreen) operates inside the browser; Network Protection is the cross-process extension of that feed to the other process classes.&lt;/p&gt;
&lt;p&gt;The shift is from &lt;em&gt;isolate, then permit anything inside the isolated zone&lt;/em&gt; (WDAG) to &lt;em&gt;enforce a reputational/IOC-based block list at the host network stack&lt;/em&gt; (Defender). The replacement gives up the partition boundary in exchange for matching coverage across every process on the device, not just Edge.&lt;/p&gt;
&lt;h3&gt;6.4 Office Protected View and Office SmartScreen (per-document admission)&lt;/h3&gt;
&lt;p&gt;The Office slice of WDAG -- the variant that wrapped untrusted Word, PowerPoint, and Excel files in a Hyper-V partition -- was always a layered feature on top of an older, cheaper primitive: Office Protected View [@support-microsoft-com-8e43-2bbcdbcb6653]. The Microsoft Support page describes the primitive directly: &quot;files from these potentially unsafe locations are opened as read only or in Protected View. By using Protected View, you can read a file, see its contents and enable editing while reducing the risks.&quot; The page also calls out the WDAG layering explicitly: &quot;If your machine has Application Guard for Microsoft 365 enabled, documents that previously opened in Protected View will now open in Application Guard for Microsoft 365&quot; -- which is exactly the slice that 24H2 removed. Without WDAG, Protected View is the residual primitive: documents from the internet, untrusted senders, or unsafe locations open read-only in a stripped-down Office process until the user opts in to editing.&lt;/p&gt;
&lt;p&gt;Around Protected View sits a second admission layer: SmartScreen-derived reputation checks on the artifact itself. The Microsoft 365 Apps internet-macros guidance [@learn-microsoft-com-macros-blocked] sets the policy directly: &quot;VBA macros are a common way for malicious actors to gain access to deploy malware and ransomware. Therefore, to help improve security in Office, we&apos;re changing the default behavior of Office applications to block macros in files from the internet.&quot; The page describes how Office uses the Mark of the Web -- the same signal SmartScreen uses for binaries -- to decide whether macros in a given document are admitted. Where the WDAG-for-Office configuration would have re-rendered the document inside a Hyper-V partition regardless of macro content, the 2026 replacement turns the question off: macros in internet-origin documents simply do not run.&lt;/p&gt;
&lt;p&gt;Together, the two features are the document analog of Smart App Control + Defender network protection: a read-only fallback for the artifact itself (Protected View) and a reputation-driven admission policy for its riskiest payload (macros). Neither replaces a partition; the union covers WDAG&apos;s Office slice at the cost of giving up the kernel boundary around the document.&lt;/p&gt;

flowchart LR
    WDAG[WDAG legacy feature]
    WDAG --&amp;gt;|Untrusted browsing| ESM[Edge Enhanced Security Mode&lt;br /&gt;JIT off, ACG, CET on unfamiliar sites]
    WDAG --&amp;gt;|Untrusted downloads| SAC[Smart App Control&lt;br /&gt;Cloud-AI binary trust]
    WDAG --&amp;gt;|Network trust zoning| DNP[Defender network protection&lt;br /&gt;Host-stack URL/domain enforcement]
    WDAG --&amp;gt;|Office documents| OFP[Office Protected View / SmartScreen]
&lt;p&gt;The stack is not a one-for-one swap. Each feature trades the Hyper-V VM boundary for something cheaper to operate. The aggregate covers the WDAG threat model at &lt;em&gt;typical&lt;/em&gt; navigation cost; for the unusual case where an enterprise still wants a hard kernel boundary around an untrusted workload, Microsoft&apos;s recommended fallback [@learn-microsoft-com-application-guard] is explicit: &quot;If your organization requires container-based isolation, we recommend Windows Sandbox or Azure Virtual Desktop (AVD).&quot; The Hyper-V partition is still there. It just is no longer running every employee&apos;s browser, all day, by default.&lt;/p&gt;
&lt;h2&gt;7. Why Sandbox Survives&lt;/h2&gt;
&lt;p&gt;If the deprecation reasoning above is right, the natural question is why the &lt;em&gt;same&lt;/em&gt; substrate, allocated by &lt;em&gt;the same&lt;/em&gt; HCS API, in &lt;em&gt;the same&lt;/em&gt; kind of Hyper-V partition, survived as Windows Sandbox. The answer is that everything that made WDAG expensive maps to an operational advantage in Sandbox.&lt;/p&gt;
&lt;p&gt;The lifecycle is gesture-bound, not session-bound. The cost is paid by the user who explicitly asked for it, when they asked for it, and not before. The Sandbox install page [@learn-microsoft-com-sandbox-install] ships the feature disabled by default; turning it on costs the dynamic base image on disk and nothing on memory until launch.&lt;/p&gt;
&lt;p&gt;The substitute set is empty. For the &quot;run an untrusted executable once&quot; threat model, no in-process mitigation suite plays the role ESM plays for browsing. There is no in-AppContainer answer to &quot;I want to detonate &lt;code&gt;suspicious.exe&lt;/code&gt; and observe it&quot;; Smart App Control prevents execution rather than containing it; AppLocker policies refuse the run rather than sandboxing it. The use case Sandbox fills is what is &lt;em&gt;left over&lt;/em&gt; when prevention fails or is operationally unacceptable, and there is no cheaper way to fill it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The &quot;run an untrusted executable&quot; threat model lacks a cheaper substitute, so Sandbox&apos;s Hyper-V partition cost is the floor. WDAG&apos;s &quot;render an untrusted website&quot; threat model gained a cheaper substitute (Edge ESM), so WDAG&apos;s same Hyper-V partition cost stopped being the floor and became the ceiling -- and was retired.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The integration surface is also far smaller. Sandbox exposes one launcher binary, one configuration file format, no policy engine, no clipboard direction policies (just on/off), no network zoning, no pre-warmed worker process, no host-side broker for an embedded browser. The host-side attack surface is correspondingly thin: a &lt;code&gt;.wsb&lt;/code&gt; parser, an HCS caller, a window-host process. Each WDAG-style integration bug class -- network-isolation evaluator, browser broker, document-routing logic -- has no analog.&lt;/p&gt;
&lt;p&gt;A useful contrast: the &lt;code&gt;isolatedapplauncher.h&lt;/code&gt; [@learn-microsoft-com-api-isolatedapplauncher] page exposes &lt;code&gt;IIsolatedAppLauncher&lt;/code&gt;, &lt;code&gt;IIsolatedProcessLauncher&lt;/code&gt;, &lt;code&gt;IsProcessInIsolatedContainer&lt;/code&gt;, and &lt;code&gt;IsProcessInWDAGContainer&lt;/code&gt;. That is the application surface of a feature that hosts third-party processes and lets them know they are inside it. Sandbox has nothing comparable, because no third-party application is supposed to ship with &quot;behave differently inside Sandbox&quot; logic. The guest is a fresh Windows install, the artifact is whatever the user dropped in, and the host does not need to expose an &quot;am I inside?&quot; predicate.&lt;/p&gt;
&lt;p&gt;Sandbox also benefits from the &lt;em&gt;negative space&lt;/em&gt; of the deprecation. The replacement stack (Edge ESM, Smart App Control, Defender network protection) collectively pushes the &lt;em&gt;unbearable&lt;/em&gt; workloads off the Hyper-V partition: the always-on browser, the heavyweight Office document host, the network-zone enforcer. What is left for Sandbox is the relatively small set of workloads where partition isolation is the right answer: malware triage, installer testing, one-off compatibility checks, isolated developer environments. The feature is now used closer to its design intent than it was in the WDAG era.This is the rare case where deprecating a sibling makes a feature &lt;em&gt;more&lt;/em&gt; aligned with its purpose. Before WDAG retirement, the question &quot;should this be in Sandbox or WDAG?&quot; had a complicated answer involving who you were and what you were doing. After 24H2, the question collapses: if you want a partition, you mean Sandbox.&lt;/p&gt;
&lt;h2&gt;8. The 2026 Isolation Stack&lt;/h2&gt;
&lt;p&gt;With WDAG gone, the post-24H2 Windows isolation taxonomy is best read as four orthogonal primitives, each answering a different question about an untrusted workload. None alone substitutes for WDAG&apos;s combined function; together they cover the ground WDAG used to. The tiers below are numbered for reference; the numbering does &lt;em&gt;not&lt;/em&gt; imply a single linear cost/strength axis. Process mitigations live &lt;em&gt;inside&lt;/em&gt; AppContainer-wrapped processes (they are not &quot;below&quot; AppContainer on a cost axis, they are within it), and admission primitives (Smart App Control, Defender network protection) are an orthogonal family that decides whether a binary or destination is allowed at all -- a question that runs before capability containment, not above or below it.&lt;/p&gt;

A mechanism that answers a specific question about how an untrusted workload is constrained. The four families that the 2026 Windows stack composes are: (1) *process-internal mitigations* that limit what a corrupted-memory exploit can do (ACG, CET, Edge ESM); (2) *capability sandboxes* that limit what a process can name and reach (AppContainer); (3) *admission policies* that decide whether a binary may run or a destination may be contacted at all (Smart App Control, Defender network protection); and (4) *kernel-partition boundaries* that put an entire second NT kernel between the workload and the user&apos;s data (Hyper-V VM). Each family has its own cost shape; only the kernel-partition boundary appears on the Microsoft Servicing Criteria for Windows [@microsoft-com-servicing-criteria] as a serviced security boundary.
&lt;h3&gt;Tier 1: Process mitigations (Edge ESM, ACG, CET)&lt;/h3&gt;
&lt;p&gt;The cheapest family runs the workload on the host kernel under a stricter set of process-level controls. Edge Enhanced Security Mode is the visible UI; the underlying primitives are the Hardware-enforced Stack Protection [@techcommunity-microsoft-com-p-2163340] (CET) and Arbitrary Code Guard [@learn-microsoft-com-protection-reference] (ACG) referenced from the browse-safer page [@learn-microsoft-com-browse-safer]. These mitigations apply &lt;em&gt;inside&lt;/em&gt; whatever container the binary already runs in -- an AppContainer-wrapped Edge renderer, or a non-AppContainer process -- and limit the privileges a corrupted-memory exploit can give itself. They are sufficient for the &lt;em&gt;vast majority&lt;/em&gt; of untrusted navigations after the JIT-disabling trade is made.&lt;/p&gt;
&lt;h3&gt;Tier 2: AppContainer (capability-bound sandbox)&lt;/h3&gt;
&lt;p&gt;The capability sandbox is the AppContainer [@learn-microsoft-com-appcontainer-isolation] primitive. The MSDN page enumerates the isolation slices under six section headings -- Credential isolation, Device isolation, File isolation, Network isolation, Process isolation, and Window isolation -- all enforced at the OS, none requiring a partition. AppContainer is the wrapper around Edge&apos;s renderer, around UWP apps, around modern app-isolation packages. It is the cheap container that scales to every process on the device. Inside an AppContainer, Tier 1 mitigations still apply; AppContainer constrains what the process can &lt;em&gt;name&lt;/em&gt;, Tier 1 constrains what a corrupted process can &lt;em&gt;do&lt;/em&gt;. They are complementary, not stacked.&lt;/p&gt;
&lt;h3&gt;Tier 3: Smart App Control + Defender network protection (policy at the OS edge)&lt;/h3&gt;
&lt;p&gt;Adjacent to the process tiers, the policy tier decides what binaries and what destinations are allowed at all. Smart App Control governs &lt;em&gt;what runs&lt;/em&gt;; Defender network protection governs &lt;em&gt;what the device talks to&lt;/em&gt;. These are not isolation primitives in the strict sense -- they are &lt;em&gt;admission&lt;/em&gt; primitives. They turn off the question before the partition has to answer it.&lt;/p&gt;
&lt;h3&gt;Tier 4: Hyper-V VM (Windows Sandbox, Windows Server Hyper-V isolation containers)&lt;/h3&gt;
&lt;p&gt;At the top of the cost curve sits the Hyper-V VM boundary -- the only tier whose worst-case escape pays the $250,000 bounty [@microsoft-com-hyper-v]. Windows Sandbox is the desktop face; Hyper-V isolation containers [@learn-microsoft-com-hyperv-container] on Windows Server (&quot;each container runs inside of a highly optimized virtual machine and effectively gets its own kernel&quot;) are the server face. The 2026 stack uses this tier sparingly, on user gesture, for workloads where the cheaper tiers are not enough.&lt;/p&gt;

flowchart TD
    T1[Tier 1: Process mitigations&lt;br /&gt;ACG, CET, Edge ESM]
    T2[Tier 2: AppContainer&lt;br /&gt;Capability-bound process sandbox]
    T3[Tier 3: Policy admission&lt;br /&gt;Smart App Control + Defender network protection]
    T4[Tier 4: Hyper-V VM&lt;br /&gt;Windows Sandbox / HV isolation containers]
    T1 ~~~ T2 ~~~ T3 ~~~ T4
    T1 -.-&amp;gt;|untrusted browsing| ESM2[Edge ESM]
    T2 -.-&amp;gt;|modern apps| UWP[UWP / packaged apps]
    T3 -.-&amp;gt;|admit/deny| SAC2[SAC + DNP]
    T4 -.-&amp;gt;|on-demand detonation| WS2[Windows Sandbox]
&lt;p&gt;The taxonomy is layered without being strictly linear. Read it as a four-question pipeline rather than a four-rung ladder. Tier 3 (Smart App Control + Defender network protection) decides &lt;em&gt;what runs and what the device talks to&lt;/em&gt; -- admission, not containment. Whatever Tier 3 admits then lands inside Tier 2 (AppContainer), which constrains the binary&apos;s &lt;em&gt;capabilities&lt;/em&gt; -- file, network, device, window, credential, and process scope. Inside that AppContainer-wrapped process, Tier 1 (ACG, CET, Edge ESM) applies &lt;em&gt;process-internal&lt;/em&gt; mitigations that limit what a corrupted-memory exploit can do. Tier 4 (Hyper-V VM) is the last-resort &lt;em&gt;kernel&lt;/em&gt; boundary: when the workload is hostile enough that the host kernel itself must be assumed reachable from the renderer, Windows Sandbox or a Hyper-V isolation container puts an entire NT kernel between the artifact and the user&apos;s data. WDAG used to plug a session-bound, transparent variant of Tier 4 underneath every Edge navigation; once Tier 1 hardening (ACG, CET, ESM) closed the marginal-security gap on the &lt;em&gt;typical&lt;/em&gt; navigation, that session-bound Tier 4 paid more than it saved, and was deleted.&lt;/p&gt;
&lt;h2&gt;9. Engineering Takeaways&lt;/h2&gt;
&lt;p&gt;A few rules of thumb fall out of the architectural comparison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use the lowest tier whose boundary you actually need.&lt;/strong&gt; If your threat is &quot;this binary may try to escape the renderer,&quot; AppContainer + process mitigations suffice. If your threat is &quot;this binary may try to escape the kernel,&quot; you need a Hyper-V partition; that means Sandbox or, for production, an isolation container. The Microsoft Servicing Criteria for Windows [@microsoft-com-servicing-criteria] lists which boundaries Microsoft commits to defending; anything not on that list is best treated as a depth-in-defense layer, not a primary boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disable shared channels first; renegotiate them only when forced.&lt;/strong&gt; The default &lt;code&gt;.wsb&lt;/code&gt;-less Sandbox enables networking and clipboard redirection -- per the configuration docs [@learn-microsoft-com-wsb-file], enabled networking &quot;can expose untrusted applications to the internal network.&quot; For malware triage, build the paranoid &lt;code&gt;.wsb&lt;/code&gt; from the snippet in section 2 and only loosen it when a specific analysis step requires it.&lt;/p&gt;
&lt;p&gt;{`
// A naive but useful decision tree. Print the recommended tier for a workload.
function pickTier(workload) {
  const w = workload.toLowerCase();
  if (w.includes(&quot;untrusted exe&quot;) || w.includes(&quot;malware&quot;)) {
    return &quot;Tier 4: Windows Sandbox (on-demand, gesture-bound)&quot;;
  }
  if (w.includes(&quot;untrusted website&quot;) || w.includes(&quot;unfamiliar site&quot;)) {
    return &quot;Tier 1: Edge Enhanced Security Mode + Tier 3: Defender network protection&quot;;
  }
  if (w.includes(&quot;untrusted document&quot;) || w.includes(&quot;office&quot;)) {
    return &quot;Tier 3: Smart App Control + Office Protected View&quot;;
  }
  if (w.includes(&quot;third-party app&quot;) || w.includes(&quot;uwp&quot;)) {
    return &quot;Tier 2: AppContainer&quot;;
  }
  return &quot;Default: ship the workload under Tier 2 AppContainer; escalate if the threat model justifies it.&quot;;
}&lt;/p&gt;
&lt;p&gt;[
  &quot;Detonate untrusted exe from email&quot;,
  &quot;Open an unfamiliar site for research&quot;,
  &quot;Open an untrusted Office document&quot;,
  &quot;Run a third-party packaged app&quot;
].forEach(w =&amp;gt; console.log(w + &quot;  -&amp;gt;  &quot; + pickTier(w)));
`}&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid features whose own boundary is not a serviced boundary.&lt;/strong&gt; A useful litmus test is to read the Microsoft Security Servicing Criteria for Windows [@microsoft-com-servicing-criteria] and ask whether the feature&apos;s own claimed isolation appears there. WDAG didn&apos;t; Hyper-V VM did. Designs that rely on a non-serviced isolation are more brittle, both technically (no bounty pressure on the boundary) and operationally (no commitment to fix integration bugs out-of-band).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plan for deprecation of integration features, not of primitives.&lt;/strong&gt; Microsoft retired WDAG; it did not retire HCS, Hyper-V isolation containers, or AppContainer. The primitives outlast the productizations. A codebase that depends on the primitives (calling HCS directly, wrapping a workload in AppContainer) is more durable than one that depends on a packaged feature (calling &lt;code&gt;IIsolatedAppLauncher&lt;/code&gt;, relying on Network Isolation policy semantics) whose lifecycle is set by product economics.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Workloads that traverse a Sandbox boundary leave specific telemetry. The host event log records &lt;code&gt;Containers-DisposableClientVM&lt;/code&gt; start/stop events; HCS partition allocations are visible to ETW; mapped-folder access from inside the guest crosses a brokered channel that surfaces in host file-system filters. If an incident response playbook expects to see &quot;Hyper-V partition created&quot; or &quot;container-disposable-client-vm started,&quot; those are the canonical signals from the substrate, not from Sandbox-specific telemetry.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;10. Open Problems and Future Direction&lt;/h2&gt;
&lt;p&gt;The 2026 stack is good. It is not finished. Several open problems remain visible at the seams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transparent, gesture-priced isolation.&lt;/strong&gt; WDAG&apos;s session-bound model failed; Sandbox&apos;s gesture-bound model is too explicit for everyday use. There is no current Windows feature that combines (a) automatic, policy-driven launch (&quot;this URL is outside the trust zone, isolate it&quot;), (b) Sandbox-style on-demand allocation, and (c) sub-second cold start. Each pair of those three is achievable -- WDAG had (a) and (b) but not (c); Sandbox has (b) and (c) but not (a); ESM has (a) and (c) but gives up the partition boundary. Closing all three simultaneously is the standing open problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hardware-rooted attestation of the partition.&lt;/strong&gt; Today&apos;s Hyper-V partition is anchored by VBS, which is anchored by Secure Boot, which is anchored by the platform firmware. Microsoft Pluton [@learn-microsoft-com-security-processor] -- &quot;a secure crypto-processor built into the CPU... designed to provide the functionality of the Trusted Platform Module (TPM) and deliver other security functionality beyond what is possible with the TPM 2.0 specification&quot; -- raises the floor on what a guest can attest about, opening a path to confidential-VM-style guarantees on the client. The shape of that integration with Sandbox is not yet public.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Confidential client VMs.&lt;/strong&gt; On the server, Azure confidential VMs [@learn-microsoft-com-vm-overview] provide a &quot;hardware-enforced boundary between your application and the virtualization stack&quot; via AMD SEV-SNP and Intel TDX, with &quot;secure key release with cryptographic binding between the platform&apos;s successful attestation and the VM&apos;s encryption keys.&quot; Whether that boundary -- guest memory unreadable by the host kernel -- ever shows up under client Windows Sandbox or Hyper-V is an open architectural question. If it does, it changes the Hyper-V VM threat model: a malicious &lt;em&gt;host&lt;/em&gt; (or compromised host kernel) could no longer read guest memory, which would close a category of risk that currently sits outside the bounty scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI-agent action containment.&lt;/strong&gt; WDAG&apos;s specific shape -- a session-bound partition that transparently absorbed risky actions on behalf of a user -- is suggestive of an emerging problem: containing the actions of AI agents that take tool-using steps inside a user&apos;s session. Today&apos;s stack does not have a feature shaped quite like this. Sandbox is too explicit; AppContainer is too process-bound; ESM is browser-only; Smart App Control is admit/deny, not contain/observe. An &quot;AI-agent action sandbox&quot; would need WDAG&apos;s transparency without WDAG&apos;s resident-per-employee cost. The architectural question is whether the lessons of WDAG&apos;s retirement should make the next attempt look like Sandbox-with-a-policy-trigger or like AppContainer-with-a-stronger-boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shared-microarchitectural-state side channels.&lt;/strong&gt; The Hyper-V VM boundary is a logical boundary. The CPU caches, branch predictors, and prefetch units are still shared with the host. Spectre-class side channels survive partition boundaries and survive confidential-VM boundaries; the canonical Meltdown/Spectre disclosure [@meltdownattack-com] frames the primitive as a class of transient-execution attacks against the shared microarchitectural state itself, and Microsoft&apos;s KB4072698 guidance for speculative-execution side-channel vulnerabilities [@support-microsoft-com-b632-0d96f30c8c8e] catalogs a long succession of advisories (ADV180002, ADV180012, ADV180018 L1TF, ADV190013 MDS, ADV220002 MMIO Stale Data, CVE-2022-23825 Branch Type Confusion, CVE-2022-0001 Branch History Injection, CVE-2023-20569 AMD Return Address Predictor) that each required Hyper-V-host mitigation to keep the partition boundary effective. Mitigations close &lt;em&gt;known&lt;/em&gt; variants at the cost of performance, but the underlying primitive -- one core, two security domains -- does not change. The ideal sandbox -- sub-second cold start, single-digit-MB resident overhead, transparent policy launch, &lt;em&gt;and&lt;/em&gt; a partition boundary that closes all microarchitectural channels -- remains unachievable on shared silicon. This is not a Windows-specific problem; it is the lower bound on what any client-side sandbox can deliver.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The 2026 isolation stack is the right shape for the threats it was designed against: a malicious binary, an unfamiliar website, an untrusted document, a third-party app. It is not yet shaped for the threats that will dominate 2027 and beyond: confidential client compute, agent action containment, hardware-rooted attestation. Watching where the next partition-shaped primitive appears -- or fails to -- is how the architecture will continue to evolve.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;Windows Sandbox and WDAG are the cleanest natural experiment Windows has run on Hyper-V isolation as a product. Same substrate, same partition primitive, same bounty-protected boundary; opposite lifecycle bindings, opposite threat models, opposite outcomes. The substrate survives because the substrate is the boundary; the productizations come and go because they are bets on how to spend that boundary&apos;s budget. WDAG bet on session-bound transparency and lost to a cheaper process-mitigation stack; Sandbox bet on gesture-bound disposability and remains the right answer for the workload it was designed for. The story is less about Hyper-V and more about lifecycle: when you allocate isolation matters as much as how much isolation you allocate.&lt;/p&gt;
</content:encoded><category>windows-security</category><category>hyper-v</category><category>sandbox</category><category>application-guard</category><category>isolation</category><category>hcs-api</category><category>vbs</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The ACPI Tables That Quietly Secure Your Windows Machine</title><link>https://paragmali.com/blog/the-acpi-tables-that-quietly-secure-your-windows-machine/</link><guid isPermaLink="true">https://paragmali.com/blog/the-acpi-tables-that-quietly-secure-your-windows-machine/</guid><description>Five small ACPI tables -- DMAR, IORT, WSMT, SDEV, WPBT -- form the firmware-OS contract behind VBS, Credential Guard, Kernel DMA Protection, and BitLocker.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
Windows&apos;s strongest security guarantees -- Credential Guard, BitLocker, Kernel DMA Protection, Memory Integrity -- all rest on five small ACPI tables the OEM&apos;s firmware writes before the Windows boot loader runs. Two of them (DMAR / IORT, WSMT) are hard prerequisites for VBS launch; one (SDEV) decides which devices the Secure Kernel may partition; one (WPBT) lets the firmware drop a SYSTEM-privileged binary into Windows on every boot, and accepted revoked certificates until 2021. This article walks each table, the failure families they admit, and the inventory commands to audit them on your own laptop.
&lt;h2&gt;1. A Revoked Cert, A Secured-Core PC, A 52-Byte Table&lt;/h2&gt;
&lt;p&gt;In September 2021, researchers at Eclypsium published a video of a Secured-Core PC -- the most heavily protected Windows configuration money can buy, with Credential Guard, HVCI, BitLocker, and Kernel DMA Protection all enabled -- being silently rooted at boot [@eclypsium-wpbt]. The malicious binary was Authenticode-signed with a Hacking Team code-signing certificate that had been revoked six years earlier. Windows ran it anyway, with SYSTEM privileges, before the user even reached the lock screen. The mechanism was a single ACPI table almost no one outside platform-firmware engineering can name.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Eclypsium researchers wrote: &lt;em&gt;&quot;This issue affects all Windows-based devices going back to Windows 8 when WPBT was first introduced. We have successfully demonstrated the attack on modern, Secured-Core PCs that are running the latest boot protections&quot;&lt;/em&gt; [@eclypsium-wpbt]. Microsoft&apos;s recommended mitigation was not to fix the certificate validator. It was to ask customers to author a Windows Defender Application Control policy that constrains WPBT-injected binaries [@eclypsium-wpbt].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How is this possible if every box on the security checklist was ticked? The answer is structural. Every modern Windows guarantee -- Credential Guard isolating LSASS in a higher Virtual Trust Level, the &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel&lt;/a&gt; partitioning a Windows Hello IR camera away from kernel-mode drivers, &lt;a href=&quot;https://paragmali.com/blog/bitlocker-on-windows-architecture-attacks-and-the-limits-of-/&quot; rel=&quot;noopener&quot;&gt;BitLocker&lt;/a&gt; sealing volume keys against PCR[7], Kernel DMA Protection blocking a Thunderclap-class peripheral [@thunderclap-io] -- assumes 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;hypervisor&lt;/a&gt; came up &lt;em&gt;knowing the correct shape of the platform&lt;/em&gt;. That shape is not discovered by Windows. It is described to Windows, in five small ACPI tables the OEM&apos;s UEFI firmware built before the Windows boot manager even started.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every modern Windows security guarantee assumes the hypervisor came up knowing the correct shape of the platform. That shape is described in five small ACPI tables the OEM&apos;s UEFI firmware built before the Windows boot manager even started. The hardware does the enforcement; the tables decide what gets enforced.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Their names, in the order this article walks them, are &lt;strong&gt;DMAR&lt;/strong&gt; (Intel VT-d, the IOMMU table on x86 [@acpica-actbl1]), &lt;strong&gt;IORT&lt;/strong&gt; (the Arm SMMU analogue [@acpica-actbl2-iort]), &lt;strong&gt;WSMT&lt;/strong&gt; (the OEM&apos;s pact with Microsoft about System Management Mode behaviour [@acpica-actbl3-wsmt]), &lt;strong&gt;SDEV&lt;/strong&gt; (the list of devices the Secure Kernel may wall off from non-secure code [@acpi-65-sdev]), and &lt;strong&gt;WPBT&lt;/strong&gt; (the channel by which the firmware can drop a binary into &lt;code&gt;c:\windows\system32&lt;/code&gt; and run it on every boot [@acpica-actbl3-wpbt]). Each table is a few dozen to a few thousand bytes. Together, they are the firmware-OS contract on which everything else above the hypervisor depends.&lt;/p&gt;
&lt;p&gt;Four questions fall out of that framing, and the rest of this article answers each in turn. &lt;em&gt;Who populates these tables?&lt;/em&gt; &lt;em&gt;Who validates them?&lt;/em&gt; &lt;em&gt;What does Windows do when they are wrong?&lt;/em&gt; &lt;em&gt;What does the attacker get when they forge them?&lt;/em&gt; Along the way we will encounter the design idiom that recurs across every one of the five: the OEM declares a property the operating system has no independent way to verify. Microsoft&apos;s own engineers say so on the public Learn page for WSMT [@ms-oem-uefi-wsmt]. Once you internalise that idiom, the rest of the article reads as five variations on a single theme.&lt;/p&gt;
&lt;p&gt;This is the substrate article in a longer series on Windows platform security. The hypervisor-as-isolation-primitive [@hyperv-sibling], the trustlets that run in the Secure Kernel [@vbs-trustlets-sibling], &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Pluton-as-TPM&lt;/a&gt; [@pluton-sibling], the &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;discrete TPM&lt;/a&gt; [@tpm-sibling], BitLocker [@bitlocker-sibling], &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; [@secure-boot-sibling], application identity and code-integrity policy [@app-identity-sibling], and USB device-arrival policy [@plug-and-trust-sibling] all rest on these five tables. We do not redefine those concepts; we trace where they touch the table set, and we link out where the curious reader wants the deeper tour.&lt;/p&gt;
&lt;p&gt;So: where do these tables come from in the first place? They have a thirty-year history that explains the structural problem.&lt;/p&gt;
&lt;h2&gt;2. ACPI as the Firmware-OS Contract: 1996 to Now&lt;/h2&gt;
&lt;p&gt;How did we get from &quot;describing sleep states&quot; to &quot;deciding whether Credential Guard turns on&quot;? The answer is a thirty-year drift, and it is worth a short tour because each new table answered an attack class the prior contract could not describe.&lt;/p&gt;
&lt;p&gt;ACPI 1.0 shipped in December 1996, jointly authored by Intel, Microsoft, and Toshiba; HP, Huawei, and Phoenix joined later, and in October 2013 the ACPI Special Interest Group transferred all assets to the UEFI Forum, which still publishes the standard today (current revision 6.6, released May 13, 2025) [@wikipedia-acpi]. The original idea was modest: replace the Advanced Power Management 1.x INT 15h real-mode mess with a &lt;em&gt;generic table-passing chassis&lt;/em&gt; the OS could read in protected mode.APM 1.0 shipped in 1992; revision 1.2 in 1996 was the last version of the spec, and Microsoft dropped APM support in Windows Vista [@wikipedia-apm]. APM expected the OS to invoke real-mode BIOS routines through INT 15h; once Windows ran a hardware abstraction layer in protected mode that was no longer architecturally tolerable.&lt;/p&gt;

The firmware-written, OS-read table format that describes a platform&apos;s non-discoverable devices, capabilities, and security properties. The OS finds an entry-point structure (the RSDP) via the EFI system table, walks it to either an RSDT or XSDT, and from there reads typed tables identified by 4-byte ASCII signatures.
&lt;p&gt;The mechanics are uniform. Microsoft&apos;s own bring-up documentation describes them verbatim: &lt;em&gt;&quot;Windows depends on UEFI firmware to boot up the hardware platform . . . The platform firmware fills in the address of either the RSDT or XSDT in the RSDP. (If both table addresses are provided, Windows prefers the XSDT)&quot;&lt;/em&gt; [@ms-acpi-tables]. Each table carries the same 36-byte header (signature, length, revision, checksum, OEM ID, OEM table ID, OEM revision, creator ID, creator revision); the body is signature-specific. The contract: &lt;strong&gt;firmware writes typed tables, the OS reads them, the OS trusts them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the first decade of ACPI, every table described power, addressing, or device topology. Then the security tables began to arrive, one per attack class, each one narrowing the gap between &lt;em&gt;what hardware can do&lt;/em&gt; and &lt;em&gt;what the OS believes the hardware will do&lt;/em&gt;.&lt;/p&gt;

timeline
    title ACPI security-table genealogy
    1996 : ACPI 1.0 released (Dec, Intel/Microsoft/Toshiba)
    2007 : DMAR introduced (Intel VT-d / Q35)
    2011 : WPBT spec dated 29 November (Windows 8 era)
    2015 : IORT introduced (ACPI 6.0, April)
    2016 : WSMT v1.0 dated 18 April (Windows 10 v1607)
    2017 : SDEV introduced (ACPI 6.2, May)
    2021 : Eclypsium discloses WPBT revoked-cert acceptance
    2025 : ACPI 6.6 published (May 13)
&lt;p&gt;Timeline date sources, in row order: ACPI 1.0 [@wikipedia-acpi]; DMAR with Intel Q35 [@acpica-actbl1]; WPBT [@acpica-actbl3-wpbt]; IORT in ACPI 6.0 [@acpica-actbl2-iort]; WSMT v1.0 [@acpica-actbl3-wsmt]; SDEV in ACPI 6.2 [@acpica-actbl2-sdev]; Eclypsium 2021 [@eclypsium-wpbt]; ACPI 6.6 May 13, 2025 [@wikipedia-acpi].&lt;/p&gt;
&lt;p&gt;The arc compresses to five timestamps. &lt;strong&gt;DMAR&lt;/strong&gt;, around 2007 with Intel&apos;s Q35 chipset and the first VT-d implementations, was the first ACPI table whose purpose was &lt;em&gt;security&lt;/em&gt; rather than power: it described the IOMMU translation contexts that let the OS confine a peripheral&apos;s DMA reach [@acpica-actbl1]. &lt;strong&gt;WPBT&lt;/strong&gt;, dated November 29, 2011 in the ACPICA conformance comment and shipped with Windows 8 [@acpica-actbl3-wpbt; @eclypsium-wpbt], was the first table whose payload was &lt;em&gt;executable code&lt;/em&gt;: a physical pointer to a binary that Windows would copy into &lt;code&gt;system32&lt;/code&gt; and run. &lt;strong&gt;IORT&lt;/strong&gt;, introduced in ACPI 6.0 in April 2015 [@acpica-actbl2-iort], extended the IOMMU-description idea to Arm; the substrate became pan-architectural. &lt;strong&gt;WSMT&lt;/strong&gt;, version 1.0 dated April 18, 2016 and supported in Windows 10 v1607 [@acpica-actbl3-wsmt; @ms-oem-uefi-wsmt], was the first table whose payload was an &lt;em&gt;OEM warranty about behaviour Windows cannot verify&lt;/em&gt;. &lt;strong&gt;SDEV&lt;/strong&gt;, introduced in ACPI 6.2 in May 2017 [@acpi-65-sdev; @acpica-actbl2-sdev], was the first table whose role was to &lt;em&gt;describe the security partition itself&lt;/em&gt; -- a hint about which devices belong inside the Secure Kernel.&lt;/p&gt;
&lt;p&gt;A pattern unifies them. In every case, the OEM &lt;em&gt;describes&lt;/em&gt; a boundary the OS does not have an independent way to verify. WSMT articulates the principle most explicitly: &lt;em&gt;&quot;Because SMM is opaque to the operating system, it is not possible to produce a test which runs in Windows to verify that the protections prescribed in the WSMT specification are actually implemented in SMM&quot;&lt;/em&gt; [@ms-oem-uefi-wsmt]. The same shape recurs in DMAR (the firmware describes the address-translation policy; Windows trusts that the IOMMU is enabled and that no over-broad reserved memory regions punch holes in it), in SDEV (the firmware lists secure devices; Windows trusts that the listing is correct and complete), and in WPBT (the firmware nominates a binary; Windows trusts that the signature was, until 2021, sufficient to keep adversaries out).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The ACPI security-table set is &lt;em&gt;attestable but not enforceable&lt;/em&gt; from inside Windows. The OEM declares a property; the OS reads the declaration; the OS cannot independently refute lies in the contents. Every generation of mitigation since -- Secured-core PC certification, Pluton-rooted measured boot, Windows Defender Application Control over WPBT -- is an attempt to turn one corner of that unenforceable contract into an enforceable check, either pre-ship, at boot, or per-deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the firmware describes the platform and the OS trusts the description, what happens when the firmware describes a peripheral that can DMA-read your password? That is the IOMMU question. It is the oldest of the five tables, and the cleanest example of the &lt;em&gt;table describes; hardware enforces&lt;/em&gt; pattern. Its name is DMAR -- and on Arm, IORT.&lt;/p&gt;
&lt;h2&gt;3. DMAR and IORT: The IOMMU Tables That Make Kernel DMA Protection Possible&lt;/h2&gt;
&lt;p&gt;In the mid-2000s a researcher named Maximillian Dornseif demonstrated, in 2004, that he could plug an iPod into a locked laptop over FireWire and read the laptop&apos;s physical memory [@wikipedia-dma-attack]. The fix took fifteen years. Here is why.&lt;/p&gt;
&lt;p&gt;The DMA-attack class is older than the IOMMU. FireWire and OHCI 1394 SBP-2 spoofing made it concrete in the 2000s; Thunderbolt 1 (2011) and Thunderbolt 2 (2013) brought the same primitive back through a different connector [@wikipedia-dma-attack]; in February 2019, the Thunderclap NDSS paper by A. Theodore Markettos, Colin Rothwell, Brett F. Gutstein, Allison Pearce, Peter G. Neumann, Simon W. Moore, and Robert N. M. Watson demonstrated that &lt;em&gt;even with the IOMMU on&lt;/em&gt;, OS-side mistakes in &lt;em&gt;what the table describes&lt;/em&gt; let a malicious peripheral exfiltrate keys in seconds [@thunderclap-io]. The paper is the load-bearing academic primary for the entire genre.&lt;/p&gt;

The hardware unit that translates per-device DMA addresses to physical addresses, restricting a peripheral&apos;s DMA reach to assigned pages. On x86 it is Intel VT-d or AMD-Vi; on Arm it is the SMMU. Per Wikipedia: *&quot;Memory is protected from malicious devices that are attempting DMA attacks and faulty devices that are attempting errant memory transfers because a device cannot read or write to memory that has not been explicitly allocated (mapped) for it&quot;* [@wikipedia-iommu].
&lt;p&gt;Microsoft&apos;s first software-side DMA defence appeared in the Windows 7 era as a registry-driven disablement of FireWire SBP-2 attaches when the screen was locked [@wikipedia-dma-attack]. It was a dead end. Thunderbolt brought the same primitive back through a different connector almost immediately, and the only durable answer was to enrol the IOMMU.&lt;/p&gt;
&lt;h3&gt;DMAR: the Intel VT-d table&lt;/h3&gt;
&lt;p&gt;DMAR is the table whose body Windows reads to decide whether DMA remapping is even possible. The ACPICA reference header (&lt;code&gt;actbl1.h&lt;/code&gt;) declares the signature and the conformance: &lt;em&gt;&lt;code&gt;#define ACPI_SIG_DMAR &quot;DMAR&quot;  /* DMA Remapping table */&lt;/code&gt;&lt;/em&gt; and &lt;em&gt;&quot;Conforms to &apos;Intel Virtualization Technology for Directed I/O&apos;, Version 2.3, October 2014&quot;&lt;/em&gt; [@acpica-actbl1].&lt;/p&gt;
&lt;p&gt;The body is a sequence of typed sub-tables. The taxonomy from &lt;code&gt;actbl1.h&lt;/code&gt;, with the byte values that identify each sub-table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sub-table&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;DRHD (Hardware Unit)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Describes a single VT-d remapping unit and the devices it covers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RMRR (Reserved Memory)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Identity-mapped memory windows for legitimate firmware-DMA needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ATSR (Root ATS)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;PCIe Address Translation Services support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RHSA (Hardware Affinity)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NUMA affinity for remapping units&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ANDD (Namespace)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;ACPI Namespace Device Descriptors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SATC&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;SoC Integrated Address Translation Cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIDP&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;SoC-Integrated Device Property Reporting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The top-level Flags byte declares three platform-level properties: &lt;code&gt;ACPI_DMAR_INTR_REMAP&lt;/code&gt; (bit 0, interrupt remapping support), &lt;code&gt;ACPI_DMAR_X2APIC_OPT_OUT&lt;/code&gt; (bit 1), and &lt;code&gt;ACPI_DMAR_X2APIC_MODE&lt;/code&gt; (bit 2) [@acpica-actbl1]. Microsoft&apos;s Windows-side opt-in piggy-backs onto the same Flags byte: bit 2 must be set, and the Microsoft OEM Kernel DMA Protection page calls it &lt;code&gt;DMA_CTRL_PLATFORM_OPT_IN_FLAG&lt;/code&gt;, citing &lt;em&gt;Intel VT-d Spec Rev 2.5 Section 8.1&lt;/em&gt; as the authoritative definition [@oem-kernel-dma]. Without that bit set, Memory Access Protection stays off even if VT-d hardware is fully functional.&lt;/p&gt;

The AMD-side analogue is IVRS (I/O Virtualization Reporting Structure), and the OEM opt-in lives in a different field: *&quot;For AMD platforms, system firmware must set &apos;DMA remap support&apos; bit in the IVRS IVinfo field (AMD IOMMU Specification Rev 3.05, Section 5.2.1)&quot;* [@oem-kernel-dma]. DMAR, IVRS, and IORT are mutually exclusive on a given platform; all three are first-class for Kernel DMA Protection. A laptop ships with exactly one of them depending on the silicon vendor.
&lt;h3&gt;IORT: the Arm SMMU table&lt;/h3&gt;
&lt;p&gt;IORT does the same job for the Arm SMMU. The ACPICA header pins the conformance: &lt;em&gt;&lt;code&gt;#define ACPI_SIG_IORT &quot;IORT&quot;&lt;/code&gt;&lt;/em&gt; and &lt;em&gt;&quot;Conforms to &apos;IO Remapping Table System Software on ARM Platforms&apos;, Document number: ARM DEN 0049E.f, Apr 2024&quot;&lt;/em&gt; [@acpica-actbl2-iort]. The node taxonomy, from the same header:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Node type&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;ITS_GROUP&lt;/td&gt;
&lt;td&gt;0x00&lt;/td&gt;
&lt;td&gt;GIC Interrupt Translation Service group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NAMED_COMPONENT&lt;/td&gt;
&lt;td&gt;0x01&lt;/td&gt;
&lt;td&gt;Non-PCI named device&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCI_ROOT_COMPLEX&lt;/td&gt;
&lt;td&gt;0x02&lt;/td&gt;
&lt;td&gt;PCIe root complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMMU&lt;/td&gt;
&lt;td&gt;0x03&lt;/td&gt;
&lt;td&gt;SMMUv1 / v2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SMMU_V3&lt;/td&gt;
&lt;td&gt;0x04&lt;/td&gt;
&lt;td&gt;SMMUv3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PMCG&lt;/td&gt;
&lt;td&gt;0x05&lt;/td&gt;
&lt;td&gt;Performance Monitoring Counter Group&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RMR&lt;/td&gt;
&lt;td&gt;0x06&lt;/td&gt;
&lt;td&gt;Reserved Memory Region (Arm analogue of x86 RMRR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IWB&lt;/td&gt;
&lt;td&gt;0x07&lt;/td&gt;
&lt;td&gt;I/O Wakeup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;IORT folds two responsibilities together that x86 keeps separate: in addition to describing SMMU translation contexts, it carries the GIC ITS entries that govern interrupt remapping. (On x86, GIC-ITS-equivalent MSI routing is governed by MADT APIC entries; VT-d interrupt remapping is a separate DMAR hardware capability, also described in the DMAR table via the INTR_REMAP flag.) Each PCI_ROOT_COMPLEX or NAMED_COMPONENT node carries an ID-mapping array of &lt;code&gt;(InputBase, IdCount, OutputBase, OutputReference)&lt;/code&gt; tuples that translate PCIe Requester IDs to SMMU StreamIDs. The mapping arithmetic is the IOMMU. The table just tells the OS where the arithmetic lives.&lt;/p&gt;
&lt;h3&gt;How Windows turns the table into policy&lt;/h3&gt;
&lt;p&gt;Kernel DMA Protection enrols when a small number of conditions all hold. Microsoft&apos;s documentation lays them out [@oem-kernel-dma; @kernel-dma-thunderbolt; @dma-remapping-drivers], and they form a textbook AND-gate.&lt;/p&gt;

flowchart TD
    A[DMAR/IVRS/IORT present?] --&amp;gt;|No| OFF[Kernel DMA Protection: Off]
    A --&amp;gt;|Yes| B[DMA_CTRL_PLATFORM_OPT_IN_FLAG set?]
    B --&amp;gt;|No| OFF
    B --&amp;gt;|Yes| C[VT-d/AMD-Vi/SMMU enabled in firmware setup?]
    C --&amp;gt;|No| OFF
    C --&amp;gt;|Yes| D{&quot;Driver opt-in?&quot;}
    D --&amp;gt;|No, legacy device| OFF2[Device denied DMA, KDP partially enrolled]
    D --&amp;gt;|Yes, RemappingSupported INF directive| ON[Kernel DMA Protection: On for this device]
&lt;p&gt;The driver opt-in deserves a closer look, because it is where Thunderclap left its scar. The legacy mechanism was a per-driver &lt;code&gt;DmaRemappingCompatible&lt;/code&gt; parameter; Windows 24H2 introduced a per-device &lt;code&gt;RemappingSupported&lt;/code&gt; INF directive that supersedes it [@dma-remapping-drivers]. The modern intent is finer-grained: a single driver may legitimately ship across compatible and incompatible device variants, and the per-device declaration is the only safe granularity. Graphics is the canonical hold-out -- WDDM 3.0+ drivers can opt in, but earlier graphics stacks could not, and shipping graphics cards before WDDM 3.0 effectively blocked Kernel DMA Protection on whole platforms [@kernel-dma-thunderbolt].&lt;/p&gt;
&lt;p&gt;When the AND-gate fails, Windows surfaces it as a single line in &lt;code&gt;msinfo32&lt;/code&gt; System Summary: &lt;code&gt;Kernel DMA Protection: Off&lt;/code&gt;. The remediation is rarely software. &lt;em&gt;&quot;Reboot into UEFI settings, Turn on Intel Virtualization Technology, Turn on Intel Virtualization Technology for I/O (VT-d)&quot;&lt;/em&gt; is Microsoft&apos;s own checklist [@kernel-dma-thunderbolt]. If the table is missing entirely, the only fix is an OEM BIOS update.&lt;/p&gt;
&lt;h3&gt;Three failure families, observable from inside Windows&lt;/h3&gt;
&lt;p&gt;Three observable failure families recur. &lt;em&gt;Missing DMAR / IVRS / IORT&lt;/em&gt; surfaces as &lt;code&gt;Kernel DMA Protection: Off&lt;/code&gt; and the only fix is a BIOS update [@kernel-dma-thunderbolt]. &lt;em&gt;Over-broad RMRR / RMR&lt;/em&gt; was the Thunderclap finding: even with the IOMMU on, identity-mapped memory windows that legitimately exist for USB handoff or integrated graphics can overlap sensitive memory; a malicious peripheral assigned to the same context exfiltrates secrets while the IOMMU faithfully reports it as policy-compliant [@thunderclap-io]. &lt;em&gt;VT-d disabled in firmware setup&lt;/em&gt; surfaces identically to a missing table; the remediation is a UEFI menu, not a Windows update.&lt;/p&gt;
&lt;p&gt;{`
function kdpDecision({dmarPresent, optInFlagSet, iommuEnabled, driverRemappingCompatible}) {
  if (!dmarPresent) return &quot;KDP: Off (reason: DMAR/IVRS/IORT table missing -- BIOS update required)&quot;;
  if (!optInFlagSet) return &quot;KDP: Off (reason: DMA_CTRL_PLATFORM_OPT_IN_FLAG not set in DMAR Flags byte)&quot;;
  if (!iommuEnabled) return &quot;KDP: Off (reason: VT-d/AMD-Vi disabled in UEFI setup)&quot;;
  if (!driverRemappingCompatible) return &quot;KDP: Off for that device (reason: driver lacks RemappingSupported INF entry)&quot;;
  return &quot;KDP: On&quot;;
}&lt;/p&gt;
&lt;p&gt;console.log(&quot;Secured-Core PC:    &quot;, kdpDecision({dmarPresent:true, optInFlagSet:true, iommuEnabled:true, driverRemappingCompatible:true}));
console.log(&quot;OEM omission:       &quot;, kdpDecision({dmarPresent:false, optInFlagSet:false, iommuEnabled:true, driverRemappingCompatible:true}));
console.log(&quot;VT-d disabled:      &quot;, kdpDecision({dmarPresent:true, optInFlagSet:true, iommuEnabled:false, driverRemappingCompatible:true}));
console.log(&quot;Driver not opted-in:&quot;, kdpDecision({dmarPresent:true, optInFlagSet:true, iommuEnabled:true, driverRemappingCompatible:false}));
`}&lt;/p&gt;
&lt;p&gt;The Thunderclap residual is the article&apos;s first &lt;em&gt;aha&lt;/em&gt; moment. The IOMMU is on. The hardware is working. The OS has read DMAR and turned on Kernel DMA Protection. And a malicious Thunderbolt device exfiltrates a TLS key in a few seconds, because the &lt;em&gt;table&lt;/em&gt; described an RMRR that overlaps the victim driver&apos;s heap, or because the victim driver shared sensitive memory with a peripheral DMA window. The hardware was not the issue. The &lt;em&gt;table&lt;/em&gt; was. From this point forward in the article, you should not ask &lt;em&gt;&quot;is the IOMMU on?&quot;&lt;/em&gt; You should ask &lt;em&gt;&quot;is the IOMMU on, and did the firmware describe the right thing?&quot;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; DMAR (Intel), IVRS (AMD), and IORT (Arm) are mutually exclusive on a given platform. All three are first-class for Kernel DMA Protection; the OEM opt-in flag lives in a different field of each, and the Windows-side prerequisites are otherwise the same.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The IOMMU question was an above-the-board hardware boundary. The next question is below-the-board: System Management Mode, the privilege level above the kernel that the OS literally cannot inspect. Microsoft&apos;s response was to make the OEMs sign a pact about it. The pact is a 40-byte ACPI table (a 36-byte ACPI header plus a 4-byte ProtectionFlags field) called WSMT.&lt;/p&gt;
&lt;h2&gt;4. WSMT: Microsoft&apos;s Pact With OEMs About SMM&lt;/h2&gt;
&lt;p&gt;There is a CPU privilege level above the kernel. Windows cannot see what runs there. So Microsoft made the OEMs sign a pact about it.&lt;/p&gt;

An x86 CPU mode entered via System Management Interrupt (SMI). SMM code runs in SMRAM, a region of physical memory the OS cannot map or read. SMI handlers run with full physical-memory access and can read, write, and modify any kernel structure. SMM is sometimes called *ring -2* because it sits architecturally below Hyper-V&apos;s *ring -1*. The Intel 386SL was the first chip to implement it; every modern x86 CPU does [@wikipedia-smm].

A class of attack where a less-privileged caller induces a more-privileged subject to perform an unintended action by passing in attacker-controlled inputs the subject does not validate. In the SMM case, an unprivileged kernel-mode caller hands an SMI handler a pointer to memory the kernel controls; the SMI handler dereferences it without checking whether the target lives inside SMRAM, and the attacker has just bought a write into ring -2.
&lt;p&gt;The attack class is older than the table. UEFI rootkits like LoJax (September 2018), attributed to Sednit / APT28 by ESET, weaponised SMM-adjacent persistence: &lt;em&gt;&quot;This persistence method is particularly invasive as it will not only survive an OS reinstall, but also a hard disk replacement&quot;&lt;/em&gt; [@eset-lojax-html]. The 2015 Hacking Team breach published an entire UEFI rootkit module along with the code-signing certificate that Eclypsium would later reuse in 2021 [@mitre-attack-s0047].The Hacking Team certificate that drove the 2021 Eclypsium WPBT proof-of-concept was the same one shipped with the 2015 Hacking Team UEFI module. A revoked code-signing cert from one breach became the unlock for an unrelated table six years later, because the WPBT signature gate did not check revocation. A software-only OS-side fix to the SMI-handler-pointer-validation problem is impossible by construction: Windows cannot inspect SMM code, and SMRAM is not addressable to it.&lt;/p&gt;
&lt;p&gt;So Microsoft did the only thing that was tractable. On April 18, 2016, version 1.0 of the Windows SMM Security Mitigations Table specification was published [@acpica-actbl3-wsmt]. The body is one 32-bit field. ACPICA codifies it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct acpi_table_wsmt {
    ACPI_TABLE_HEADER Header;
    UINT32            ProtectionFlags;
} ACPI_TABLE_WSMT;

#define ACPI_WSMT_FIXED_COMM_BUFFERS                (1)
#define ACPI_WSMT_COMM_BUFFER_NESTED_PTR_PROTECTION (2)
#define ACPI_WSMT_SYSTEM_RESOURCE_PROTECTION        (4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three bits. Each bit is a warranty by the OEM that their SMI handlers behave correctly in one specific way. Microsoft&apos;s published semantics, paraphrased lightly so the bits read as English [@ms-oem-uefi-wsmt]:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Bit&lt;/th&gt;
&lt;th&gt;What the OEM warrants&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FIXED_COMM_BUFFERS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x1&lt;/td&gt;
&lt;td&gt;All SMI communication buffers live in firmware-allocated memory of fixed location and size; SMM never reads or writes outside those buffers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COMM_BUFFER_NESTED_PTR_PROTECTION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x2&lt;/td&gt;
&lt;td&gt;Pointers nested inside those buffers are validated against the same allowed regions before SMM dereferences them (the confused-deputy fix)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SYSTEM_RESOURCE_PROTECTION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0x4&lt;/td&gt;
&lt;td&gt;Critical platform resources (CPU MSRs, chipset registers) are guarded from unintended SMM modification by lower-privilege callers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;When does Windows read this table? &lt;em&gt;&quot;Supported versions of the Windows operating system read in the Windows SMM Security Table early during initialization, prior to start of the ACPI interpreter&quot;&lt;/em&gt; [@ms-wsmt-fixed-combuffer]. &lt;em&gt;Prior to start of the ACPI interpreter&lt;/em&gt; is the load-bearing phrase. Windows has not yet booted the hypervisor when it consumes WSMT; it has not yet decided whether to launch VBS. The table is read first; the decision follows.&lt;/p&gt;

sequenceDiagram
    participant FW as OEM Firmware (build time)
    participant POST as POST / DXE
    participant BL as Windows Boot Manager
    participant WBL as Winload.efi
    participant HV as Hyper-V
    participant VBS as VBS / Secure Kernel
    FW-&amp;gt;&amp;gt;POST: Build WSMT with ProtectionFlags
    POST-&amp;gt;&amp;gt;BL: Hand off ACPI table set via EFI system table
    BL-&amp;gt;&amp;gt;WBL: Load winload.efi
    WBL-&amp;gt;&amp;gt;WBL: Read WSMT prior to ACPI interpreter start
    alt Flags == 0x7 (all three asserted)
        WBL-&amp;gt;&amp;gt;HV: Launch hypervisor
        HV-&amp;gt;&amp;gt;VBS: Start Secure Kernel, enrol Credential Guard / HVCI
    else Flags partial or missing
        WBL-&amp;gt;&amp;gt;WBL: De-feature: VBS may not start, HVCI may stay disabled
    end
&lt;p&gt;The OEM-VBS page makes WSMT a hard prerequisite, not a nice-to-have: &lt;em&gt;&quot;Firmware support for SMM protection -- System firmware must adhere to the recommendations for hardening SMM code described in the Windows SMM Security Mitigations Table (WMST) specification . . . Firmware must implement the protections described in the WSMT specification, and set the corresponding protection flags as described in the specification to report compliance with these requirements to the operating system&quot;&lt;/em&gt; [@oem-vbs]. If the flags are clear, VBS may de-feature. Memory Integrity may not enable. Credential Guard may refuse to start. The customer never sees a banner; they see the absence of a feature.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s OEM page on Virtualization-based security makes WSMT compliance with the corresponding Protection Flags asserted a hard prerequisite for VBS launch [@oem-vbs]. A laptop without WSMT, or with the flags clear, may report that VBS is &lt;em&gt;available&lt;/em&gt; and yet refuse to start it on every boot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The structural punchline lands here, in Microsoft&apos;s own words:&lt;/p&gt;

Because SMM is opaque to the operating system, it is not possible to produce a test which runs in Windows to verify that the protections prescribed in the WSMT specification are actually implemented in SMM. From the operating system, the only check that is possible is to look for the presence of the WSMT, and check the state of all defined Protection Flags. -- Microsoft Learn, *Windows SMM Security Mitigations Table* [@ms-oem-uefi-wsmt]
&lt;p&gt;This is the article&apos;s second &lt;em&gt;aha&lt;/em&gt; moment. &lt;em&gt;Windows reads the flags. Windows trusts the flags. Windows cannot verify the flags.&lt;/em&gt; The OEM declares; Windows reads; Windows cannot refute. Once you internalise that idiom, every other ACPI security table in this article reads as a variation on it. SDEV declares which devices are secure. WPBT declares which binary is signed. DMAR declares which RMRR ranges are legitimate. In every case, the OEM authors a property and Windows believes it.&lt;/p&gt;
&lt;p&gt;A worked example makes the consequence concrete. Open a PowerShell prompt and run &lt;code&gt;Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard&lt;/code&gt;. The two fields that matter are &lt;code&gt;VirtualizationBasedSecurityStatus&lt;/code&gt; (0 = off, 1 = enabled but not running, 2 = running) and &lt;code&gt;SecurityServicesRunning&lt;/code&gt; (an array, where 1 = Credential Guard and 2 = HVCI). On a machine where WSMT is missing or its flags are clear, you may see &lt;code&gt;VirtualizationBasedSecurityStatus = 1&lt;/code&gt; and an empty &lt;code&gt;SecurityServicesRunning&lt;/code&gt; array. The system &lt;em&gt;intends&lt;/em&gt; to run VBS. The system &lt;em&gt;cannot&lt;/em&gt; run VBS. The cause is invisible until you consult the DeviceGuard WMI class -- and even then, the WSMT influence is implicit, not named.&lt;/p&gt;
&lt;p&gt;WSMT tells the hypervisor what SMM promised not to do. The next table tells the hypervisor which devices to wall off from non-secure code in the first place. Its name is SDEV.&lt;/p&gt;
&lt;h2&gt;5. SDEV: The Firmware Tells the Hypervisor Which Devices Are For Trustlets Only&lt;/h2&gt;
&lt;p&gt;Your Windows Hello IR camera is supposed to be unreachable from a kernel-mode rootkit. How does Windows know it is the IR camera the firmware claims it is, and not, say, a USB device the attacker plugged in five seconds ago?&lt;/p&gt;
&lt;p&gt;The answer is SDEV. The ACPI 6.5 specification, Section 5.2.27, is unusually candid about what the table is and is not [@acpi-65-sdev]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;The Secure DEVices (SDEV) table is a list of secure devices known to the system. The table is applicable to systems where a secure OS partition and a non-secure OS partition co-exist. A secure device is a device that is protected by the secure OS, preventing accesses from non-secure OS. The table provides a hint as to which devices should be protected by the secure OS. The enforcement of the table is provided by the secure OS and any pre-boot environment preceding it. &lt;strong&gt;The table itself does not provide any security guarantees.&lt;/strong&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;

The table itself does not provide any security guarantees. -- ACPI Specification 6.5, Section 5.2.27 [@acpi-65-sdev]

An ACPI table introduced in ACPI 6.2 (May 2017) that enumerates the devices the firmware believes should be partitioned into the Secure Kernel rather than the normal kernel. The Windows-side consumer struct is `_SDEV_SECURE_ACPI_INFO_ENTRY`, available since Windows 10 version 2004 (May 2020) [@ms-sdev-struct].
&lt;h3&gt;The three states a device can be in&lt;/h3&gt;
&lt;p&gt;The spec defines three SDEV states, and they map directly onto what the Secure Kernel does at boot [@acpi-65-sdev]:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SDEV state&lt;/th&gt;
&lt;th&gt;Spec language&lt;/th&gt;
&lt;th&gt;Operational consequence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Listed, Allow-Handoff clear&lt;/td&gt;
&lt;td&gt;&lt;em&gt;&quot;the device should be always protected within the secure OS . . . the secure OS may require that a device used for user authentication must be protected to guard against tampering by malicious software&quot;&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Device is owned by VTL1 for the lifetime of the boot; the normal kernel cannot reach it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listed, Allow-Handoff set&lt;/td&gt;
&lt;td&gt;&lt;em&gt;&quot;the device should be initially protected by the secure OS, but it is up to the discretion of the secure OS to allow the device to be handed off to the non-secure OS when requested&quot;&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Secure Kernel takes ownership at boot but may release the device to VTL0 on demand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not listed&lt;/td&gt;
&lt;td&gt;&lt;em&gt;&quot;no hints are provided. Any OS component that expected the device to be in secure mode would not correctly function&quot;&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;Features that need a secure-device anchor (Enhanced Sign-in Security for Windows Hello, the vTPM trustlet) silently disable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The two SDEV entry types are, from ACPICA&apos;s &lt;code&gt;actbl2.h&lt;/code&gt;: &lt;em&gt;&lt;code&gt;ACPI_SDEV_TYPE_NAMESPACE_DEVICE = 0&lt;/code&gt;&lt;/em&gt; (an ACPI Namespace device path like &lt;code&gt;\_SB.PCI0.XHCI&lt;/code&gt;) and &lt;em&gt;&lt;code&gt;ACPI_SDEV_TYPE_PCIE_ENDPOINT_DEVICE = 1&lt;/code&gt;&lt;/em&gt; (a PCIe Bus / Device / Function tuple). The header Flags byte uses two bits: &lt;code&gt;ACPI_SDEV_HANDOFF_TO_UNSECURE_OS&lt;/code&gt; (bit 0) and &lt;code&gt;ACPI_SDEV_SECURE_COMPONENTS_PRESENT&lt;/code&gt; (bit 1) [@acpica-actbl2-sdev]. The &lt;em&gt;Allow-Handoff&lt;/em&gt; bit is the one that decides which of the three states above applies.&lt;/p&gt;
&lt;p&gt;The Windows-side struct is published on Microsoft Learn as &lt;code&gt;_SDEV_SECURE_ACPI_INFO_ENTRY&lt;/code&gt; [@ms-sdev-struct]:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct _SDEV_SECURE_ACPI_INFO_ENTRY {
  SDEV_ENTRY_HEADER Header;
  USHORT IdentifierOffset;
  USHORT IdentifierLength;
  USHORT VendorInfoOffset;
  USHORT VendorInfoLength;
  USHORT SecureResourcesOffset;
  USHORT SecureResourcesLength;
} SDEV_SECURE_ACPI_INFO_ENTRY;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Windows-side consumer struct lists &lt;em&gt;&quot;Minimum supported client: Windows 10, version 2004&quot;&lt;/em&gt; [@ms-sdev-struct]. That is May 2020, three years after SDEV was introduced in ACPI 6.2 (May 2017). ACPI tables routinely outlive the OS consumers that read them by years; the table set is a bus, and consumers attach to it on their own schedule.&lt;/p&gt;
&lt;h3&gt;How SDEV becomes trustlet ownership&lt;/h3&gt;
&lt;p&gt;The Secure Kernel does not consume SDEV directly to start a &lt;a href=&quot;https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;trustlet&lt;/a&gt;. SDEV is the &lt;em&gt;hint&lt;/em&gt;; the binding to a specific trustlet is encoded in Windows policy and OEM driver INFs. The companion article on VBS trustlets walks the trustlet IDs in detail [@vbs-trustlets-sibling]; the routing is implicit.&lt;/p&gt;

flowchart TD
    A[Firmware lists device in SDEV] --&amp;gt; B{Allow-Handoff bit set?}
    B --&amp;gt;|Clear -- always secure| C[Trustlet-aware driver present?]
    B --&amp;gt;|Set -- handoff allowed| D[Trustlet-aware driver present?]
    C --&amp;gt;|Yes| E[Device owned by VTL1 trustlet -- BioIso / LsaIso / vmsp]
    C --&amp;gt;|No| F[Device unusable -- ESS feature silently disabled]
    D --&amp;gt;|Yes| G[Trustlet may release device to VTL0 on request]
    D --&amp;gt;|No| H[Device falls back to VTL0 ownership]
    A2[Device not in SDEV] --&amp;gt; I[No trustlet ownership; ESS, vTPM disabled]

The full mapping is documented in the VBS Trustlets companion article [@vbs-trustlets-sibling]. The short version: the Windows Hello IR camera for Enhanced Sign-in Security is routed to BioIso (the Secure Biometrics trustlet) via its SDEV listing; smart-card readers and PINs that flow through Credential Guard are routed to LsaIso; the discrete TPM device path, when SDEV-listed, is routed to the vTPM trustlet (vmsp). Fingerprint sensors in ESS use a separate Match-on-Sensor + USB-Secure-Connection path that is not driven by SDEV. The structural gap is that SDEV does not name *which* trustlet a device should be routed to. The binding is implicit in OEM driver INFs and Windows policy, and a multi-trustlet platform cannot rely on the table to express routing.
&lt;h3&gt;Where SDEV becomes a Secured-core PC certification gate&lt;/h3&gt;
&lt;p&gt;The current OEM Standards for highly secure Windows 11 devices page makes SDEV authoring an explicit certification gate when the platform claims Windows Hello with Enhanced Sign-in Security: &lt;em&gt;&quot;A device with Windows Hello with ESS is enabled if it has the ESS hardware built-in components for face or fingerprint authentication, and the necessary support in BIOS&quot;&lt;/em&gt; [@oem-highly-secure-11]. For the face-authentication path, the SDEV listing of the Windows Hello IR camera is, in practice, what &lt;em&gt;&quot;the necessary support in BIOS&quot;&lt;/em&gt; cashes out to. (Fingerprint authentication in ESS uses Match-on-Sensor with a USB Secure Connection -- a different protection mechanism that does not flow through SDEV.) Without the IR-camera SDEV entry, the hardware exists, the driver loads, the user&apos;s face is captured -- and the secure pipeline never engages, because the Secure Kernel was never told the camera was its responsibility.&lt;/p&gt;
&lt;p&gt;Three observable failure families recur. &lt;em&gt;Device not listed&lt;/em&gt; surfaces as Enhanced Sign-in Security silently disabling; the user sees &lt;em&gt;&quot;Windows Hello requires additional setup&quot;&lt;/em&gt; and never reaches the secure path. &lt;em&gt;Listed but driver-incompatible&lt;/em&gt; triggers the Allow-Handoff fallback and the device is owned by the normal kernel, exactly the outcome SDEV was meant to prevent. &lt;em&gt;Adversarially listed&lt;/em&gt; is the worst case: an attacker with a DXE foothold (the firmware-stage class that LogoFAIL [@nvd-cve-2023-40238] and BIOSDisconnect typify) writes a malicious SDEV entry into ACPI memory and routes a device the attacker controls into the Secure Kernel partition. That last case is what the ACPI 6.5 spec means when it says &lt;em&gt;&quot;the table itself does not provide any security guarantees.&quot;&lt;/em&gt; The Secure Kernel enforces the partition; the table only suggests where the partition should fall.&lt;/p&gt;
&lt;p&gt;The article&apos;s third recurring failure family is now visible in three of the five tables: &lt;em&gt;missing&lt;/em&gt;, &lt;em&gt;malformed&lt;/em&gt;, &lt;em&gt;forged&lt;/em&gt;. SDEV decides which devices the firmware says are secure. The next table -- WPBT -- decides which &lt;em&gt;binaries&lt;/em&gt; the firmware says Windows should run. That is the dial that, when broken, turned everything-protections-on Secured-Core PCs into rootkit hosts.&lt;/p&gt;
&lt;h2&gt;6. WPBT: The OEM Rootkit That Microsoft Designed In On Purpose&lt;/h2&gt;
&lt;p&gt;In 2012 Microsoft shipped a feature that lets the firmware drop a binary into &lt;code&gt;c:\windows\system32&lt;/code&gt; and run it at SYSTEM on every boot [@eclypsium-wpbt]. The reason was customer experience. The result was a designed-in rootkit channel.&lt;/p&gt;

A fixed-layout ACPI table whose body is a physical pointer to a binary stored in firmware memory. At every boot, the Windows session manager reads the pointer, copies the binary into `c:\windows\system32`, validates its Authenticode signature, and executes it with SYSTEM privileges before the user reaches the lock screen. ACPICA&apos;s reference header pins the conformance to *&quot;Windows Platform Binary Table (WPBT) 29 November 2011&quot;* [@acpica-actbl3-wpbt].
&lt;p&gt;The Microsoft specification, preserved verbatim by Eclypsium, describes the mechanism without flinching: &lt;em&gt;&quot;The WPBT is a fixed Advanced Configuration and Power Interface (ACPI) table that enables boot firmware to provide Windows with a platform binary that the operating system can execute. The binary handoff medium is physical memory, allowing the boot firmware to provide the platform binary without modifying the Windows image on disk&quot;&lt;/em&gt; [@eclypsium-wpbt]. The ACPICA struct is small enough to read in one breath:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct acpi_table_wpbt {
    ACPI_TABLE_HEADER Header;
    UINT32 HandoffSize;
    UINT64 HandoffAddress;     /* physical pointer to the binary */
    UINT8  Layout;
    UINT8  Type;
    UINT16 ArgumentsLength;
} ACPI_TABLE_WPBT;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The single load-bearing field is &lt;code&gt;HandoffAddress&lt;/code&gt;: a 64-bit physical pointer to the binary. The signing requirement, again preserved verbatim by Eclypsium [@eclypsium-wpbt]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;All binaries published to Windows using the WPBT mechanism outlined in this paper must be embedded signed and timestamped. These images should be linked with the /INTEGRITYCHECK option and signed using the SignTool command-line tool with the /nph switch to suppress page hashes.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why did Microsoft ship this? OEM customer-experience continuity across clean reinstalls. A customer who runs Windows Setup from USB and wipes their machine reasonably expects everything they paid for to come back: vendor utilities, enterprise enrolment shims, anti-theft agents. WPBT was Microsoft&apos;s answer to &lt;em&gt;&quot;how does the OEM persist its software across an OS-level reinstall?&quot;&lt;/em&gt; The answer Microsoft chose was: by handing the firmware a sanctioned channel to inject a SYSTEM-level binary into every boot. Eclypsium&apos;s own coverage records that &lt;em&gt;&quot;acclaimed researcher and co-author of Windows Internals, Alex Ionescu, has been calling out the dangers of WPBT as a rootkit as early as 2012 and continues to do so today&quot;&lt;/em&gt; [@eclypsium-wpbt].&lt;/p&gt;

sequenceDiagram
    participant FW as OEM Firmware
    participant ACPI as ACPI table set
    participant SMSS as Session Manager (smss.exe)
    participant CI as Code Integrity
    participant EXE as wpbbin.exe (SYSTEM)
    FW-&amp;gt;&amp;gt;ACPI: Build WPBT, set HandoffAddress to in-memory binary
    ACPI-&amp;gt;&amp;gt;SMSS: Session manager reads WPBT during early boot
    SMSS-&amp;gt;&amp;gt;SMSS: Copy binary from physical memory into system32
    SMSS-&amp;gt;&amp;gt;CI: Validate Authenticode signature
    CI--&amp;gt;&amp;gt;SMSS: Accept (until 2021: even revoked certs accepted)
    SMSS-&amp;gt;&amp;gt;EXE: Launch as SYSTEM, before lock screen
&lt;h3&gt;A history of WPBT abuse, in three acts&lt;/h3&gt;
&lt;p&gt;The WPBT abuse history predates the table itself. The mechanism existed informally as a BIOS Option ROM trick before it was standardised; once standardised, the abuse cases scaled [@securelist-computrace].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;What was broken&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;2008-2014&lt;/td&gt;
&lt;td&gt;Computrace / Absolute LoJack&lt;/td&gt;
&lt;td&gt;BIOS Option ROM dropper (pre-WPBT)&lt;/td&gt;
&lt;td&gt;Vendor-installed anti-theft agent persisted across reinstalls; C&amp;amp;C protocol enabled hijacking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;Lenovo Service Engine (LSE)&lt;/td&gt;
&lt;td&gt;Formal WPBT (Windows 8 era)&lt;/td&gt;
&lt;td&gt;Buffer overflow allowed remote code execution via vendor-installed binary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;LoJax (APT28 / Sednit)&lt;/td&gt;
&lt;td&gt;UEFI rootkit reusing Computrace&apos;s persistence design&lt;/td&gt;
&lt;td&gt;First in-the-wild UEFI rootkit; survived OS reinstall and disk replacement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Eclypsium &quot;Everyone Gets a Rootkit&quot;&lt;/td&gt;
&lt;td&gt;Formal WPBT signature gate&lt;/td&gt;
&lt;td&gt;Signature check accepted revoked certificates; Secured-Core PCs vulnerable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Computrace, analysed by Vitaly Kamluk and Sergey Belov in February 2014, was the legitimate ancestor. Their post documented an Absolute Software anti-theft agent that survived clean Windows reinstalls because the firmware re-injected &lt;code&gt;rpcnetp.exe&lt;/code&gt; at every boot via a WPBT-class mechanism that predated WPBT itself: &lt;em&gt;&quot;the owner of the system claimed he had never installed Absolute Computrace and didn&apos;t even know the software was present on his computer&quot;&lt;/em&gt; [@securelist-computrace]. The reverse-engineering revealed a Russian-doll structure -- &lt;em&gt;&quot;&lt;code&gt;rpcnetp.exe&lt;/code&gt; inside &lt;code&gt;autochk.exe&lt;/code&gt; inside EFI Application inside another EFI-Application inside ROM Module&quot;&lt;/em&gt; [@securelist-computrace] -- and a C&amp;amp;C protocol weak enough that the researchers built proof-of-concept hijacking. WPBT-class persistence existed as attack surface before WPBT was a table.&lt;/p&gt;
&lt;p&gt;LSE was the first formal-WPBT abuse. CISA&apos;s August 12, 2015 alert framed it tersely: &lt;em&gt;&quot;Certain Lenovo personal computers contain a vulnerability in LSE (a Lenovo BIOS feature). Exploitation of this vulnerability may allow a remote attacker to take control of an affected system&quot;&lt;/em&gt; [@cisa-lse]. The NVD entry pinned the weakness class: &lt;em&gt;&quot;A buffer overflow vulnerability was reported, (fixed and publicly disclosed in 2015) in the Lenovo Service Engine (LSE), affecting various versions of BIOS for Lenovo Notebooks, that could allow a remote user to execute arbitrary code on the system&quot;&lt;/em&gt; [@nvd-cve-2015-5684]. LSE injected &lt;code&gt;wpbbin.exe&lt;/code&gt; into &lt;code&gt;system32&lt;/code&gt;, downloaded a separate utility called &lt;em&gt;OneKey Optimizer&lt;/em&gt;, and overwrote &lt;code&gt;autochk.exe&lt;/code&gt; to maintain persistence. The only reliable fix was an OEM BIOS update.&lt;/p&gt;
&lt;p&gt;LoJax came in September 2018. ESET&apos;s white paper documented the first in-the-wild UEFI rootkit, attributed to the Sednit / APT28 group: &lt;em&gt;&quot;This persistence method is particularly invasive as it will not only survive an OS reinstall, but also a hard disk replacement&quot;&lt;/em&gt; [@eset-lojax-html]. The persistence design was directly inspired by Computrace&apos;s LoJack; ESET noted that &lt;em&gt;&quot;In May 2018, an Arbor Networks blog post described several trojanized samples of Absolute Software&apos;s LoJack small agent, rpcnetp.exe&quot;&lt;/em&gt; [@eset-lojax-html]. A 2008-vintage anti-theft mechanism became the template for state-actor espionage.&lt;/p&gt;
&lt;h3&gt;The 2021 Eclypsium disclosure: &quot;Everyone Gets a Rootkit&quot;&lt;/h3&gt;
&lt;p&gt;In September 2021, the Eclypsium research team published the structural finding that reframed WPBT from &lt;em&gt;&quot;controversial OEM convenience&quot;&lt;/em&gt; to &lt;em&gt;&quot;structurally broken signature gate&quot;&lt;/em&gt;. The post was institutionally authored by &lt;em&gt;&quot;the Eclypsium research team&quot;&lt;/em&gt; with no by-line in the rendered article body; this article preserves that institutional attribution. The finding [@eclypsium-wpbt]:&lt;/p&gt;

While Microsoft requires a WPBT binary to be signed, it will accept an expired or revoked certificate. This means an attacker can sign a malicious binary with any readily available expired certificate. This issue affects all Windows-based devices going back to Windows 8 when WPBT was first introduced. We have successfully demonstrated the attack on modern, Secured-Core PCs that are running the latest boot protections. -- Eclypsium, *Everyone Gets a Rootkit* (September 2021) [@eclypsium-wpbt]
&lt;p&gt;The proof-of-concept was elegant in the worst way. The researchers signed a malicious binary with a Hacking Team code-signing certificate that had been revoked in 2015 (a side effect of the 2015 Hacking Team breach). They placed it in firmware memory. They wrote a WPBT entry pointing at it. On a Secured-Core PC with Credential Guard, HVCI, BitLocker, and Kernel DMA Protection all enabled, Windows ran the binary at SYSTEM before the user reached the lock screen. The signature gate was the only thing standing between the firmware and arbitrary kernel-grade code. The signature gate accepted revoked certificates.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response was not to fix the validator [@eclypsium-wpbt]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Microsoft recommends customers use Windows Defender Application Control (WDAC) to limit what is allowed to run on their devices. WDAC policy is also enforced for binaries included in the WPBT and should mitigate this issue. We recommend customers implement a WDAC policy that is as restrictive as practical for their environment.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is an explicit acknowledgement that the original signing-only model was structurally inadequate; the fix was outsourced to a customer-authored allow-list. WDAC is the &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;App Identity&lt;/a&gt; sibling article&apos;s territory [@app-identity-sibling]; for the present article, the relevant fact is that the only mitigation Microsoft recommended did not change Microsoft&apos;s code. It changed the customer&apos;s policy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; WPBT is a designed-in OEM persistence channel that, until 2021, allowed any binary signed with any code-signing certificate -- including certificates revoked years earlier -- to execute at SYSTEM on every boot of every Windows-since-8 machine, including the most heavily protected Secured-Core PCs. The fix was not a patch to the validator. The fix was to ask customers to author Windows Defender Application Control policies that constrain what WPBT may run.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The mitigation paths a defender can take today, in order of how supported they are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;WDAC policy over WPBT&lt;/td&gt;
&lt;td&gt;Microsoft-recommended&lt;/td&gt;
&lt;td&gt;Constrains which binaries WPBT may execute, regardless of signing-cert status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BIOS option to disable WPBT&lt;/td&gt;
&lt;td&gt;OEM-dependent&lt;/td&gt;
&lt;td&gt;A few enterprise-class OEMs offer it; most do not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dropWPBT&lt;/code&gt; (community tool)&lt;/td&gt;
&lt;td&gt;Unsupported&lt;/td&gt;
&lt;td&gt;Removes the WPBT entry from in-memory ACPI before Windows reads it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cert-revocation enforcement&lt;/td&gt;
&lt;td&gt;Unimplemented&lt;/td&gt;
&lt;td&gt;Microsoft has not changed the WPBT validator to honour revocation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The community `dropWPBT` project on GitHub, referenced by Eclypsium in their disclosure post [@eclypsium-wpbt], is a UEFI driver that removes the WPBT entry from the in-memory ACPI table set before Windows boot manager reads it. Microsoft does not document a supported way to disable WPBT consumption from inside Windows. The Eclypsium post is explicit: *&quot;In our research, we have not found documentation from Microsoft detailing how to disable WPBT&quot;* [@eclypsium-wpbt].
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft does not document a supported way to disable WPBT consumption from inside Windows. The community &lt;code&gt;dropWPBT&lt;/code&gt; project is unsupported. Any defender who wants to neutralise WPBT must rely on either an OEM BIOS toggle (where offered) or a WDAC policy that constrains the binaries WPBT may execute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We have walked five tables: DMAR, IORT, WSMT, SDEV, WPBT. Three failure families recur in each: omission, mistake, forgery. Time to make the threat model honest.&lt;/p&gt;
&lt;h2&gt;7. Forged, Missing, and Lying Tables: An Honest Threat Model&lt;/h2&gt;
&lt;p&gt;We have seen the tables. We have seen one of them break catastrophically. Now name the failure families honestly, because each has a different attacker, a different fix, and a different observable signal.&lt;/p&gt;

flowchart TD
    A[Failure mode] --&amp;gt; B[OEM omission]
    A --&amp;gt; C[OEM mistake]
    A --&amp;gt; D[Adversarial forgery]
    B --&amp;gt; B1[Cause: table absent or flag clear]
    B1 --&amp;gt; B2[Observable: msinfo32 / Win32_DeviceGuard]
    B2 --&amp;gt; B3[Fix: OEM BIOS update]
    C --&amp;gt; C1[Cause: table present but lying about behaviour]
    C1 --&amp;gt; C2[Observable: none from inside Windows]
    C2 --&amp;gt; C3[Fix: certification, external research, OEM BIOS update]
    D --&amp;gt; D1[Cause: attacker with DXE foothold rewrites table]
    D1 --&amp;gt; D2[Observable: requires measured ACPI to detect]
    D2 --&amp;gt; D3[Fix: WDAC over WPBT, Pluton-rooted attestation -- partial]
&lt;h3&gt;OEM omission: the most common failure&lt;/h3&gt;
&lt;p&gt;The most common case is the simplest. Kernel DMA Protection silently shows &lt;code&gt;Off&lt;/code&gt; because the OEM&apos;s DMAR is missing or because the &lt;code&gt;DMA_CTRL_PLATFORM_OPT_IN_FLAG&lt;/code&gt; is clear in the Flags byte [@oem-kernel-dma]. Windows Hello with Enhanced Sign-in Security silently disables the face-authentication path because the Windows Hello IR camera was never listed in SDEV [@oem-highly-secure-11]. VBS de-features because WSMT is missing or its three Protection Flags are partially clear [@ms-oem-uefi-wsmt]. The defender&apos;s observable surface is &lt;code&gt;msinfo32&lt;/code&gt;, the &lt;code&gt;Win32_DeviceGuard&lt;/code&gt; WMI class, and the System Summary pane; the fix in every case is an OEM BIOS update, on the OEM&apos;s release schedule, with whatever distribution latency that involves.&lt;/p&gt;
&lt;h3&gt;OEM mistake: present but lying&lt;/h3&gt;
&lt;p&gt;The second case is the worst-case from a detection standpoint, because it is unobservable from inside Windows. WSMT may report all three Protection Flags asserted on a platform whose SMI handlers were never actually rewritten to validate nested pointers. SDEV may list a device whose driver was never hardened to enforce its trustlet ownership. DMAR may declare a tight policy for a chipset whose VT-d implementation has a documented errata that defeats it. Microsoft itself states the impossibility result for WSMT in the public Learn prose [@ms-oem-uefi-wsmt]. The only mechanisms that catch this class are (a) certification programs that audit the firmware before it ships (Windows Hardware Lab Kit, Secured-core PC requirements [@oem-highly-secure-11]) and (b) external research, after the fact. The fix is, again, an OEM BIOS update.&lt;/p&gt;
&lt;h3&gt;Adversarial forgery: an attacker with a DXE foothold&lt;/h3&gt;
&lt;p&gt;The third case is the most consequential. An attacker with a foothold in the firmware boot environment -- the DXE class typified by LogoFAIL (CVE-2023-40238, the Insyde BMP decoder memory-corruption Binarly published at Black Hat Europe 2023 [@nvd-cve-2023-40238]) -- writes a new WPBT entry, or a new SDEV entry, or a different DMAR Flags value into ACPI memory before Windows reads it. The Eclypsium 2021 demonstration showed that this works against Secured-Core PCs in 2021 [@eclypsium-wpbt]. The defender&apos;s observable surface is, by construction, none unless the firmware measured the relevant tables into a TPM PCR and the hypervisor consumes that measurement. The fix is partial today: WDAC over WPBT for the binary-execution case, Pluton-rooted attestation for the table-content-drift case, and OEM BIOS hardening for everything else.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; LogoFAIL is the cleanest example of why forgery is the hardest failure family. It is a pre-OS UEFI image-parser remote code execution in DXE, the firmware execution environment that &lt;em&gt;builds&lt;/em&gt; the ACPI tables in the first place [@nvd-cve-2023-40238]. If you can patch DXE, you can patch the tables before Windows reads them. The five tables we have walked sit &lt;em&gt;below&lt;/em&gt; Secure Boot&apos;s verifier; LogoFAIL sits &lt;em&gt;below&lt;/em&gt; the five tables. Cross-link the Secure Boot sibling article for the full chain [@secure-boot-sibling].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Pluton&apos;s honest residual&lt;/h3&gt;
&lt;p&gt;Pluton-rooted attestation closes some, but not all, of the forgery gap. The TCG PC Client Platform Firmware Profile specifies how firmware events are extended into TPM Platform Configuration Registers; Microsoft requires platform firmware to extend a specific event into PCR[7] when DMA protection is disabled or downgraded: &lt;em&gt;&quot;On every boot where the IOMMU (VT-D or AMD-Vi) or Kernel DMA Protection are disabled, will be disabled, or configured to a lower security state, the platform MUST extend an EV_EFI_ACTION event into PCR[7] before enabling DMA. The event string SHALL be &apos;DMA Protection Disabled&apos;&quot;&lt;/em&gt; [@oem-kernel-dma]. That is the only narrowly-specified flow in this article that lets a remote verifier learn -- via TPM quote -- that the table set was downgraded between firmware build and OS boot.&lt;/p&gt;
&lt;p&gt;It is also a single example. The general case -- &lt;em&gt;&quot;every security-bearing ACPI table was measured into a known PCR at firmware load, and the hypervisor refuses to launch trustlets if the measurement does not match a known-good baseline&quot;&lt;/em&gt; -- is not a deployed mechanism on Windows today. Pluton-as-TPM is a precondition; the measurement schema is the missing piece [@ms-pluton; @pluton-sibling].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Pluton-rooted measured boot closes the &lt;em&gt;freshness gap&lt;/em&gt; (the table did not change between firmware build and OS parse). It does not close the &lt;em&gt;contents-correctness gap&lt;/em&gt; (the table contents were correct at firmware build in the first place). A WSMT with all three flags asserted by an OEM that did not actually harden their SMM handlers will measure the same way every boot, and the Pluton-rooted attestation will faithfully report it as valid. The contents-correctness problem requires either out-of-band certification (Secured-core PC) or a fundamentally different architecture (a vendor-controlled hardware-software stack, as on Apple&apos;s Secure Enclave-equipped silicon) -- not measured boot.&lt;/p&gt;
&lt;/blockquote&gt;

The window in which an attacker may modify an ACPI table after the firmware authored it but before the operating system reads it. Pluton-rooted measured boot detects modifications in this window because the PCR measurement at boot will not match the known-good baseline.

The class of failures in which the table contents were *incorrect at firmware build* -- the OEM declared properties that do not hold, or the firmware authored a wide RMRR that overlaps sensitive memory, or the WSMT flags overstate the SMM hardening that actually shipped. Measured boot cannot detect this class because the measurement matches the baseline; the baseline itself is wrong.
&lt;p&gt;The freshness gap and the contents-correctness gap are independent failure modes, and they need independent mechanisms. Pluton solves the first. Nothing in the deployed Windows-on-OEM-firmware model solves the second; out-of-band certification (Secured-core PC) is the closest approximation, and it works only for the sample of devices Microsoft tests pre-ship.&lt;/p&gt;
&lt;p&gt;We can name the failures. So who is responsible for fixing each one? That is the lifecycle question.&lt;/p&gt;
&lt;h2&gt;8. The Lifecycle Question: Who Populates, Who Validates, Who Owns the Bug&lt;/h2&gt;
&lt;p&gt;The OS reads the tables. It does not write them. So who does, and who checks the writer&apos;s work?&lt;/p&gt;
&lt;h3&gt;Population&lt;/h3&gt;
&lt;p&gt;SDEV, WSMT, and WPBT entries are constructed by the OEM&apos;s UEFI BIOS team, sometimes via platform-controller-side helpers (Intel ME, AMD PSP) when secure-resource enumeration crosses platform-controller boundaries. DMAR is mostly built by the reference Independent BIOS Vendor code that ships with Intel and AMD reference designs (American Megatrends, Insyde, Phoenix -- the three IBVs listed in the public UEFI Forum membership directory [@uefi-forum-members]) and customised by the OEM. IORT is filled in by the System-on-Chip vendor&apos;s reference firmware on Arm (Qualcomm, Ampere, NVIDIA on Grace-class platforms). The table set is &lt;em&gt;assembled at firmware build time&lt;/em&gt;, not at boot. Once Windows is running, the tables are read-only; the only way to change them is to re-flash the firmware.&lt;/p&gt;
&lt;h3&gt;Validation, pre-ship&lt;/h3&gt;
&lt;p&gt;Pre-ship validation runs through the Windows Hardware Lab Kit and the Microsoft Hardware Compatibility Program. Secured-Core PC certification raises the bar de facto. Per the OEM Standards for highly secure Windows 11 devices page, Secured-Core requires Secure Boot enabled with the third-party UEFI CA not trusted by default; TPM 2.0 meeting the latest TCG requirements; &lt;em&gt;&quot;the device supports Memory Access Protection (Kernel DMA Protection)&quot;&lt;/em&gt; (i.e., DMAR / IVRS / IORT correctly authored); &lt;em&gt;&quot;System Guard Secure Launch (D-RTM) with System Management Mode (SMM) isolation&quot;&lt;/em&gt; OR &lt;em&gt;&quot;S-RTM and Standalone MM with MM supervisor (the approach implemented on FASR devices)&quot;&lt;/em&gt;; HVCI enabled; Windows Hello with Enhanced Sign-in Security (i.e., SDEV authored); and BitLocker [@oem-highly-secure-11]. WSMT-flags-asserted is checked transitively via the SMM-isolation requirement.&lt;/p&gt;

flowchart LR
    subgraph OEM
        P1[Build DMAR / IORT / WSMT / SDEV / WPBT at firmware build time]
        P2[Re-author on each BIOS update]
    end
    subgraph Microsoft
        V1[WHQL / HLK pre-ship validation]
        V2[Secured-Core PC certification]
        V3[Post-ship: ad-hoc research only]
    end
    subgraph Customer
        C1[Run msinfo32, Win32_DeviceGuard, Get-MpComputerStatus]
        C2[Author WDAC policy that constrains WPBT-injected binaries]
        C3[Apply OEM BIOS updates -- only path for table-content fixes]
    end
    P1 --&amp;gt; V1
    V1 --&amp;gt; V2
    V2 --&amp;gt; C1
    P2 --&amp;gt; C3
    V3 -.-&amp;gt; C2
&lt;h3&gt;Validation, post-ship&lt;/h3&gt;
&lt;p&gt;There is almost none, except via the WHQL driver flow and ad-hoc Microsoft research after a public disclosure. The 2021 Eclypsium WPBT-cert-validation finding triggered a Microsoft re-examination, and the response was a customer-side WDAC mitigation rather than an OS-side validator change [@eclypsium-wpbt]. The servicing-velocity problem is structural: ACPI table content cannot be patched by Windows Update; it requires a UEFI BIOS update from the OEM. The 2015 Lenovo Service Engine incident required Lenovo BIOS updates [@cisa-lse; @nvd-cve-2015-5684]; the Eclypsium finding could not wait for a comparable industry-wide BIOS-update wave, so Microsoft chose the WDAC path.&lt;/p&gt;
&lt;h3&gt;Servicing&lt;/h3&gt;
&lt;p&gt;OEM BIOS update is the only path for table-content fixes. OS-side WDAC is the only path for binary-execution constraints over WPBT. Pluton-rooted attestation is the only path for drift detection between firmware build and OS boot. The three are layered, not redundant: a defender who cares about the WPBT class needs all three.&lt;/p&gt;
&lt;h3&gt;The four open problems&lt;/h3&gt;
&lt;p&gt;The four open problems are not implementation details. They are structural negative spaces where no shipping mechanism today fills the gap.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;First, there is no industry-standard attestable claim that an OEM has actually implemented the SMM mitigations they declared in WSMT.&lt;/em&gt; The obvious direction is a Pluton-attested SMM-mitigation manifest: a hardware-rooted statement that the firmware that built the WSMT also includes the SMI-handler implementations that justify the flags. Not standardised today. The current WSMT flags are a free-text declaration the OEM may make for any reason; the only check is presence.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Second, SDEV does not name which trustlet a device should be routed to.&lt;/em&gt; The binding between an SDEV-listed device and the consuming trustlet (BioIso, LsaIso, vmsp) is encoded implicitly in Windows policy and OEM driver INFs. There is no extensibility story for future trustlets, and no way for a third-party trustlet to declare which SDEV entries it expects to consume. If Microsoft ships a new trustlet for Wi-Fi credentials in five years, SDEV cannot describe the binding without a spec revision.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Third, WPBT signing trust roots are not declared in the table.&lt;/em&gt; The implicit assumption was that any Authenticode-trusted certificate would do. The Eclypsium 2021 disclosure broke that assumption [@eclypsium-wpbt]. WDAC is the workaround; a fix would require WPBT to declare a narrower trust root the firmware vouches for, and the OS to enforce only that root. Such a change has not shipped.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Fourth, forged-table detection from the Secure Kernel is partial.&lt;/em&gt; Not all five security tables are measured into well-defined PCRs. The only narrowly-specified flow is the PCR[7] EV_EFI_ACTION &lt;em&gt;&quot;DMA Protection Disabled&quot;&lt;/em&gt; event Microsoft requires when DMA protection is downgraded [@oem-kernel-dma]. A unified &lt;em&gt;&quot;measured ACPI&quot;&lt;/em&gt; PCR -- e.g., PCR[5] extended with the hash of every security-bearing table at firmware load, paired with hypervisor-side enforcement that refuses to launch trustlets if the measurement does not match a known-good baseline -- is the obvious direction. It is not deployed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The four open problems are: (1) no attestable claim that WSMT-declared SMM mitigations are actually implemented; (2) SDEV does not name the consuming trustlet; (3) WPBT signing trust roots are not declared in the table; (4) forged-table detection from VTL1 is partial. None of these is solved in shipping Windows in 2026. This is the live frontier of the firmware-OS contract.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Knowing the failure families and the lifecycle, what should you actually do on Monday morning? That is the practical guide.&lt;/p&gt;
&lt;h2&gt;9. Practical Guide: Inventory, Procurement, Defence&lt;/h2&gt;
&lt;p&gt;You are now equipped to read these tables on your own laptop and to argue procurement criteria with a vendor. Here is the operational toolkit.&lt;/p&gt;
&lt;h3&gt;Inventory commands&lt;/h3&gt;
&lt;p&gt;The fastest way to find out what is actually enabled on a Windows machine is a short PowerShell session followed by an optional Linux-side dump for the table contents themselves.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;VBS / HVCI / Credential Guard state; the implicit witness for whether WSMT influence allowed VBS to start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;msinfo32&lt;/code&gt; (System Summary pane)&lt;/td&gt;
&lt;td&gt;Kernel DMA Protection (DMAR / IVRS / IORT influence), Secure Boot State, Memory Integrity, Virtualization-based security state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;`Get-PnpDevice -PresentOnly&lt;/td&gt;
&lt;td&gt;Where-Object { $_.Class -eq &quot;Biometric&quot; }`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Get-MpComputerStatus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Defender state including AMSI providers, useful for cross-checking the WDAC-over-WPBT mitigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux: &lt;code&gt;sudo acpidump -b -o tables.acpi &amp;amp;&amp;amp; acpixtract -a tables.acpi &amp;amp;&amp;amp; iasl -d *.dat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dumps and disassembles the ACPI table set; you can read SDEV / WSMT / WPBT / DMAR / IORT in human form&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A worked example brings the flags to life. Suppose you dump the tables on a Surface-class laptop. SDEV will list &lt;code&gt;\_SB.PCI0.GFX0.IRCM&lt;/code&gt; (the integrated infrared camera used by Windows Hello) with the Allow-Handoff bit clear -- the camera is owned by the Secure Kernel for the lifetime of the boot. WSMT will show &lt;code&gt;ProtectionFlags = 7&lt;/code&gt; (all three bits set: &lt;code&gt;FIXED_COMM_BUFFERS | COMM_BUFFER_NESTED_PTR_PROTECTION | SYSTEM_RESOURCE_PROTECTION&lt;/code&gt;). DMAR will show DRHD entries for each VT-d remapping unit and the Flags byte will have bit 2 (&lt;code&gt;DMA_CTRL_PLATFORM_OPT_IN_FLAG&lt;/code&gt;) set. WPBT may or may not be present; if present, you can extract &lt;code&gt;HandoffSize&lt;/code&gt; and the binary itself, and pass the binary to &lt;code&gt;signtool verify /pa /v&lt;/code&gt; to read its Authenticode chain.&lt;/p&gt;

```
PS&amp;gt; $g = Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard
PS&amp;gt; &quot;VBS status: $($g.VirtualizationBasedSecurityStatus); services running: $($g.SecurityServicesRunning -join &apos;,&apos;)&quot;
```&lt;p&gt;&lt;code&gt;VirtualizationBasedSecurityStatus&lt;/code&gt;: 0 = off, 1 = enabled but not running, 2 = running. &lt;code&gt;SecurityServicesRunning&lt;/code&gt; is an array: 1 = Credential Guard, 2 = HVCI (Memory Integrity), 3 = System Guard Secure Launch, 4 = SMM Firmware Measurement. An array of [2, 3] means both HVCI and System Guard Secure Launch are active. A &lt;em&gt;1 / empty-array&lt;/em&gt; result is the classic &lt;em&gt;&quot;WSMT or another VBS prerequisite is missing&quot;&lt;/em&gt; signature.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Procurement criteria for a security-conscious buyer&lt;/h3&gt;
&lt;p&gt;The procurement conversation is the most consequential one a defender can have. The five table set is not patchable from Windows Update; if you bought wrong, you are stuck with it for the device&apos;s lifetime. The criteria worth pinning down before you sign a purchase order:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;What it guarantees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Secured-Core PC certification&lt;/td&gt;
&lt;td&gt;DMAR / IVRS / IORT present and correctly authored, Memory Access Protection enrollable, WSMT flags asserted, SDEV populated for biometrics, HVCI on, BitLocker on [@oem-highly-secure-11]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BIOS option to disable WPBT&lt;/td&gt;
&lt;td&gt;Customer-side opt-out from the WPBT class without relying on WDAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IORT presence on Arm laptops&lt;/td&gt;
&lt;td&gt;Confirms SMMU-on-by-default in firmware (Snapdragon X / Surface Pro X-class)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vendor BIOS-update SLA covering ACPI security tables&lt;/td&gt;
&lt;td&gt;Predictable patch cadence for the tables that cannot be Windows-Updated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pluton-as-TPM option&lt;/td&gt;
&lt;td&gt;Closes the LPC-bus eavesdropping gap and supports PCR-based table measurement [@ms-pluton]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;Defender-side Monday-morning actions&lt;/h3&gt;
&lt;p&gt;Three actions are worth doing on the next available maintenance window.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Deploy a WDAC policy that constrains WPBT-injected binaries.&lt;/em&gt; This is Microsoft&apos;s recommended Eclypsium mitigation [@eclypsium-wpbt]. The App Identity sibling article walks WDAC authoring in detail [@app-identity-sibling]. Even a permissive policy that requires a specific signing root for WPBT binaries (e.g., your OEM&apos;s production cert, no others) eliminates the revoked-cert-attack class.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Verify that Memory Integrity, VBS, and Credential Guard are actually running, not just supported.&lt;/em&gt; Run &lt;code&gt;Win32_DeviceGuard.SecurityServicesRunning&lt;/code&gt; across your fleet and alert on machines where the array is empty but &lt;code&gt;VirtualizationBasedSecurityStatus = 1&lt;/code&gt;. That signature is the classic &lt;em&gt;&quot;the prerequisites are not met&quot;&lt;/em&gt; outcome -- often WSMT.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Snapshot the ACPI table set on managed endpoints; alert on deltas across BIOS updates.&lt;/em&gt; A WPBT delta that does not correspond to a documented BIOS-update changelog entry is a SOC alert. So is the appearance or removal of an SDEV entry between two consecutive boots. Most enterprise firmware tooling can do this; if yours cannot, the Linux-side &lt;code&gt;acpidump | acpixtract | iasl -d&lt;/code&gt; pipeline is a workable fallback.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For high-value endpoints, treat &lt;code&gt;Kernel DMA Protection: Off&lt;/code&gt; in &lt;code&gt;msinfo32&lt;/code&gt; as a SOC alert worth chasing, not a tolerable default. The remediation is usually a UEFI menu (turn on VT-d) or a BIOS update (fix DMAR authoring), not a Windows operation. The five minutes spent enabling it are worth more than the next quarter of EDR alerts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Two final operational anchors round out the article: a frequently-asked-questions block you can hand to a colleague, and a closing study guide for revision.&lt;/p&gt;
&lt;h2&gt;10. FAQ and Closing&lt;/h2&gt;
&lt;h3&gt;A few questions a colleague will ask&lt;/h3&gt;

Mostly no on enterprise SKUs. You may lose an OEM tracking agent, a warranty-recovery utility, or a vendor-supplied dock-firmware updater. Microsoft does not document a supported way to disable WPBT consumption from inside Windows [@eclypsium-wpbt], so the BIOS toggle (where the OEM offers it) is the cleanest path. On a managed enterprise fleet where the recovery flow is owned by IT and the OEM utility is not load-bearing, the cost is usually zero and the security benefit is the entire WPBT class.

Yes. That is exactly the point of the table. A device listed in SDEV with the Allow-Handoff bit clear is owned by the Secure Kernel for the lifetime of the boot; non-secure-OS code, including the Windows kernel, cannot reach it [@acpi-65-sdev]. The companion article on VBS trustlets walks the partitioning mechanics for the BioIso, LsaIso, and vmsp trustlets [@vbs-trustlets-sibling]. Caveat: if SDEV does not list the device, the Secure Kernel never takes ownership, and the device is owned by the normal kernel by default.

VBS will likely de-feature, and you may not be able to enable Credential Guard or HVCI. Severity depends on what you are using the device for. Microsoft Learn names WSMT compliance with the corresponding Protection Flags asserted as a hard prerequisite for VBS launch [@oem-vbs]. On a developer workstation that handles no production credentials, the practical impact may be modest. On a laptop a domain administrator carries to a coffee shop, the practical impact is a lot of post-exploitation primitives that were supposed to be blocked.

Not on its own. Windows runs the binary. The mitigations are a Windows Defender Application Control policy that constrains what WPBT may execute [@eclypsium-wpbt] or a BIOS option to disable WPBT consumption (where the OEM offers it). Until the WPBT signature validator changes -- which Microsoft has not committed to -- there is no Windows-side mechanism that refuses an attacker-signed binary if the certificate is technically Authenticode-valid (even if revoked).

ACPI&apos;s design point in 1996 was that the OS abstracts away platform variance via OEM-declared tables. The same property that lets a single Windows binary run on a thousand SKUs is the property that puts the OEM on the trust path. The trade-off has been visible since 1996 [@wikipedia-acpi]. The alternative architecture -- a vendor-controlled hardware-and-software stack like Apple&apos;s Mac silicon, where the same vendor controls both ends -- closes the contents-correctness gap by collapsing the OEM and the OS into a single entity. It also collapses the customer-choice space.

All three describe an IOMMU. DMAR is the table for Intel VT-d; IVRS is the table for AMD-Vi; IORT is the table for the Arm SMMU. They are mutually exclusive on a given platform; a laptop ships with exactly one of them depending on the silicon vendor. All three are first-class for Kernel DMA Protection, and the OEM opt-in flag lives in a different field of each [@oem-kernel-dma].

Partial. The TCG Platform Configuration Register framework supports the idea, and Microsoft requires PCR[7] EV_EFI_ACTION events when DMA protection is downgraded [@oem-kernel-dma], but a unified measured-ACPI PCR -- one that extends every security-bearing table at firmware load and lets the hypervisor refuse to launch trustlets when the measurement does not match a known-good baseline -- is not standardised today. This is the live frontier; the Pluton sibling article tracks the silicon-attestation context [@pluton-sibling].
&lt;h3&gt;Closing&lt;/h3&gt;
&lt;p&gt;This article is the substrate for the rest of the Windows platform-security series. The hypervisor-as-isolation-primitive [@hyperv-sibling] runs only when WSMT lets it. The trustlets that run inside the Secure Kernel [@vbs-trustlets-sibling] reach SDEV-listed devices and only those. Pluton-as-TPM [@pluton-sibling] and the discrete TPM [@tpm-sibling] anchor the measured-boot chain that, in principle, could detect a forged ACPI table -- and in practice, today, detects exactly one downgraded-DMA-protection event in PCR[7]. BitLocker [@bitlocker-sibling] seals against PCR values that are themselves measurements of the firmware that built the table set. Secure Boot [@secure-boot-sibling] verifies the bootloader that reads the table set; LogoFAIL showed that the firmware &lt;em&gt;underneath&lt;/em&gt; Secure Boot can patch the tables before Secure Boot&apos;s verifier fires. Application identity and code integrity policy [@app-identity-sibling] is the only customer-side lever for the WPBT class. USB device-arrival policy [@plug-and-trust-sibling] is the only customer-side lever for the runtime portion of the DMA class.&lt;/p&gt;
&lt;p&gt;Every guarantee those articles describe rests on five tables the firmware writes and the OS trusts. You now know the names of the tables, the names of the failure families, and the inventory commands to read them on your own machine. The next time you see &lt;code&gt;Kernel DMA Protection: Off&lt;/code&gt; in &lt;code&gt;msinfo32&lt;/code&gt;, you will know what is missing, who can fix it, and why it matters more than the EDR vendor&apos;s marketing slide implied. The next time someone tells you their Secured-Core PC is rootkit-proof, you will know which 52-byte table to ask about.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;2026-05-11-the-acpi-tables-that-quietly-secure-your-windows-machine&quot; keyTerms={[
  { term: &quot;ACPI&quot;, definition: &quot;Advanced Configuration and Power Interface; the firmware-written, OS-read table format that describes a platform&apos;s non-discoverable devices and capabilities&quot; },
  { term: &quot;DMAR&quot;, definition: &quot;DMA Remapping Reporting Table; the Intel VT-d ACPI table that describes the IOMMU translation contexts and remapping units&quot; },
  { term: &quot;IORT&quot;, definition: &quot;I/O Remapping Table; the Arm-side ACPI 6.0+ analogue of DMAR, describing SMMU translation contexts and GIC ITS interrupt routing&quot; },
  { term: &quot;IVRS&quot;, definition: &quot;I/O Virtualization Reporting Structure; the AMD-Vi ACPI table for IOMMU description on AMD platforms&quot; },
  { term: &quot;WSMT&quot;, definition: &quot;Windows SMM Security Mitigations Table; a 40-byte ACPI table (36-byte header + 4-byte ProtectionFlags) whose 32-bit ProtectionFlags field declares OEM warranties about SMI-handler behaviour&quot; },
  { term: &quot;SDEV&quot;, definition: &quot;Secure Devices Table; an ACPI 6.2+ table that lists devices the firmware believes should be partitioned into the Secure Kernel&quot; },
  { term: &quot;WPBT&quot;, definition: &quot;Windows Platform Binary Table; an ACPI table whose body is a physical pointer to a binary Windows executes at SYSTEM on every boot&quot; },
  { term: &quot;SMM&quot;, definition: &quot;System Management Mode; an x86 CPU mode entered via SMI that runs in SMRAM with full physical-memory access, opaque to the OS&quot; },
  { term: &quot;Confused deputy&quot;, definition: &quot;An attack class where a less-privileged caller induces a more-privileged subject to perform unintended actions via attacker-controlled inputs the subject does not validate&quot; },
  { term: &quot;RMRR / RMR&quot;, definition: &quot;Reserved Memory Region Reporting (DMAR) / Reserved Memory Region (IORT); identity-mapped memory windows the firmware declares for legitimate firmware-DMA needs&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A user-mode process running in VTL1 (the Secure Kernel&apos;s address space); Windows ships several including BioIso, LsaIso, and vmsp&quot; },
  { term: &quot;Freshness gap&quot;, definition: &quot;The class of failures where an ACPI table changes between firmware build and OS parse; closed by Pluton-rooted measured boot&quot; },
  { term: &quot;Contents-correctness gap&quot;, definition: &quot;The class of failures where an ACPI table&apos;s contents were incorrect at firmware build; not closed by measured boot&quot; }
]} questions={[
  { q: &quot;What is the ProtectionFlags value that declares all three WSMT mitigations asserted, and what does each bit mean?&quot;, a: &quot;0x7. Bit 0 (FIXED_COMM_BUFFERS) warrants that all SMI communication buffers live in fixed firmware-allocated memory; bit 1 (COMM_BUFFER_NESTED_PTR_PROTECTION) warrants that nested pointers inside those buffers are validated against the same allowed regions; bit 2 (SYSTEM_RESOURCE_PROTECTION) warrants that critical platform resources are guarded from unintended SMM modification.&quot; },
  { q: &quot;Why is Microsoft&apos;s WSMT documentation explicit that the table is &apos;attestable but not enforceable&apos; from inside Windows?&quot;, a: &quot;Because SMM runs at a higher privilege than any code Windows can execute, and SMRAM is not addressable to the OS. Windows can read the WSMT Protection Flags but cannot run a test that verifies whether the underlying SMI handlers actually implement the warranted protections; only the OEM&apos;s pre-ship validation can confirm that.&quot; },
  { q: &quot;What was the Eclypsium 2021 finding about WPBT, and what was Microsoft&apos;s recommended mitigation?&quot;, a: &quot;Microsoft&apos;s WPBT signature validator accepted expired and revoked code-signing certificates; the researchers signed a malicious binary with a 2015-revoked Hacking Team certificate and ran it at SYSTEM on a Secured-Core PC. Microsoft&apos;s recommended mitigation was for customers to deploy a Windows Defender Application Control policy that constrains binaries WPBT may execute, rather than fixing the WPBT signature validator itself.&quot; },
  { q: &quot;Why does Kernel DMA Protection silently disable on some VT-d-capable laptops?&quot;, a: &quot;Because the AND-gate has multiple inputs: DMAR must be present, the DMA_CTRL_PLATFORM_OPT_IN_FLAG bit (bit 2 of the DMAR Flags byte) must be set, the IOMMU must be enabled in firmware setup, and the device driver must declare DMA-remapping compatibility (per-device RemappingSupported INF directive on Windows 24H2+). Any one of those failing turns it off, and the firmware-controlled inputs require an OEM BIOS update to fix.&quot; },
  { q: &quot;What is the difference between the freshness gap and the contents-correctness gap, and which one does Pluton-rooted measured boot close?&quot;, a: &quot;The freshness gap is the class of failures where an ACPI table changes between firmware build and OS parse; Pluton-rooted measured boot closes it because PCR measurements at boot will not match the known-good baseline. The contents-correctness gap is the class where the table contents were incorrect at firmware build; measured boot cannot close it because the measurement matches the (incorrect) baseline. Only out-of-band certification (Secured-Core PC) approximates a fix.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>acpi</category><category>firmware</category><category>vbs</category><category>kernel-dma-protection</category><category>wpbt</category><category>sdev</category><category>wsmt</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>The Object Manager Namespace: The Hierarchical Filesystem Underneath Every Windows Security Boundary</title><link>https://paragmali.com/blog/the-object-manager-namespace/</link><guid isPermaLink="true">https://paragmali.com/blog/the-object-manager-namespace/</guid><description>A bottom-up tour of the Windows Object Manager namespace, the 1993 Cutler-era kernel data structure that every Windows security boundary quietly assumes.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**The Windows Object Manager namespace is the kernel-resident, filesystem-shaped tree that every Windows security boundary quietly assumes.** Every named kernel object -- processes, threads, sections, files, registry keys, tokens, mutants, semaphores, ALPC ports, devices, drivers, jobs, silos -- lives somewhere under `\`. Six generations of isolation primitives (Session 0 isolation, AppContainer lowbox, integrity levels, VBS trustlets, Server Silos, and the `ObRegisterCallbacks` EDR sensor surface) are all path rewrites, per-directory ACLs, or kernel callbacks layered on the same 1993 Cutler-era four-piece structure. This article builds the namespace bottom-up -- `OBJECT_HEADER`, `OBJECT_TYPE`, `ParseProcedure`, `OBJECT_DIRECTORY` -- walks the 2026 top-level directory atlas on Windows 11 25H2, surveys the exploit tradition (symbolic-link redirection, namespace squatting, bait-and-switch on `\??` and `\Device`, arbitrary directory creation), and closes on the EDR pivot in `ObRegisterCallbacks`.
&lt;h2&gt;1. The path that isn&apos;t a path&lt;/h2&gt;
&lt;p&gt;Open &lt;code&gt;WinObj.exe&lt;/code&gt; as administrator on any Windows 11 25H2 machine (&lt;a href=&quot;https://en.wikipedia.org/wiki/Windows_11_version_history&quot; rel=&quot;noopener&quot;&gt;Windows 11 version history&lt;/a&gt;). For about ten seconds the screen looks like a filesystem. The root is named &lt;code&gt;\&lt;/code&gt;. Below it sit folders called &lt;code&gt;\Device&lt;/code&gt;, &lt;code&gt;\BaseNamedObjects&lt;/code&gt;, &lt;code&gt;\Sessions&lt;/code&gt;, &lt;code&gt;\RPC Control&lt;/code&gt;, &lt;code&gt;\KnownDlls&lt;/code&gt;, and &lt;code&gt;\ObjectTypes&lt;/code&gt;. Double-click any of them and you see children. Right-click any node and you can read a security descriptor. This is essentially the same UI a 1996 SysAdmin would have recognised; the tool first shipped that year as part of Mark Russinovich and Bryce Cogswell&apos;s Winternals [@en-wikipedia-mark-russinovich], and the current build is a Microsoft-signed Sysinternals binary whose navigation surface has not been redesigned in three decades [@ms-winobj].&lt;/p&gt;
&lt;p&gt;Navigate to &lt;code&gt;\Sessions\1\AppContainerNamedObjects&lt;/code&gt; and the picture starts to fracture. Inside that directory you will find one subdirectory per running AppContainer-sandboxed app, each named after a long Security Identifier of the form &lt;code&gt;S-1-15-2-...&lt;/code&gt;. Pick the one belonging to the Microsoft Edge renderer process you are reading this article in. Every named mutant, event, section, semaphore, and ALPC port the renderer can ever name lives inside that one subdirectory. The renderer cannot escape it. Not because of a permission check that comes second, but because the kernel rewrites every name the renderer asks for, transparently, before path resolution begins. Microsoft&apos;s AppContainer Isolation documentation [@ms-appcontainer-isolation] calls this &quot;sandboxing the application kernel objects.&quot;&lt;/p&gt;
&lt;p&gt;This tree is not a filesystem. There is no disk persistence; nothing under &lt;code&gt;\&lt;/code&gt; survives a reboot. It is not the Windows registry either; the registry is a separate subsystem with its own hive format that hangs off the namespace only through a parse procedure on the &lt;code&gt;Key&lt;/code&gt; object type. What this tree is, instead, is the Object Manager namespace: the in-memory, kernel-resident, hierarchical name service that the Windows kernel uses to locate every nameable kernel object [@ms-managing-kernel-objects]. Its top-level directories are catalogued in the driver kit&apos;s Object Directories reference [@ms-object-directories].&lt;/p&gt;

The Windows Object Manager, internally called `Ob`, is a kernel-mode subsystem of the Windows Executive that manages the lifetime, naming, security, and accounting of every resource the kernel exposes to user mode as a named object. Wikipedia summarises it as a &quot;subsystem implemented as part of the Windows Executive which manages Windows resources... each [resource] reside[s] in a namespace for categorization&quot; [@en-wikipedia-object-manager].
&lt;p&gt;Here is the thesis the rest of this article spends nine thousand words unpacking. Every Windows security boundary you have read about -- Session 0 isolation, Mandatory Integrity Control, AppContainer, the Virtualization-Based Security trustlets, Server Silos and Windows containers, the EDR sensor surface that fires when something opens a handle to &lt;code&gt;lsass.exe&lt;/code&gt; -- is &lt;em&gt;physically realised&lt;/em&gt; in this tree. Each boundary is either a path rewrite at lookup time, a per-directory ACL, a token-keyed name substitution, or a kernel callback registered against an &lt;code&gt;OBJECT_TYPE&lt;/code&gt;. The boundaries you read about elsewhere are the &lt;em&gt;policies&lt;/em&gt;; this tree is the &lt;em&gt;mechanism&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The Object Manager has shipped without architectural change for thirty-three years. Whose decision was that? And why did a 1993 data structure survive untouched while the GUI, the driver model, the security subsystem, and the boot path around it were rewritten more than once?&lt;/p&gt;
&lt;h2&gt;2. Where the namespace came from&lt;/h2&gt;
&lt;p&gt;The decision belongs to Dave Cutler. In 1988 Microsoft hired Cutler away from Digital Equipment Corporation. The Wikipedia biography records the line of operating systems Cutler had developed at DEC: &quot;RSX-11M, VAXELN, VMS, and MICA&quot; [@en-wikipedia-dave-cutler]. Three of those shipped commercially; the fourth, MICA, was cancelled with the Prism RISC program. Cutler walked out, and Microsoft signed him with a charter from Bill Gates to build a portable next-generation kernel that could host the existing Windows API on top of a 32-bit, multi-architecture base [@en-wikipedia-architecture-of-windows-nt]. Cutler brought a small team of DEC veterans with him.&lt;/p&gt;
&lt;p&gt;The Object Manager is one of that team&apos;s earliest design decisions. The architectural bet was to &lt;em&gt;unify every named kernel object&lt;/em&gt; under one filesystem-shaped tree, with each type carrying a parse procedure so a single family of syscalls (&lt;code&gt;NtCreateFile&lt;/code&gt;, &lt;code&gt;NtOpenSection&lt;/code&gt;, &lt;code&gt;NtOpenProcess&lt;/code&gt;, and so on) could address files, registry keys, processes, ports, sections, drivers, devices, jobs, and synchronization primitives using the same path-walk algorithm. That was an unusual choice in 1989. VMS had a more typed, less unified resource broker. Mach treated kernel objects as capability-style port rights and never gave them a hierarchical name. Cutler&apos;s choice was, at heart, a Plan-9-style &quot;every named resource is a filesystem path&quot; idea, imported into a Windows shell.Plan 9 from Bell Labs (Pike, Thompson, et al.) was the academic articulation of the &quot;everything is a path&quot; property: every kernel-named resource, including processes and network connections, surfaced as a file under a 9P-served namespace. Plan 9 never reached commercial scale, but its design idea reached production through NT, and through Linux&apos;s /proc, /sys, and FUSE.&lt;/p&gt;
&lt;p&gt;Windows NT 3.1 shipped on July 27, 1993. It was &quot;Microsoft&apos;s first 32-bit operating system,&quot; supported on IA-32, DEC Alpha, and MIPS [@en-wikipedia-windows-nt-3-1]. The Object Manager was already one of its executive subsystems, sitting alongside the I/O Manager, the Memory Manager, the Process Manager, the Security Reference Monitor, and the Local Procedure Call subsystem [@en-wikipedia-architecture-of-windows-nt]. The four pieces this article will rebuild from scratch -- the &lt;code&gt;OBJECT_HEADER&lt;/code&gt; that prefixes every object in memory, the &lt;code&gt;OBJECT_TYPE&lt;/code&gt; singleton that owns each type&apos;s method table, the &lt;code&gt;ParseProcedure&lt;/code&gt; that delegates path resolution to the owning subsystem, and the &lt;code&gt;OBJECT_DIRECTORY&lt;/code&gt; hash table that maps names to objects -- were all in the NT 3.1 kernel. None of them has been rearchitected since.&lt;/p&gt;
&lt;p&gt;That same year, Microsoft Press published &lt;em&gt;Inside Windows NT&lt;/em&gt;, written by technical writer Helen Custer with a Foreword by Cutler himself. The book&apos;s Object Manager chapter is the canonical pre-2000 description of the namespace, cited on the Sysinternals WinObj page [@ms-winobj] as &quot;Helen Custer&apos;s &lt;em&gt;Inside Windows NT&lt;/em&gt; provides a good overview of the Object Manager namespace.&quot; Custer&apos;s book has been out of print for two decades, but the citation chain through Russinovich&apos;s tool is durable.&lt;/p&gt;
&lt;p&gt;Three years later, in 1996, Russinovich and Cogswell co-founded Winternals and released WinObj 1.0 [@en-wikipedia-mark-russinovich]. WinObj was the first publicly distributed tool to walk &lt;code&gt;\&lt;/code&gt; from user mode, using the native &lt;code&gt;NtOpenDirectoryObject&lt;/code&gt; and &lt;code&gt;NtQueryDirectoryObject&lt;/code&gt; syscalls that the Object Manager exposed through NTDLL [@ms-winobj]. The following year, Russinovich&apos;s October 1997 &lt;em&gt;Windows IT Pro&lt;/em&gt; column &quot;Inside the Object Manager&quot; gave the namespace its first treatment in the trade press. The original URL did not survive changes to TechTarget&apos;s web property portfolio in 2025 (TechTarget was acquired by Informa PLC in 2025), but the WinObj page still cites the column by name as &quot;Mark&apos;s October 1997 [WindowsITPro Magazine] column, &apos;Inside the Object Manager&apos;.&quot;The Russinovich 1997 column has no surviving direct URL because the URL did not survive changes to TechTarget&apos;s web property portfolio in 2025. The most accessible surviving citation is through the WinObj page itself. The same archive failure also explains why Helen Custer&apos;s 1993 biography returns HTTP 404 on Wikipedia in 2026; the book (ISBN 1-55615-481-X) survives in used-book channels only.&lt;/p&gt;
&lt;p&gt;The line of book-length internals references that began with Custer continued through &lt;em&gt;Inside Windows 2000&lt;/em&gt; (third edition) and the &lt;em&gt;Windows Internals&lt;/em&gt; series that succeeded it. The 7th edition Part 1 was published by Microsoft Press in May 2017, authored by Russinovich, Alex Ionescu, and David A. Solomon [@microsoftpressstore-wininternals7-part1]; its Chapter 8 is the current canonical reference for the Object Manager. James Forshaw&apos;s April 2024 &lt;em&gt;Windows Security Internals&lt;/em&gt; [@nostarch-windows-security-internals] is the contemporary companion that ties the namespace into the access-check pipeline.&lt;/p&gt;
&lt;p&gt;The 1993 design assumed a single global namespace. One process tree, one &lt;code&gt;\BaseNamedObjects&lt;/code&gt;, one &lt;code&gt;\Windows\WindowStations\WinSta0&lt;/code&gt;, one &lt;code&gt;\??&lt;/code&gt; view of DOS device letters. Everyone shared everything. Did that assumption survive the Internet?&lt;/p&gt;
&lt;h2&gt;3. The pre-Vista namespace and how it broke&lt;/h2&gt;
&lt;p&gt;It did not. By the late 1990s every interactive Windows user was sharing a name service with every running service. The single-global-namespace assumption produced three distinct exploit classes, each rediscovered repeatedly between 1996 and 2007, and each ultimately closed only by architectural change.&lt;/p&gt;
&lt;p&gt;The most public failure was the &lt;em&gt;shatter attack&lt;/em&gt;. In August 2002 a researcher named Chris Paget published a paper titled &quot;Exploiting design flaws in the Win32 API for privilege escalation.&quot; Wikipedia&apos;s article on the disclosure preserves the chronology: &quot;Shatter attacks became a topic of intense conversation in the security community in August 2002 after the publication of Chris Paget&apos;s paper&quot; [@en-wikipedia-shatter-attack]. The proof-of-concept was about thirty lines. As an unprivileged interactive user, Paget sent a &lt;code&gt;WM_TIMER&lt;/code&gt; window message to a service&apos;s hidden window in the same &lt;code&gt;\Windows\WindowStations\WinSta0&lt;/code&gt; (which all services and all interactive users shared in pre-Vista Windows), with a callback parameter pointing to attacker-placed shellcode. The shellcode ran as SYSTEM.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s initial response, preserved in the Wikipedia article, was that &quot;the flaw lies in the specific, highly privileged service&quot;: a per-service bug, patch the services. That stance did not survive the structural-class argument. The exploit was not a bug in one service. It was a &lt;em&gt;property of the namespace&lt;/em&gt;: as long as services and users shared a window station and a &lt;code&gt;\BaseNamedObjects&lt;/code&gt;, any service that ever called a Windows API processing a message from its message queue was reachable from any logged-in user.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A second class of pre-Vista failure was &lt;em&gt;named-object squatting&lt;/em&gt;. A low-privilege user pre-creates &lt;code&gt;\BaseNamedObjects\Some_Global_Event&lt;/code&gt; with a permissive DACL. A privileged service later calls &lt;code&gt;CreateEvent(&quot;Some_Global_Event&quot;)&lt;/code&gt; with default open-or-create semantics and ends up inheriting the squatter&apos;s object, security descriptor and all. This is not one service-author&apos;s bug; it is the consequence of every service-author trusting that names in a shared namespace would resolve to objects they themselves created. The pattern has been rediscovered approximately once a year for two decades. James Forshaw documents the contemporary named-pipe analog in his 2017 &quot;Named Pipe Secure Prefixes&quot; post [@tiraniddo-named-pipe-secure-prefixes], where the SMSS-created prefixes &lt;code&gt;\Device\NamedPipe\ProtectedPrefix\Administrators&lt;/code&gt;, &lt;code&gt;\Device\NamedPipe\ProtectedPrefix\LocalService&lt;/code&gt;, and &lt;code&gt;\Device\NamedPipe\ProtectedPrefix\NetworkService&lt;/code&gt; are TCB-privilege-gated -- only &lt;code&gt;smss.exe&lt;/code&gt; can create sibling protected prefixes, so a service that publishes its pipe below one of these prefixes inherits a DACL that low-privilege squatters cannot reach.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The third class was &lt;em&gt;symbolic-link redirection&lt;/em&gt;. The pre-Vista Object Manager exposed two kinds of user-creatable symbolic link: object-manager symbolic links inside &lt;code&gt;\??&lt;/code&gt; (the per-session DOS-devices view) and NTFS mount points on disk. The attack pattern was the same in both. A privileged process is asked to open a path the user controls part of. The user has pre-planted a symbolic link partway through the path that redirects the residual walk into a target the user could not otherwise write. The privileged process opens the redirected file and treats it as if it were the original.&lt;/p&gt;
&lt;p&gt;Forshaw&apos;s 2015 Project Zero post on the symbolic-link hardening generation is the canonical taxonomy: &quot;There are three types of symbolic links you can access from a low privileged user, Object Manager Symbolic Links, Registry Key Symbolic Links and NTFS Mount Points&quot; [@p0-symlink-mitigations]. His worked example for the Internet Explorer 11 EPM sandbox is CVE-2015-0055 [@nvd-cve-2015-0055], described in the post as &quot;an information disclosure issue in the IE EPM sandbox which abused symbolic links to bypass a security check.&quot;&lt;/p&gt;
&lt;p&gt;The aha moment from this section is the one Microsoft eventually conceded. The pre-Vista failure mode was not three independent bug families. It was &lt;em&gt;one&lt;/em&gt; structural problem -- a single global namespace shared by every principal -- with three faces. No amount of per-service patching could close it. The fix had to be architectural: the namespace itself had to be partitioned.The Interactive Services Detection Service (ISDS) was Vista&apos;s backward-compatibility hack for legacy services that drew GUIs into Session 0. ISDS displayed a &quot;An interactive service has requested attention&quot; prompt that let the user switch to Session 0 long enough to dismiss the dialog. It was deprecated in Windows 10 1803 and is the historical artifact of just how much pre-Vista code assumed services and users would share a window station.&lt;/p&gt;
&lt;p&gt;That fix took five years to ship. Windows Vista RTM was released on November 8, 2006 and General Availability arrived on January 30, 2007 [@en-wikipedia-windows-vista]. Vista did not ship one fix; it shipped three independent partition mechanisms in the same release window, because the structural failure had three faces and each face needed its own mechanism. The next section catalogues those mechanisms and the four additional generations of additive isolation that have built on them since.&lt;/p&gt;
&lt;h2&gt;4. Six generations of namespace isolation&lt;/h2&gt;
&lt;p&gt;The namespace itself has not been rearchitected since 1993. What has evolved, in six discrete generations between 1993 and 2026, is the set of &lt;em&gt;partition primitives&lt;/em&gt; layered on top: the mechanisms that let the kernel hide subtrees from particular callers, rewrite paths transparently for particular tokens, or invoke a registered watcher when a particular handle is created. Each generation closes a structural class. None has rendered its predecessor obsolete. On 2026 Windows 11 25H2 all six are simultaneously load-bearing.&lt;/p&gt;

flowchart LR
    G1[&quot;Gen 1&lt;br /&gt;NT 3.1, Jul 1993&lt;br /&gt;Single global namespace&quot;] --&amp;gt; G2
    G2[&quot;Gen 2&lt;br /&gt;Vista, Jan 2007 / SP1, Feb 2008&lt;br /&gt;Session 0 + MIC + ObRegisterCallbacks&quot;] --&amp;gt; G3
    G3[&quot;Gen 3&lt;br /&gt;Windows 8, Oct 2012&lt;br /&gt;AppContainer / Lowbox / per-package directory&quot;] --&amp;gt; G4
    G4[&quot;Gen 4&lt;br /&gt;Windows 10 RTM, Jul 2015&lt;br /&gt;VBS / IUM secure-kernel namespace&quot;] --&amp;gt; G5
    G5[&quot;Gen 5&lt;br /&gt;Windows Server 2016, Oct 2016&lt;br /&gt;Server Silos / silo-scoped views&quot;] --&amp;gt; G6
    G6[&quot;Gen 6&lt;br /&gt;MS15-090, Aug 2015 -&amp;gt;&lt;br /&gt;symbolic-link class hardening&quot;]
&lt;p&gt;Generation numbering is thematic (by isolation capability introduced) rather than strictly chronological. Gen 6 (MS15-090, August 11, 2015) predates Gen 5 (Windows Server 2016, October 12, 2016) by 14 months; the numbering reflects the logical layering of isolation mechanisms, not their calendar sequence.&lt;/p&gt;
&lt;h3&gt;4.1 Generation 2 -- Session 0 isolation, integrity levels, ObRegisterCallbacks&lt;/h3&gt;
&lt;p&gt;Vista shipped three mechanisms in one release window because the structural failure had three faces.&lt;/p&gt;
&lt;p&gt;The first was &lt;em&gt;Session 0 isolation&lt;/em&gt;. From Vista forward, services run in Session 0 alone; the first interactive logon starts at Session 1. Each session gets its own subtree at &lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\BaseNamedObjects&lt;/code&gt;, &lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\Windows\WindowStations&lt;/code&gt;, and &lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\DosDevices&lt;/code&gt;. The Win32 &lt;code&gt;Local\&lt;/code&gt; prefix routes through &lt;code&gt;kernel32!BaseGetNamedObjectDirectory&lt;/code&gt; into the per-session BNO; &lt;code&gt;Global\&lt;/code&gt; routes into the shared &lt;code&gt;\BaseNamedObjects&lt;/code&gt; [@ms-termserv-kernel-object-namespaces]. The Wikipedia Shatter article preserves the architectural fix verbatim: &quot;Local user logins were moved from Session 0 to Session 1, thus separating the user&apos;s processes from system services that could be vulnerable&quot; [@en-wikipedia-shatter-attack]. After Vista an interactive user could no longer &lt;code&gt;SendMessage(WM_TIMER)&lt;/code&gt; into a service&apos;s hidden window because the user and the service no longer shared a window station.&lt;/p&gt;
&lt;p&gt;The second mechanism was &lt;em&gt;Mandatory Integrity Control&lt;/em&gt;. Vista introduced a new ACE type, &lt;code&gt;SYSTEM_MANDATORY_LABEL_ACE&lt;/code&gt;, attached to every object&apos;s security descriptor. Each token carries one of four integrity levels (Low S-1-16-4096, Medium S-1-16-8192, High S-1-16-12288, or System S-1-16-16384), and the Security Reference Monitor compares the requester&apos;s level against the object&apos;s level &lt;em&gt;after&lt;/em&gt; path resolution succeeds [@en-wikipedia-mandatory-integrity-control]. MIC is not a namespace partition. A Low-IL process and a Medium-IL process resolve the same &lt;code&gt;\BaseNamedObjects&lt;/code&gt; directory; only the open is denied at the leaf. The structural property MIC adds is that the leaf check is &lt;em&gt;unbypassable from user mode&lt;/em&gt;; the check fires regardless of which DACL the object carries.&lt;/p&gt;
&lt;p&gt;The third mechanism was &lt;code&gt;ObRegisterCallbacks&lt;/code&gt;. Microsoft&apos;s wdm.h documentation records the API&apos;s first ship date verbatim: &quot;Available starting with Windows Vista with Service Pack 1 (SP1) and Windows Server 2008&quot; [@ms-obregistercallbacks]. The API lets a KMCS-signed driver intercept handle creation and handle duplication on &lt;code&gt;PsProcessType&lt;/code&gt;, &lt;code&gt;PsThreadType&lt;/code&gt;, and the desktop object type. The registration carries an Altitude (a FltMgr-style collision key) and an array of &lt;code&gt;OB_OPERATION_REGISTRATION&lt;/code&gt; records [@ms-ob-callback-registration]. Pre-operation callbacks can strip access-mask bits before the handle is granted; post-operation callbacks fire for logging. The parallel API &lt;code&gt;PsSetCreateProcessNotifyRoutineEx&lt;/code&gt; [@ms-pssetcreateprocessnotifyroutineex] covers process creation. Together, these are the kernel-mode primitives every modern EDR product depends on; they ship inside the Object Manager itself and they are the reason an EDR knows when something opens a handle to &lt;code&gt;lsass.exe&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;4.2 Generation 3 -- AppContainer and the lowbox token&lt;/h3&gt;
&lt;p&gt;Windows 8 shipped on October 26, 2012 [@en-wikipedia-windows-8]. Modern / UWP apps downloaded from the Microsoft Store needed a sandbox finer-grained than per-session BNO. The Vista path rewriting in &lt;code&gt;kernel32!BaseGetNamedObjectDirectory&lt;/code&gt; happened in user mode, which made it the wrong layer for a sandbox: a hostile renderer could in principle bypass the user-mode rewrite. The new layer moved into the kernel.&lt;/p&gt;
&lt;p&gt;Each UWP / MSIX process runs under a special token type, the &lt;em&gt;AppContainer / LowBox token&lt;/em&gt; (referred to in kernel code as the &lt;em&gt;lowbox token&lt;/em&gt;), created by &lt;code&gt;NtCreateLowBoxToken&lt;/code&gt;. The token carries a &lt;code&gt;TOKEN_APPCONTAINER_INFORMATION&lt;/code&gt; block that names the process&apos;s package SID (&lt;code&gt;S-1-15-2-...&lt;/code&gt;) and an &lt;code&gt;AppContainerNumber&lt;/code&gt;. Inside &lt;code&gt;ObpLookupObjectName&lt;/code&gt;, &lt;em&gt;before&lt;/em&gt; the path is walked, the kernel checks whether the caller&apos;s token is a lowbox token; if it is, lookups of &lt;code&gt;\BaseNamedObjects\X&lt;/code&gt;, &lt;code&gt;\RPC Control\X&lt;/code&gt;, and other rewriteable paths get redirected into &lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\AppContainerNamedObjects\&amp;lt;package-sid&amp;gt;\X&lt;/code&gt;. The user-mode caller never sees the rewrite. The package-SID directory is created by SYSTEM at process-creation time with a security descriptor that grants the package SID, and only the package SID, full access. Microsoft&apos;s wording is precise: AppContainer works by &quot;sandboxing the application kernel objects, the AppContainer environment prevents the application from influencing, or being influenced by, other application processes&quot; [@ms-appcontainer-isolation].&lt;/p&gt;

The AppInfo service, which is responsible for creating the new application, calls the undocumented API CreateAppContainerToken to do some internal housekeeping. Unfortunately this API creates object directories under the user&apos;s AppContainerNamedObjects object directory to support redirecting BaseNamedObjects and RPC endpoints by the OS. -- James Forshaw, Project Zero Issue 1550 [@p0-issue1550]
&lt;p&gt;The residual class the AppContainer model has not closed is the one Forshaw&apos;s August 30, 2018 Project Zero post [@p0-issue1550] documents: because the SYSTEM-side AppInfo service has to write into the user&apos;s AppContainerNamedObjects subtree to set up redirection, an unprivileged caller can race the directory creation and end up planting a symbolic link the SYSTEM service then follows. The class -- &quot;SYSTEM-privileged directory creation in user-controllable territory&quot; -- is the worked example of why &quot;the kernel rewrites the name&quot; is an isolation property only when the SYSTEM helpers also use the rewrite.&lt;/p&gt;
&lt;h3&gt;4.3 Generation 4 -- VBS trustlets and the IUM secure-kernel namespace&lt;/h3&gt;
&lt;p&gt;Windows 10 RTM shipped on July 29, 2015 [@en-wikipedia-windows-10-version-history]. The Virtualization-Based Security (VBS) feature set introduced a parallel object-manager-shaped namespace that lives in Virtual Trust Level 1 (VTL1) and is inaccessible to the VTL0 NT kernel. Inside VTL1 the Secure Kernel (&lt;code&gt;securekernel.exe&lt;/code&gt;) maintains its own root, its own type registry, and its own handle-table machinery. The VTL0 NT kernel can see &lt;em&gt;trustlet processes&lt;/em&gt; -- the per-trustlet user-mode containers running in Isolated User Mode (IUM) -- but it cannot reach into their secure-side state.&lt;/p&gt;
&lt;p&gt;Alex Ionescu&apos;s Black Hat USA 2015 talk Battle of SKM and IUM [@ionescu-bh2015-pdf] is the canonical inventory of the inbox Trustlet IDs at ship: Trustlet 0 is the Secure Kernel Process hosting Device Guard; Trustlet 1 is LSAISO.EXE for Credential Guard; Trustlet 2 is VMSP.EXE hosting the virtual TPM; Trustlet 3 is the vTPM provisioning trustlet. Each is identified by a Trustlet ID and reachable only through narrow Secure Kernel ALPC ports. The VBS Trustlets piece in this series unpacks the threat model.&lt;/p&gt;
&lt;h3&gt;4.4 Generation 5 -- Server Silos and the silo-scoped namespace&lt;/h3&gt;
&lt;p&gt;Windows Server 2016 shipped on October 12, 2016 [@en-wikipedia-windows-server-2016]. Microsoft needed a Linux-namespaces equivalent so that container runtimes -- Docker, containerd, and the Azure Kubernetes Service Windows-node pods that followed -- could host adjacent workloads on one kernel. The answer was &lt;em&gt;Server Silo&lt;/em&gt;: a new &lt;code&gt;OBJECT_TYPE&lt;/code&gt; registered alongside &lt;code&gt;Job&lt;/code&gt;, &lt;code&gt;Process&lt;/code&gt;, and &lt;code&gt;Thread&lt;/code&gt;, that carries its own &lt;code&gt;RootDirectory&lt;/code&gt;, &lt;code&gt;DosDevicesDirectory&lt;/code&gt;, and &lt;code&gt;ServerSiloGlobals&lt;/code&gt;. A process attached to a silo via &lt;code&gt;PsAttachSiloToCurrentThread&lt;/code&gt; sees the silo&apos;s namespace as its root; the silo&apos;s &lt;code&gt;\GLOBAL??\C:&lt;/code&gt; resolves to the silo&apos;s &lt;code&gt;\Device\HarddiskVolume*&lt;/code&gt;, which is a different &lt;code&gt;Device&lt;/code&gt; object from the host&apos;s. Job objects [@ms-job-objects] provide the cgroups-equivalent resource-accounting dimension; the Silo type builds on top.&lt;/p&gt;
&lt;p&gt;The canonical reverse-engineering reference is Daniel Prizmant&apos;s July 2020 Unit 42 writeup, which spells out the architecture: &quot;job objects are used in a similar way control groups (cgroups) are used in Linux, and... server silo objects were used as a replacement for namespaces support in the kernel&quot; [@unit42-rev-eng-windows-containers].&lt;/p&gt;
&lt;p&gt;The companion piece, Prizmant&apos;s June 2021 &lt;em&gt;Siloscape&lt;/em&gt; [@unit42-siloscape], is the first known malware family that escapes the silo boundary: Prizmant named the malware &quot;Siloscape (sounds like silo escape) because its primary goal is to escape the container, and in Windows this is implemented mainly by a server silo.&quot; James Forshaw&apos;s April 2021 Project Zero post &lt;em&gt;Who Contains the Containers?&lt;/em&gt; [@p0-who-contains-containers] is the four-LPE companion disclosure. Microsoft&apos;s standing position is that Server Silo is not a security boundary; the Hyper-V Container, which adds a Hyper-V VM around the container&apos;s silo, is the security-boundary product.&lt;/p&gt;
&lt;h3&gt;4.5 Generation 6 -- the symbolic-link hardening continuum&lt;/h3&gt;
&lt;p&gt;The cross-cutting hardening generation closes the symlink subclass that recurred in Generations 1, 3, and 5. MS15-090 shipped on August 11, 2015 [@ms-ms15-090] and &quot;corrects how Windows Object Manager handles object symbolic links created by a sandbox process, by preventing improper interaction with the registry by sandboxed applications, and by preventing improper interaction with the filesystem by sandboxed applications.&quot; The bulletin&apos;s canonical Object Manager CVE is CVE-2015-2428 [@nvd-cve-2015-2428], described verbatim as the case where the &quot;Object Manager in Microsoft Windows... does not properly constrain impersonation levels during interaction with object symbolic links that originated in a sandboxed process.&quot; Subsequent Windows 10 builds added &lt;code&gt;OBJ_DONT_REPARSE&lt;/code&gt;, an open-time flag that disables symbolic-link substitution for callers willing to opt in, and post-Siloscape patches in 2021 closed &lt;code&gt;NtSetInformationSymbolicLink&lt;/code&gt; retargeting from inside a silo.&lt;/p&gt;
&lt;p&gt;The scope document for this article originally attributed MS15-090 to CVE-2015-2528 and CVE-2015-1463. Independent NVD verification confirmed neither is correct: CVE-2015-2528 [@nvd-cve-2015-2528] is the MS15-102 Task Management EoP, and CVE-2015-1463 [@nvd-cve-2015-1463] is a ClamAV denial-of-service crash. The canonical MS15-090 OM-symlink CVE is CVE-2015-2428. Separately, CVE-2018-0824 [@nvd-cve-2018-0824] is a CWE-502 COM deserialization issue that joined the CISA KEV catalog on 2024-08-05, not a namespace-squatting CVE.&lt;/p&gt;
&lt;p&gt;The residual subclass MS15-090 did not close was the per-session &lt;code&gt;\??&lt;/code&gt; DosDevices remapping path under impersonation. A low-privileged process whose token is impersonated by a SYSTEM service can plant a &lt;code&gt;DefineDosDevice&lt;/code&gt; remapping that survives into the impersonation-time &lt;code&gt;\??&lt;/code&gt; view, and the SYSTEM-side activation-context resolver then opens the redirected path while running with elevated privileges. The canonical 2023 worked example is HackSys&apos;s &lt;em&gt;Activation Context Hell -- DosDevices Remapping Attack under Impersonation&lt;/em&gt; [@hacksys-activation-context-hell], which targets the CSRSS / SxS activation-context resolver and shipped as CVE-2023-35359 [@nvd-cve-2023-35359], with the closely-related CVE-2022-22047 [@nvd-cve-2022-22047] covering the underlying CSRSS surface. The mitigation has to live inside the impersonation-aware &lt;code&gt;\??&lt;/code&gt; resolver in the SYSTEM caller, not at the symlink-creation gate.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every generation since Generation 1 has &lt;em&gt;layered&lt;/em&gt; a new isolation primitive on top of the prior generation. None has rendered its predecessor obsolete. On 2026 Windows 11 25H2 all six generations coexist simultaneously: a UWP / MSIX app inside a Server Silo on a VBS-enabled host is session-partitioned, lowbox-rewritten, silo-scoped, VTL0-confined, integrity-gated, and watched by every loaded EDR&apos;s &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; filter. Each layer adds an independent enforcement point at &lt;code&gt;ObpLookupObjectName&lt;/code&gt; time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Six generations of isolation primitives is a tidy story, but it has glossed the most important question. What is the actual kernel data structure all six generations parameterize? What does the path-walk algorithm look like, what is the type registry, and where does the hash table live?&lt;/p&gt;
&lt;h2&gt;5. The four load-bearing primitives&lt;/h2&gt;
&lt;p&gt;If you remember one paragraph from this article, make it this one. The Object Manager namespace is built out of four kernel data structures: an &lt;code&gt;OBJECT_HEADER&lt;/code&gt; that prefixes every named object in memory, an &lt;code&gt;OBJECT_TYPE&lt;/code&gt; singleton that owns each type&apos;s method table, a &lt;code&gt;ParseProcedure&lt;/code&gt; that delegates path resolution to the owning subsystem when needed, and an &lt;code&gt;OBJECT_DIRECTORY&lt;/code&gt; hash table that maps names to objects. Every Windows security boundary you have read about is a parameter to one of these four pieces. The next eight subsections rebuild them one at a time.&lt;/p&gt;

flowchart TB
    OD[&quot;OBJECT_DIRECTORY&lt;br /&gt;(37-bucket hash table)&quot;] --&amp;gt;|&quot;hash(name) % 37&quot;| OH
    OH[&quot;OBJECT_HEADER&lt;br /&gt;(PointerCount, HandleCount,&lt;br /&gt;TypeIndex, InfoMask,&lt;br /&gt;SecurityDescriptor, Body offset)&quot;] --&amp;gt;|&quot;TypeIndex XOR&lt;br /&gt;ObHeaderCookie&quot;| OT
    OT[&quot;OBJECT_TYPE singleton&lt;br /&gt;(in nt!ObTypeIndexTable)&quot;] --&amp;gt;|&quot;TypeInfo&quot;| TI
    TI[&quot;TYPE_INFO method table&lt;br /&gt;(Dump, Open, Close, Delete,&lt;br /&gt;ParseProcedure,&lt;br /&gt;Security, QueryName, ...)&quot;]
    OH --&amp;gt;|&quot;Body[]&quot;| BODY[&quot;Type-specific body&lt;br /&gt;(EPROCESS, FILE_OBJECT,&lt;br /&gt;SECTION_OBJECT, ...)&quot;]
&lt;h3&gt;5.1 OBJECT_HEADER&lt;/h3&gt;
&lt;p&gt;Every named kernel object lives in non-paged pool. Immediately &lt;em&gt;before&lt;/em&gt; each object&apos;s typed body sits an &lt;code&gt;OBJECT_HEADER&lt;/code&gt;, a 0x30-byte (48-byte on x64) structure that the Object Manager owns. &lt;code&gt;PointerCount&lt;/code&gt; and &lt;code&gt;HandleCount&lt;/code&gt; are the two reference counts: the former tracks raw kernel-mode pointer references, the latter tracks user-mode handles. &lt;code&gt;TypeIndex&lt;/code&gt; is a single byte that indexes into the &lt;code&gt;nt!ObTypeIndexTable&lt;/code&gt; to find the object&apos;s type singleton; since Windows 10 1709, the byte is XOR-obfuscated against the per-boot &lt;code&gt;nt!ObHeaderCookie&lt;/code&gt; so that simple type confusion is non-trivial.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;InfoMask&lt;/code&gt; is a bitmap of optional sub-headers that may precede the main header: &lt;code&gt;OBJECT_HEADER_NAME_INFO&lt;/code&gt; for named objects, &lt;code&gt;OBJECT_HEADER_QUOTA_INFO&lt;/code&gt; for objects that charge a quota block, &lt;code&gt;OBJECT_HEADER_HANDLE_INFO&lt;/code&gt; for objects that need per-process handle accounting. &lt;code&gt;SecurityDescriptor&lt;/code&gt; is a tagged pointer to the object&apos;s DACL/SACL. &lt;code&gt;Body[]&lt;/code&gt; is the offset at which the type-specific payload begins; for a process object that payload is an &lt;code&gt;EPROCESS&lt;/code&gt;, for a file it is a &lt;code&gt;FILE_OBJECT&lt;/code&gt;, and so on. The canonical reference is Chapter 8 of &lt;em&gt;Windows Internals 7th Edition Part 1&lt;/em&gt; [@microsoftpressstore-wininternals7-part1].&lt;/p&gt;

The per-object header (`nt!_OBJECT_HEADER`) that precedes every named kernel object in non-paged pool. Carries reference counts (`PointerCount`, `HandleCount`), a `TypeIndex` byte that points into `nt!ObTypeIndexTable` (XOR-obfuscated against `nt!ObHeaderCookie` since Windows 10 1709), an `InfoMask` describing optional sub-headers, a `SecurityDescriptor` pointer, and the offset to the typed `Body[]`.
&lt;p&gt;The &lt;code&gt;TypeIndex&lt;/code&gt; XOR-with-cookie is one of the smallest kernel hardening changes Microsoft has shipped: a single byte that prevents a poisoned &lt;code&gt;OBJECT_HEADER&lt;/code&gt; from naming an arbitrary type after a heap-corruption primitive. The cookie is per-boot and lives in &lt;code&gt;nt!ObHeaderCookie&lt;/code&gt;. The hardening is documented in &lt;em&gt;Windows Internals 7th Edition&lt;/em&gt; Chapter 8 [@microsoftpressstore-wininternals7-part1] and in Geoff Chappell&apos;s reverse-engineering studies; Microsoft has not, as of 2026, published a Learn-hosted reference for the cookie itself.&lt;/p&gt;
&lt;h3&gt;5.2 OBJECT_TYPE&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OBJECT_TYPE&lt;/code&gt; is the per-type singleton. There is exactly one &lt;code&gt;OBJECT_TYPE&lt;/code&gt; per registered kernel type, and they live in &lt;code&gt;\ObjectTypes&lt;/code&gt;. On Windows 11 25H2 the count sits at roughly seventy-five: &lt;code&gt;Type&lt;/code&gt;, &lt;code&gt;Directory&lt;/code&gt;, &lt;code&gt;SymbolicLink&lt;/code&gt;, &lt;code&gt;Token&lt;/code&gt;, &lt;code&gt;Job&lt;/code&gt;, &lt;code&gt;Process&lt;/code&gt;, &lt;code&gt;Thread&lt;/code&gt;, &lt;code&gt;Section&lt;/code&gt;, &lt;code&gt;Key&lt;/code&gt;, &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;Event&lt;/code&gt;, &lt;code&gt;Mutant&lt;/code&gt;, &lt;code&gt;Semaphore&lt;/code&gt;, &lt;code&gt;Timer&lt;/code&gt;, &lt;code&gt;WindowStation&lt;/code&gt;, &lt;code&gt;Desktop&lt;/code&gt;, &lt;code&gt;Device&lt;/code&gt;, &lt;code&gt;Driver&lt;/code&gt;, &lt;code&gt;IoCompletion&lt;/code&gt;, &lt;code&gt;ALPC Port&lt;/code&gt;, &lt;code&gt;EtwRegistration&lt;/code&gt;, &lt;code&gt;Silo&lt;/code&gt;, and dozens more.&lt;/p&gt;

The per-type singleton (`nt!_OBJECT_TYPE`) that owns each kernel type&apos;s method table. The `TypeInfo` field carries eight procedure pointers and one offset field (WaitObjectFlagOffset): `DumpProcedure`, `OpenProcedure`, `CloseProcedure`, `DeleteProcedure`, `ParseProcedure` (the path-resolution callback), `SecurityProcedure`, `QueryNameProcedure`, `OkayToCloseProcedure`, and a `WaitObjectFlagOffset` offset for waitable types. Every `OBJECT_TYPE` instance is reachable through `\ObjectTypes`.
&lt;p&gt;The &lt;code&gt;TypeInfo&lt;/code&gt; field on each &lt;code&gt;OBJECT_TYPE&lt;/code&gt; carries eight procedure pointers and one offset field (WaitObjectFlagOffset). The most consequential is the &lt;code&gt;ParseProcedure&lt;/code&gt;. When &lt;code&gt;ObpLookupObjectName&lt;/code&gt; is walking a path component-by-component, and a step lands on an object whose &lt;code&gt;OBJECT_TYPE&lt;/code&gt; defines a &lt;code&gt;ParseProcedure&lt;/code&gt;, the OM hands the &lt;em&gt;residual&lt;/em&gt; path and the desired access to that procedure, which becomes the namespace authority below that point. That is how the registry&apos;s &lt;code&gt;Key&lt;/code&gt; type, the I/O Manager&apos;s &lt;code&gt;Device&lt;/code&gt; type, and the various WMI / Volume-Manager subsystems insert themselves into the namespace without the Object Manager having to know any of their internal structure [@en-wikipedia-object-manager].&lt;/p&gt;
&lt;h3&gt;5.3 The parse procedure&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ObpLookupObjectName&lt;/code&gt; walks &lt;code&gt;\Foo\Bar\Baz\...\Leaf&lt;/code&gt; left-to-right. At each component the walker does one of three things. The common case is a hash-table lookup in the current &lt;code&gt;OBJECT_DIRECTORY&lt;/code&gt;&apos;s 37 buckets to find the child object by name. The second case is &lt;code&gt;SymbolicLink&lt;/code&gt; substitution: if the child object&apos;s type is &lt;code&gt;SymbolicLink&lt;/code&gt;, the walker substitutes the link target and re-enters the walk at the substitution. The third and most consequential case is &lt;em&gt;parse-procedure handoff&lt;/em&gt;. If the child object&apos;s &lt;code&gt;OBJECT_TYPE&lt;/code&gt; has a non-null &lt;code&gt;ParseProcedure&lt;/code&gt;, the walker stops, hands the residual path string to that procedure, and lets it decide what to do.&lt;/p&gt;

The load-bearing method pointer on each `OBJECT_TYPE`&apos;s `TypeInfo` field. When `ObpLookupObjectName` encounters an object whose type defines a `ParseProcedure`, the residual path is handed to that procedure for resolution. The two canonical parse procedures are `IopParseDevice` (for the `Device` type, which delegates further resolution to the device&apos;s owning driver via `IRP_MJ_CREATE`) and `CmpParseKey` (for the `Key` type, which walks the registry hive).
&lt;p&gt;&lt;code&gt;IopParseDevice&lt;/code&gt; is the parse procedure for the &lt;code&gt;Device&lt;/code&gt; type. When the walker reaches &lt;code&gt;\Device\HarddiskVolume1&lt;/code&gt; and is asked to continue with &lt;code&gt;\Users\me\file.txt&lt;/code&gt;, the I/O Manager builds an &lt;code&gt;IRP_MJ_CREATE&lt;/code&gt; packet, dispatches it to the filesystem driver that owns the volume (NTFS, ReFS, ExFAT, FAT32, or one of several others), and lets that driver walk the rest of the path inside its own on-disk structures. The driver returns a &lt;code&gt;FILE_OBJECT&lt;/code&gt;, which the Object Manager packages into a handle.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CmpParseKey&lt;/code&gt; is the parse procedure for the &lt;code&gt;Key&lt;/code&gt; type. When the walker reaches &lt;code&gt;\REGISTRY&lt;/code&gt; and is asked to continue with &lt;code&gt;\MACHINE\Software\Microsoft\Windows&lt;/code&gt;, the Configuration Manager takes over and walks the in-memory hive structures.&lt;/p&gt;
&lt;p&gt;The structural consequence is profound. Every named file in Windows is, technically, a leaf in the Object Manager namespace. NTFS, ReFS, ExFAT, and the registry are not separate naming systems; they are parse-procedure callbacks that hand &lt;code&gt;FILE_OBJECT&lt;/code&gt; or &lt;code&gt;KEY&lt;/code&gt; bodies back to the OM.&lt;/p&gt;

sequenceDiagram
    participant User as User Process
    participant OM as ObpLookupObjectName
    participant Dir as \GLOBAL?? OBJECT_DIRECTORY
    participant Dev as \Device\HarddiskVolume1 (Device type)
    participant Drv as NTFS Driver
    User-&amp;gt;&amp;gt;OM: NtCreateFile(&quot;\??\C:\Users\me\file.txt&quot;)
    OM-&amp;gt;&amp;gt;OM: rewrite \??\ -&amp;gt; \Sessions\\DosDevices\
    OM-&amp;gt;&amp;gt;Dir: lookup &quot;C:&quot;
    Dir--&amp;gt;&amp;gt;OM: SymbolicLink -&amp;gt; \Device\HarddiskVolume1
    OM-&amp;gt;&amp;gt;OM: substitute, re-enter walk
    OM-&amp;gt;&amp;gt;Dev: lookup \Device\HarddiskVolume1
    Dev--&amp;gt;&amp;gt;OM: type=Device, has ParseProcedure
    OM-&amp;gt;&amp;gt;Drv: IopParseDevice with &quot;\Users\me\file.txt&quot;
    Drv-&amp;gt;&amp;gt;Drv: IRP_MJ_CREATE: walk MFT, find file
    Drv--&amp;gt;&amp;gt;OM: FILE_OBJECT
    OM--&amp;gt;&amp;gt;User: HANDLE
&lt;h3&gt;5.4 The 37-bucket directory hash&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OBJECT_DIRECTORY&lt;/code&gt; is a 37-bucket open-hash table. The hash function is &lt;code&gt;RtlHashUnicodeString&lt;/code&gt;, applied to each component name. Thirty-seven was the prime Cutler picked in 1993; the constant has not changed in thirty-three years. The folk-knowledge corroboration is in Chapter 8 of &lt;em&gt;Windows Internals 7th Edition Part 1&lt;/em&gt; and in Forshaw&apos;s &lt;em&gt;Windows Security Internals&lt;/em&gt; Chapter 8; Microsoft has never published a Learn-hosted spec for the constant [@nostarch-windows-security-internals].&lt;/p&gt;

The 37-bucket open-hash table (`nt!_OBJECT_DIRECTORY`) that lives at every interior node of the Object Manager tree. Keys are `UNICODE_STRING` component names; the hash is `RtlHashUnicodeString` modulo 37. Each bucket is a linked list of `OBJECT_DIRECTORY_ENTRY` records that point at the next-level `OBJECT_HEADER`. Reading the tree requires `Directory`-`TRAVERSE` rights on the parent.
&lt;p&gt;The 37-bucket constant from 1993 has not changed in thirty-three years. On a 2026 Windows 11 25H2 box with several hundred MSIX packages each owning an &lt;code&gt;\AppContainerNamedObjects\&amp;lt;package-sid&amp;gt;\&lt;/code&gt; subtree, average bucket chains run several entries deep. Collision pressure on the constant is the open problem returned to in Section 9.&lt;/p&gt;
&lt;h3&gt;5.5 The lowbox redirect inside ObpLookupObjectName&lt;/h3&gt;
&lt;p&gt;This is the subsection that earns the second aha moment of the article.&lt;/p&gt;
&lt;p&gt;When the calling thread&apos;s primary token is a lowbox token, &lt;code&gt;ObpLookupObjectName&lt;/code&gt; consults the token&apos;s &lt;code&gt;AppContainerNumber&lt;/code&gt; and package SID &lt;em&gt;before&lt;/em&gt; it begins the walk. Lookups that would otherwise resolve into &lt;code&gt;\BaseNamedObjects&lt;/code&gt; or &lt;code&gt;\RPC Control&lt;/code&gt; are rewritten into &lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\AppContainerNamedObjects\&amp;lt;package-sid&amp;gt;\&lt;/code&gt;. The rewrite happens transparently to the user-mode Win32 caller, which still thinks it asked for &lt;code&gt;\BaseNamedObjects\X&lt;/code&gt;.&lt;/p&gt;

A specialised token type produced by `NtCreateLowBoxToken` that carries a `TOKEN_APPCONTAINER_INFORMATION` block (with a package SID `S-1-15-2-...` and an `AppContainerNumber`). When a process runs under a lowbox token, `ObpLookupObjectName` rewrites every named-object lookup into the per-package directory `\Sessions\\AppContainerNamedObjects\\` before path walking begins.

The user-facing brand for the lowbox-token mechanism. Every UWP / MSIX / Windows Store app runs in an AppContainer. The Windows API surface is unchanged for the app; the Object Manager rewrites every named-object name into a per-package subtree, gating cross-package coordination at the namespace layer. The Microsoft Learn page describes this as &quot;Sandboxing the application kernel objects, the AppContainer environment prevents the application from influencing, or being influenced by, other application processes&quot; [@ms-appcontainer-isolation].
&lt;p&gt;The aha moment is structural. AppContainer is not a &lt;em&gt;containment&lt;/em&gt; mechanism the way you might first picture it. It is a &lt;em&gt;name-translation&lt;/em&gt; mechanism. The lowbox token tells the kernel which directory to rewrite every name into; the sandbox is, at root, a hash-table indirection inside the kernel&apos;s path-walk function. The Edge renderer process cannot name &lt;code&gt;\BaseNamedObjects\GlobalEvent_Foo&lt;/code&gt; because the kernel rewrites that name into &lt;code&gt;\Sessions\1\AppContainerNamedObjects\S-1-15-2-...\Global\GlobalEvent_Foo&lt;/code&gt; before lookup even begins. The &quot;sandbox&quot; is a hash-table redirect.&lt;/p&gt;
&lt;h3&gt;5.6 The Silo OBJECT_TYPE and silo-scoped views&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Silo&lt;/code&gt; is itself a registered &lt;code&gt;OBJECT_TYPE&lt;/code&gt;. Each silo instance carries a silo-scoped &lt;code&gt;RootDirectory&lt;/code&gt;, &lt;code&gt;DosDevicesDirectory&lt;/code&gt;, and &lt;code&gt;ServerSiloGlobals&lt;/code&gt; (with the silo&apos;s own registry-hive root and per-silo &lt;code&gt;BaseNamedObjects&lt;/code&gt; root). &lt;code&gt;PsAttachSiloToCurrentThread&lt;/code&gt; switches the thread&apos;s namespace view; once attached, every Object Manager lookup runs through the silo&apos;s roots instead of the host&apos;s. Job objects, which provide the cgroups-equivalent resource-accounting substrate, are the underlying primitive the Silo type extends [@ms-job-objects]. The structural design history is in Prizmant&apos;s reverse-engineering writeup [@unit42-rev-eng-windows-containers].&lt;/p&gt;

A specialised `Job`-derived kernel object (`OBJECT_TYPE` Silo) introduced in Windows Server 2016 that carries silo-scoped `RootDirectory`, `DosDevicesDirectory`, and `ServerSiloGlobals` fields. A thread attached to a silo via `PsAttachSiloToCurrentThread` sees the silo&apos;s namespace as its root; the silo&apos;s `\GLOBAL??\C:` resolves to the silo&apos;s `\Device\HarddiskVolume*`, which is a different `Device` object from the host&apos;s. Server Silo is the substrate underneath Windows Server Containers and WSL1.
&lt;h3&gt;5.7 The Secure Kernel&apos;s parallel namespace&lt;/h3&gt;
&lt;p&gt;Inside VTL1, the Secure Kernel maintains a separate Object Manager tree with its own root, its own type registry, and its own handle-table machinery. The VTL0 NT kernel cannot enumerate this tree; the only cross-VTL traffic is the narrow ALPC interface each trustlet publishes. Ionescu&apos;s BH2015 inventory (Trustlet IDs 0 through 3 at ship, growing in subsequent releases) is the canonical primary [@ionescu-bh2015-pdf].&lt;/p&gt;

A user-mode process running in Isolated User Mode under the VTL1 Secure Kernel. Each trustlet is signed with both the 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), runs at Signature Level 12, and is reachable from VTL0 only through narrow ALPC ports. LSAISO.EXE (Credential Guard), VMSP.EXE (virtual TPM host), and the vTPM provisioning trustlet are the inbox examples.
&lt;h3&gt;5.8 The handle table&lt;/h3&gt;
&lt;p&gt;The namespace is the &lt;em&gt;name&lt;/em&gt; side; the per-process &lt;code&gt;HANDLE_TABLE&lt;/code&gt; is the &lt;em&gt;access&lt;/em&gt; side. Once a handle exists in a process, no name lookup happens on subsequent use; the kernel dereferences the handle through a three-level radix tree indexed by the 32-bit handle value, lands on an &lt;code&gt;OBJECT_HEADER&lt;/code&gt;, and operates on the body. This is why &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; fires on handle &lt;em&gt;creation&lt;/em&gt; and &lt;em&gt;duplication&lt;/em&gt; rather than on every use, and why an inherited handle bypasses the callback entirely. The structural consequence -- that the Object Manager is the gate at name resolution but not at every operation -- comes back in Section 8.&lt;/p&gt;
&lt;p&gt;Now you know the data structure. But what does the actual tree look like in 2026? What does &lt;code&gt;\&lt;/code&gt; contain on a Windows 11 25H2 box, and which security boundary lives in each top-level directory?&lt;/p&gt;
&lt;h2&gt;6. The 2026 top-level directory atlas&lt;/h2&gt;
&lt;p&gt;Open &lt;code&gt;WinObj.exe&lt;/code&gt; as administrator on a Windows 11 25H2 machine and the root directory at &lt;code&gt;\&lt;/code&gt; carries roughly twenty entries. The table below catalogues the load-bearing ones. Each row names the directory, the security boundary it physically realises, and a representative exploit class that has been thrown at it. The driver kit&apos;s Object Directories reference [@ms-object-directories] is Microsoft&apos;s canonical inventory.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Top-level directory&lt;/th&gt;
&lt;th&gt;What it contains&lt;/th&gt;
&lt;th&gt;Which boundary it enforces&lt;/th&gt;
&lt;th&gt;Exploit class&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\ObjectTypes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The ~75 &lt;code&gt;OBJECT_TYPE&lt;/code&gt; singletons (&lt;code&gt;Process&lt;/code&gt;, &lt;code&gt;Thread&lt;/code&gt;, &lt;code&gt;Section&lt;/code&gt;, &lt;code&gt;Key&lt;/code&gt;, &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;Token&lt;/code&gt;, &lt;code&gt;Job&lt;/code&gt;, &lt;code&gt;Silo&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;td&gt;Meta -- the type registry the rest of the namespace depends on&lt;/td&gt;
&lt;td&gt;Type confusion (mitigated by &lt;code&gt;ObHeaderCookie&lt;/code&gt; since Windows 10 1709)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Device&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Driver-published device objects (&lt;code&gt;\Device\HarddiskVolume*&lt;/code&gt;, &lt;code&gt;\Device\Tcp&lt;/code&gt;, &lt;code&gt;\Device\Tpm&lt;/code&gt;, &lt;code&gt;\Device\NamedPipe&lt;/code&gt;, &lt;code&gt;\Device\Mailslot&lt;/code&gt;, &lt;code&gt;\Device\Vmbus&lt;/code&gt;, &lt;code&gt;\Device\KsecDD&lt;/code&gt;, &lt;code&gt;\Device\CNG&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;The I/O Manager&apos;s surface; each driver&apos;s parse procedure consumes residual paths&lt;/td&gt;
&lt;td&gt;Bait-and-switch on &lt;code&gt;\Device&lt;/code&gt; (a low-privilege user redirects a privileged opener through a planted symbolic link)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Driver&lt;/code&gt;, &lt;code&gt;\FileSystem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loaded &lt;code&gt;DRIVER_OBJECT&lt;/code&gt; registries&lt;/td&gt;
&lt;td&gt;KMCS / HVCI driver-load gate&lt;/td&gt;
&lt;td&gt;Vulnerable signed-driver class (BYOVD)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\GLOBAL??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The machine-wide DosDevices view -- where &lt;code&gt;C:&lt;/code&gt; and &lt;code&gt;D:&lt;/code&gt; are symlinks to &lt;code&gt;\Device\HarddiskVolume*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cross-session drive-letter map&lt;/td&gt;
&lt;td&gt;Symlink redirect across session boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The per-session DosDevices alias, falling through to &lt;code&gt;\GLOBAL??&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Session-scoped drive-letter map&lt;/td&gt;
&lt;td&gt;The HackSys / CVE-2023-35359 worked example: a low-privilege caller plants a &lt;code&gt;DefineDosDevice&lt;/code&gt; remapping that survives into the impersonation-time &lt;code&gt;\??&lt;/code&gt; view, and the SYSTEM-side activation-context resolver opens the redirected path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\BaseNamedObjects&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The global / &lt;code&gt;Global\&lt;/code&gt;-prefixed-only BNO&lt;/td&gt;
&lt;td&gt;Cross-session named-object visibility&lt;/td&gt;
&lt;td&gt;Pre-Vista squatting class (closed by Generation 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-session subtrees (BNO, DosDevices, WindowStations, AppContainerNamedObjects)&lt;/td&gt;
&lt;td&gt;Session boundary (Generation 2)&lt;/td&gt;
&lt;td&gt;Shatter attacks (closed by Generation 2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Sessions\&amp;lt;n&amp;gt;\AppContainerNamedObjects\&amp;lt;package-sid&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-package UWP / MSIX lowbox namespace&lt;/td&gt;
&lt;td&gt;AppContainer / lowbox boundary (Generation 3)&lt;/td&gt;
&lt;td&gt;Forshaw P0 Issue 1550 arbitrary-directory creation race&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\RPC Control&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every named LRPC ALPC port (every COM call lands here)&lt;/td&gt;
&lt;td&gt;RPC endpoint visibility&lt;/td&gt;
&lt;td&gt;Endpoint squatting against named LRPC ports&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\KnownDlls&lt;/code&gt;, &lt;code&gt;\KnownDlls32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pre-mapped &lt;code&gt;Section&lt;/code&gt; objects for system DLLs&lt;/td&gt;
&lt;td&gt;Loader supply-chain&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DefineDosDevice&lt;/code&gt; + &lt;code&gt;\??&lt;/code&gt; symlink-plant trick (closed in NTDLL July 2022, build 19044.1826)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\KernelObjects&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System-defined events (&lt;code&gt;LowMemoryCondition&lt;/code&gt;, &lt;code&gt;HighMemoryCondition&lt;/code&gt;, etc.)&lt;/td&gt;
&lt;td&gt;Kernel-internal visibility&lt;/td&gt;
&lt;td&gt;None public&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Callback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System-defined &lt;code&gt;Callback&lt;/code&gt; objects (&lt;code&gt;ExCallback&lt;/code&gt; slots drivers register against)&lt;/td&gt;
&lt;td&gt;Kernel API extension surface&lt;/td&gt;
&lt;td&gt;Driver-callback abuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Security&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LSA-private endpoints&lt;/td&gt;
&lt;td&gt;LSA / authentication isolation&lt;/td&gt;
&lt;td&gt;Credential-theft (the LSAISO trustlet via Generation 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Windows&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;BNO-redirect surface and &lt;code&gt;SharedSection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Win32 subsystem shared state&lt;/td&gt;
&lt;td&gt;Cross-session Win32 state leakage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\Silos\&amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-container silo subroots on Server SKUs&lt;/td&gt;
&lt;td&gt;Server Silo boundary (Generation 5)&lt;/td&gt;
&lt;td&gt;Siloscape -- symlink retarget out of the silo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;\BNOLINKS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The boundary-keyed private-namespace index&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CreatePrivateNamespace&lt;/code&gt; cross-session/cross-package IPC&lt;/td&gt;
&lt;td&gt;None public; the directory itself is RE-derived&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart LR
    subgraph EdgeRenderer[&quot;Microsoft Edge Renderer (lowbox token)&quot;]
        K32[&quot;CreateMutexW(L&apos;Global\\Foo&apos;)&quot;]
    end
    K32 --&amp;gt;|&quot;NtCreateMutant, OBJECT_ATTRIBUTES&quot;| OB
    subgraph KernelOb[&quot;ObpLookupObjectName&quot;]
        OB[&quot;Read caller token&lt;br /&gt;token.AppContainerNumber&lt;br /&gt;token.PackageSid&quot;]
        OB --&amp;gt;|&quot;rewrite name&quot;| RW[&quot;Rewrite &apos;\\BaseNamedObjects\\Global\\Foo&apos;&lt;br /&gt;to&lt;br /&gt;&apos;\\Sessions\\1\\AppContainerNamedObjects\\&lt;br /&gt;S-1-15-2-...\\Global\\Foo&apos;&quot;]
        RW --&amp;gt; WALK[&quot;walk the rewritten path&quot;]
    end
    WALK --&amp;gt; Dir[&quot;\\Sessions\\1\\AppContainerNamedObjects\\&lt;br /&gt;S-1-15-2-...\\Global\\&lt;br /&gt;(per-package OBJECT_DIRECTORY,&lt;br /&gt;DACL allows only package SID)&quot;]
&lt;p&gt;The &lt;code&gt;\BNOLINKS&lt;/code&gt; directory deserves a separate paragraph because it is not on Microsoft Learn. &lt;code&gt;NtCreatePrivateNamespace&lt;/code&gt; is the kernel-side syscall behind the Win32 &lt;code&gt;CreatePrivateNamespace&lt;/code&gt; API [@ms-createprivatenamespacew]; the caller passes a boundary descriptor built by &lt;code&gt;CreateBoundaryDescriptor&lt;/code&gt; [@ms-createboundarydescriptorw] plus one or more SIDs added via &lt;code&gt;AddSIDToBoundaryDescriptor&lt;/code&gt; [@ms-addsidtoboundarydescriptor]. The kernel materialises one &lt;code&gt;\BNOLINKS&lt;/code&gt; entry per &lt;code&gt;(alias_prefix, boundary_descriptor_hash)&lt;/code&gt; tuple; two callers that pass the same &lt;code&gt;lpAliasPrefix&lt;/code&gt; but different boundary descriptors land on different directories. The native signature is documented in the PHNT-derived NtDoc mirror [@ntdoc-ntcreateprivatenamespace], and the &lt;code&gt;OBJECT_BOUNDARY_DESCRIPTOR&lt;/code&gt; structure layout is at ntdoc.m417z.com/object_boundary_descriptor [@ntdoc-object-boundary-descriptor]. The Win32 Object Namespaces overview [@ms-object-namespaces] is Microsoft&apos;s only published user-mode reference; the &lt;code&gt;\BNOLINKS&lt;/code&gt; directory name itself is reverse-engineering-derived.The &lt;code&gt;\BNOLINKS&lt;/code&gt; directory is documented only through reverse engineering of &lt;code&gt;ntoskrnl.exe&lt;/code&gt; -- via Forshaw&apos;s NtObjectManager and System Informer&apos;s PHNT headers -- not on Microsoft Learn. The user-mode API surface (&lt;code&gt;CreatePrivateNamespace&lt;/code&gt;, &lt;code&gt;CreateBoundaryDescriptor&lt;/code&gt;, &lt;code&gt;AddSIDToBoundaryDescriptor&lt;/code&gt;) is fully documented. The provenance gap is worth flagging when you cite the directory by name.The &lt;code&gt;\KnownDlls&lt;/code&gt; LPE class was, for a decade, the canonical example of how a DACL plus loader-side validation could lock down a supply-chain anchor. Forshaw&apos;s August 2018 P0 post first sketched a &lt;code&gt;DefineDosDevice&lt;/code&gt; + &lt;code&gt;\??&lt;/code&gt; symlink-plant chain that could land a forged &lt;code&gt;Section&lt;/code&gt; object into &lt;code&gt;\KnownDlls&lt;/code&gt;; Clement Labro (itm4n) implemented the attack as the PPLdump tool and wrote companion posts on both itm4n.github.io [@itm4n-lsass-runasppl] and the SCRT team blog [@blog-scrt-bypassing-lsa-protection-in-userland]. The class was closed in NTDLL by Windows 10 21H2 build 19044.1826; itm4n confirms the patch in &lt;em&gt;The End of PPLdump&lt;/em&gt; [@itm4n-the-end-of-ppldump]: &quot;A patch in NTDLL now prevents PPLs from loading Known DLLs.&quot;&lt;/p&gt;
&lt;p&gt;{`
const MAX_DIRECTORY_BUCKETS = 37;&lt;/p&gt;
&lt;p&gt;function rtlHashUnicodeString(name) {
  let h = 0;
  for (const ch of name.toUpperCase()) {
    h = (h * 31 + ch.charCodeAt(0)) &amp;gt;&amp;gt;&amp;gt; 0;
  }
  return h % MAX_DIRECTORY_BUCKETS;
}&lt;/p&gt;
&lt;p&gt;function makeDir() {
  return { buckets: Array(MAX_DIRECTORY_BUCKETS).fill(null).map(() =&amp;gt; []) };
}&lt;/p&gt;
&lt;p&gt;function addChild(dir, name, child) {
  dir.buckets[rtlHashUnicodeString(name)].push({ name, child });
}&lt;/p&gt;
&lt;p&gt;function lookupObjectName(path, root) {
  const components = path.split(&apos;\\&apos;).filter(Boolean);
  let cursor = root;
  for (const comp of components) {
    const bucket = rtlHashUnicodeString(comp);
    const chain = cursor.buckets[bucket];
    const hit = chain.find(e =&amp;gt; e.name.toUpperCase() === comp.toUpperCase());
    console.log(`lookup &apos;${comp}&apos; -&amp;gt; bucket ${bucket}, chain length ${chain.length}, ${hit ? &apos;HIT&apos; : &apos;MISS&apos;}`);
    if (!hit) return null;
    if (hit.child.parseProcedure) {
      const rest = &apos;\\&apos; + components.slice(components.indexOf(comp) + 1).join(&apos;\\&apos;);
      console.log(`  parse-procedure handoff for type &apos;${hit.child.type}&apos;, residual=&apos;${rest}&apos;`);
      return { handedOff: hit.child, residual: rest };
    }
    cursor = hit.child;
  }
  return cursor;
}&lt;/p&gt;
&lt;p&gt;const root = makeDir();
const device = makeDir();
device.parseProcedure = true; device.type = &apos;Device&apos;;
const sessions = makeDir();
addChild(root, &apos;Device&apos;, device);
addChild(root, &apos;Sessions&apos;, sessions);
addChild(root, &apos;BaseNamedObjects&apos;, makeDir());&lt;/p&gt;
&lt;p&gt;lookupObjectName(&apos;\\Device\\HarddiskVolume1\\Users\\me\\file.txt&apos;, root);
`}&lt;/p&gt;
&lt;p&gt;The walk is the algorithm. The 37 is the bucket count Cutler picked in 1993. The parse-procedure handoff is where the I/O Manager and the Configuration Manager and dozens of other subsystems insert themselves into the tree. Now turn the question around: Windows bet on one tree. What did the kernels that did not bet on one tree do, and why?&lt;/p&gt;
&lt;h2&gt;7. How other kernels name kernel objects&lt;/h2&gt;
&lt;p&gt;Three kernels, three different bets. Linux took the namespace and &lt;em&gt;split it into per-resource-class clones&lt;/em&gt; -- one for mounts, one for PIDs, one for IPC, one for the network stack, one for users, one for hostnames, one for cgroups, one for time -- and never built a unified tree. macOS / Darwin gave each task its own &lt;em&gt;Mach port-right namespace&lt;/em&gt; and let &lt;code&gt;launchd&lt;/code&gt; broker named-service lookups. Plan 9 from Bell Labs was the academic ancestor of &quot;every named OS resource is a filesystem path,&quot; and the design Cutler imported into NT.&lt;/p&gt;
&lt;h3&gt;7.1 Linux: per-resource namespaces&lt;/h3&gt;
&lt;p&gt;Linux ships eight namespace types, each governed by a &lt;code&gt;CLONE_NEW*&lt;/code&gt; flag passed to &lt;code&gt;clone()&lt;/code&gt;, &lt;code&gt;unshare()&lt;/code&gt;, or &lt;code&gt;setns()&lt;/code&gt;: mount, PID, network, IPC, user, UTS, cgroup, and time. The &lt;code&gt;namespaces(7)&lt;/code&gt; man page is precise: &quot;A namespace wraps a global system resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of the global resource&quot; [@man7-namespaces]. Docker, containerd, runc, Kubernetes pods, LXC, and systemd-nspawn all compose these eight flags into a Linux container.&lt;/p&gt;
&lt;p&gt;The strength of the Linux design is per-class composability. A process can be in a fresh mount namespace, a fresh PID namespace, and the host&apos;s network namespace, all at once. The weakness is the absence of a unified type registry: Linux has no equivalent of &lt;code&gt;\ObjectTypes&lt;/code&gt;, no equivalent of the &lt;code&gt;OBJECT_HEADER&lt;/code&gt; reference counting that the kernel applies uniformly to every named object. Each resource class has its own lookup function, its own permission model, and its own ownership story. A bug in any one of them is bounded to that one resource class but is also not shared mitigation across the others.&lt;/p&gt;
&lt;h3&gt;7.2 macOS / Darwin: Mach ports and the bootstrap server&lt;/h3&gt;
&lt;p&gt;Darwin&apos;s kernel-object naming is capability-style. Apple&apos;s archive documentation describes the model directly: &quot;each task consists of a virtual address space, a port right namespace, and one or more threads&quot; [@apple-mach-kernel]. Tasks send messages by holding a &lt;em&gt;port right&lt;/em&gt; -- a per-task index into a kernel-managed table of Mach ports. There is no single hierarchical namespace; ports are sent over Mach messages, and &lt;code&gt;launchd&lt;/code&gt; operates as the bootstrap-server name broker for services that need a stable rendezvous. A separate I/O Registry tree carries device objects.&lt;/p&gt;
&lt;p&gt;The strength of the Mach design is that capabilities cannot be forged; you cannot synthesise a port right out of a string the way you can synthesise a path string under Windows. The weakness is the split namespace: device objects live in the I/O Registry, services live behind &lt;code&gt;launchd&lt;/code&gt;, and the kernel itself has no equivalent of &lt;code&gt;\BaseNamedObjects&lt;/code&gt; as a one-stop shop.&lt;/p&gt;
&lt;h3&gt;7.3 Plan 9 from Bell Labs&lt;/h3&gt;
&lt;p&gt;Plan 9 is the design lineage Cutler imported. In Plan 9, every named operating-system resource -- including processes, network connections, devices, and the window system -- surfaces as a path served over 9P. The single hierarchical namespace was the central claim. Plan 9 never reached commercial scale, but its design idea reached production in three places: NT (1993, via Cutler), Linux&apos;s /proc, /sys, and FUSE (the 1990s onward), and the various capability-OS research projects (KeyKOS, EROS, seL4) that took the lessons in a different direction.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Primitive&lt;/th&gt;
&lt;th&gt;Granularity&lt;/th&gt;
&lt;th&gt;Enforcement point&lt;/th&gt;
&lt;th&gt;Structural / opt-in&lt;/th&gt;
&lt;th&gt;Bypass by privilege&lt;/th&gt;
&lt;th&gt;Inheritance gap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Per-Session (NT)&lt;/td&gt;
&lt;td&gt;Logon session&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ObpLookupObjectName&lt;/code&gt; + DACL&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeDebugPrivilege&lt;/code&gt; short-circuit&lt;/td&gt;
&lt;td&gt;Inherited handles cross sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppContainer Lowbox (NT)&lt;/td&gt;
&lt;td&gt;Package SID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ObpLookupObjectName&lt;/code&gt; rewrite&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;TCB privileges only&lt;/td&gt;
&lt;td&gt;Brokered handles enter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server Silo (NT)&lt;/td&gt;
&lt;td&gt;Container&lt;/td&gt;
&lt;td&gt;Process-&amp;gt;Silo indirection&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;KMCS-signed driver&lt;/td&gt;
&lt;td&gt;Host handles cross silos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VBS / IUM Trustlet (NT)&lt;/td&gt;
&lt;td&gt;Trust level (VTL)&lt;/td&gt;
&lt;td&gt;Hypervisor&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;Hypervisor compromise&lt;/td&gt;
&lt;td&gt;Cross-VTL ALPC only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mandatory Integrity Control (NT)&lt;/td&gt;
&lt;td&gt;IL band&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeAccessCheckByType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opt-in (per-object SACL)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeRelabelPrivilege&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inherited handles bypass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ObRegisterCallbacks&lt;/code&gt; (NT)&lt;/td&gt;
&lt;td&gt;Per-type, per-driver&lt;/td&gt;
&lt;td&gt;Object Manager pre-op callback&lt;/td&gt;
&lt;td&gt;Mediation, not partition&lt;/td&gt;
&lt;td&gt;KMCS-signed driver&lt;/td&gt;
&lt;td&gt;Inheritance bypasses callback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private Namespace (NT)&lt;/td&gt;
&lt;td&gt;Boundary SID-list&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NtCreatePrivateNamespace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;All SIDs in caller&apos;s token&lt;/td&gt;
&lt;td&gt;Boundary-keyed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux Namespace&lt;/td&gt;
&lt;td&gt;Per-resource clone&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setns&lt;/code&gt;/&lt;code&gt;unshare&lt;/code&gt;/&lt;code&gt;clone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structural&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CAP_SYS_ADMIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fork inherits namespace set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mach Port Right&lt;/td&gt;
&lt;td&gt;Per-task&lt;/td&gt;
&lt;td&gt;Capability check on send&lt;/td&gt;
&lt;td&gt;Structural (capabilities)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;host_priv&lt;/code&gt; / kernel&lt;/td&gt;
&lt;td&gt;Inherited rights on fork&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The Object Manager namespace is not a filesystem. There is no disk persistence, no journal, no FAT or MFT, no inode allocator, no per-file DACL in the filesystem sense. Nothing under `\` survives a reboot. Files-on-disk, registry-keys-in-a-hive, and named pipes are leaves in the OM tree, but the actual filesystem implementation lives in NTFS / ReFS / ExFAT drivers reached through the `Device` type&apos;s parse procedure.&lt;p&gt;What the OM namespace &lt;em&gt;shares&lt;/em&gt; with filesystems is exactly three things: the path-walk algorithm (left-to-right, component-by-component, with one hash-table lookup per component), the per-directory hash table (analogous to the directory-entry hash filesystems use), and the per-object security descriptor (which the SRM enforces at the same point a filesystem would enforce its DACL).&lt;/p&gt;
&lt;p&gt;When you read or write the phrase &quot;Object Manager namespace,&quot; the metaphor that is doing real work is &quot;in-memory directory tree the kernel uses to find named objects,&quot; not &quot;filesystem in the disk-format sense.&quot;
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;

The Windows 2000-era `CreateRestrictedToken` primitive was the wrong layer in 2000 as a standalone sandboxing mechanism -- it could not partition the namespace; it only filtered the caller&apos;s SID set against per-object DACLs. Chromium revived it in 2008 as one of four cooperating layers, and that pattern is the canonical 2026 production sandbox shape. The Chromium design document captures the constraints: &quot;The Windows sandbox is a user-mode only sandbox. There are no special kernel mode drivers... The sandbox is provided as a static library that must be linked to both the broker and the target executables&quot; (Chromium Sandbox Design [@chromium-sandbox-md], FAQ [@chromium-sandbox-faq]).&lt;p&gt;The four layers compose pairwise-orthogonally. The token gates &lt;em&gt;which DACLs&lt;/em&gt; the renderer can satisfy at &lt;code&gt;SeAccessCheck&lt;/code&gt; time; the job object gates &lt;em&gt;which kernel API surface&lt;/em&gt; the renderer can call (UI exceptions, process creation, etc.); the integrity level gates &lt;em&gt;which writes&lt;/em&gt; the renderer can perform across MIC label boundaries; the AppContainer lowbox-rewrites &lt;em&gt;every named-object lookup&lt;/em&gt; into the per-package directory inside &lt;code&gt;ObpLookupObjectName&lt;/code&gt;. A handle that survives all four checks is the only object the renderer can usefully touch. The load-bearing header is &lt;code&gt;sandbox_policy.h&lt;/code&gt;, which declares &lt;code&gt;TargetConfig::SetTokenLevel(TokenLevel initial, TokenLevel lockdown)&lt;/code&gt;, &lt;code&gt;SetJobLevel&lt;/code&gt;, &lt;code&gt;SetIntegrityLevel&lt;/code&gt;, &lt;code&gt;SetDelayedIntegrityLevel&lt;/code&gt;, and &lt;code&gt;SetAppContainerSid&lt;/code&gt;, with one verbatim mutual-exclusion note: &quot;Using an initial token is not compatible with AppContainer&quot; [@chromium-sandbox-policy-h].&lt;/p&gt;
&lt;p&gt;This is the 2026 production sandbox shape every Chromium-based browser inherits (Edge, Chrome, Brave, Vivaldi, Opera), as do Electron-based apps like Visual Studio Code&apos;s renderer processes.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;

The cross-VTL ALPC ports through which a VTL0 process talks to a VTL1 trustlet are still located in VTL0&apos;s `\RPC Control`. An attacker who controls VTL0 can *send* messages to LsaIso even though they cannot *read* LsaIso&apos;s internal state. Oliver Lyak&apos;s December 2022 *Pass-the-Challenge* result is the canonical worked example ([GitHub: ly4k/PassTheChallenge](https://github.com/ly4k/PassTheChallenge)): the trustlet&apos;s pages are never read, but the trustlet&apos;s RPC output exfiltrates the secret. The lesson is that VTL1 isolation is a *page-level* read barrier, not a *protocol-level* containment property. The VBS Trustlets piece in this corpus carries the deeper walkthrough.
&lt;p&gt;Windows bet on one tree; Linux bet on eight clone-flag dimensions; Darwin bet on capability-style port-right tables. Each bet has theoretical limits. What are they?&lt;/p&gt;
&lt;h2&gt;8. What the namespace cannot do&lt;/h2&gt;
&lt;p&gt;The frame for this section comes from James P. Anderson&apos;s 1972 USAF technical report &lt;em&gt;Computer Security Technology Planning Study&lt;/em&gt; (ESD-TR-73-51), Section 4.1.1. Anderson is the named originator of the reference-monitor concept and of the four properties such a monitor must satisfy. Wikipedia preserves the modern acronym verbatim: the reference-validation mechanism must be &quot;&lt;strong&gt;N&lt;/strong&gt;on-bypassable... &lt;strong&gt;E&lt;/strong&gt;valuable... &lt;strong&gt;A&lt;/strong&gt;lways invoked... &lt;strong&gt;T&lt;/strong&gt;amper-proof,&quot; and &quot;according to Ross Anderson, the reference monitor concept was introduced by James Anderson in an influential 1972 paper&quot; [@wikipedia-reference-monitor]. The NIST CSRC mirror hosts the original PDF [@csrc-nist-ande72].&lt;/p&gt;
&lt;p&gt;Saltzer and Schroeder&apos;s 1975 paper &lt;em&gt;The Protection of Information in Computer Systems&lt;/em&gt; [@cs-virginia-saltzer-schroeder] added the &lt;em&gt;complete-mediation principle&lt;/em&gt; -- &quot;every access to every object must be checked for authority&quot; -- and seven other design principles the reference-validation mechanism must satisfy (economy of mechanism, fail-safe defaults, open design, separation of privilege, least privilege, least common mechanism, psychological acceptability).&lt;/p&gt;
&lt;p&gt;Map the Windows Object Manager against the four NEAT properties and the answer is uncomfortable. The namespace partially achieves two (Always-invoked and Tamper-proof), fails Non-bypassable outright, and falls one to two orders of magnitude short of Evaluable.&lt;/p&gt;
&lt;h3&gt;8.1 Always-invoked: provably gapped&lt;/h3&gt;
&lt;p&gt;The namespace achieves always-invoked for &lt;em&gt;name-based opens&lt;/em&gt;. Every &lt;code&gt;Nt*OpenObject*&lt;/code&gt; syscall walks &lt;code&gt;ObpLookupObjectName&lt;/code&gt;; there is no path that returns a handle to a named object without going through the lookup. But the namespace cannot achieve always-invoked for &lt;em&gt;handle inheritance&lt;/em&gt;. A child process inherits handles from &lt;code&gt;CreateProcess(bInheritHandles=TRUE)&lt;/code&gt; without going through the OM at all. The handles already exist in the parent&apos;s &lt;code&gt;HANDLE_TABLE&lt;/code&gt;; the kernel walks the parent&apos;s table, duplicates the entries into the child&apos;s table, and the child has live access. No name-lookup, no &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; callback, no SRM check. As long as the OS API exposes handle inheritance -- and it is too deeply embedded in 33 years of shipping Windows code to remove -- the Object Manager cannot be the &lt;em&gt;sole&lt;/em&gt; reference monitor.&lt;/p&gt;
&lt;h3&gt;8.2 Tamper-proof: bounded, not absolute&lt;/h3&gt;
&lt;p&gt;The Object Manager runs in ring 0, under Kernel-Mode Code Signing (KMCS), and -- on machines with Virtualization-Based Security and Hypervisor-protected Code Integrity (HVCI) enabled -- inside a Hyper-V-enforced code-integrity policy. Any kernel-mode adversary who can load a driver bypasses the OM. KMCS and HVCI raise the cost; they do not eliminate the surface. The Bring-Your-Own-Vulnerable-Driver class of attacks (signed but exploitable drivers) is the running residual class, and the historical pattern is that one or two new vulnerable signed drivers surface every quarter.&lt;/p&gt;
&lt;h3&gt;8.3 Evaluable: provably above threshold&lt;/h3&gt;
&lt;p&gt;A small enough TCB can be machine-verified. The seL4 microkernel is the canonical demonstration: roughly 9,000 lines of C verified end-to-end against a formal specification (~11 person-years for initial functional correctness per Klein et al. SOSP 2009, and approximately 25 person-years for the full suite of subsequent proofs including information-flow and binary verification) [@sel4-project]. The Object Manager subsystem, the Security Reference Monitor, and the parse procedures the Object Manager delegates to (file-system drivers via &lt;code&gt;IopParseDevice&lt;/code&gt;; the registry via &lt;code&gt;CmpParseKey&lt;/code&gt;; ALPC; the I/O manager itself) collectively comprise tens of thousands of lines of C, putting the TCB for &quot;open a named object&quot; at one to two orders of magnitude above the verification threshold any current proof system can handle. The Object Manager is &lt;em&gt;not&lt;/em&gt; evaluable in the formal sense Anderson required.&lt;/p&gt;
&lt;h3&gt;8.4 Non-bypassable: the privilege short-circuit&lt;/h3&gt;
&lt;p&gt;A process holding &lt;code&gt;SeDebugPrivilege&lt;/code&gt; (or any privilege that grants &lt;code&gt;PROCESS_VM_*&lt;/code&gt; rights) can short-circuit per-directory ACLs. The privilege evaluation happens at &lt;code&gt;SeAccessCheck&lt;/code&gt; time, &lt;em&gt;after&lt;/em&gt; &lt;code&gt;ObpLookupObjectName&lt;/code&gt; has resolved the name. The Object Manager will resolve any path the privileged caller asks for; the gate fires, but it lets the call through. The namespace cannot defend against the holder of &lt;code&gt;SeDebugPrivilege&lt;/code&gt;. This is by design -- you want a debugger to be able to attach to anything -- but it is also the structural reason why &quot;lock down the namespace&quot; is not by itself a containment story.&lt;/p&gt;
&lt;h3&gt;8.5 What else the namespace cannot do&lt;/h3&gt;
&lt;p&gt;It cannot prevent in-process memory disclosure -- the Pass-the-Challenge limit covered in the Section 7 aside. It cannot defend against a malicious driver -- KMCS, HVCI, and WDAC gate driver load; the namespace itself trusts already-loaded drivers. It cannot eliminate time-of-check / time-of-use racing during a path walk; the walker walks components one at a time, and any reentrant call into the walker is a TOCTOU surface. The mitigation is per-call -- callers pass &lt;code&gt;OBJ_DONT_REPARSE&lt;/code&gt; on object-attributes, &lt;code&gt;FILE_FLAG_OPEN_REPARSE_POINT&lt;/code&gt; on file opens, or otherwise instruct the path-walker to refuse symbolic-link substitution -- not a structural property of the namespace.&lt;/p&gt;
&lt;h3&gt;8.6 The honest accounting&lt;/h3&gt;
&lt;p&gt;The Object Manager namespace is a &lt;em&gt;coordination&lt;/em&gt; mechanism, not a &lt;em&gt;containment&lt;/em&gt; mechanism. Containment is in the layers above: the session ID, the package SID, the integrity level, the silo ID, the VTL split. The namespace&apos;s job is to make those layers &lt;em&gt;enforceable&lt;/em&gt; by partitioning the path space so the bad open &lt;em&gt;cannot resolve to the privileged object&apos;s name&lt;/em&gt;. The layers above decide which partition the caller is in; the namespace&apos;s only job is &quot;given a path and a caller, find the object.&quot; Anderson 1972 names the &lt;em&gt;kernel mechanism&lt;/em&gt; (the reference-validation mechanism with NEAT properties); Saltzer-Schroeder 1975 names the &lt;em&gt;design principles&lt;/em&gt; the mechanism must satisfy. The Object Manager is the Windows realisation; it inherits both the strengths and the limits.&lt;/p&gt;

The namespace is a coordination mechanism, not a containment mechanism. The containment is in the layers above.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Object Manager is the coordination layer; the containment is in the partition primitives stacked on top (session ID, package SID, integrity level, silo ID, VTL). The namespace&apos;s only job is &quot;given a path and a caller, find the object.&quot; Every Windows security boundary is a parameter to that one job: a per-directory ACL, a token-keyed name rewrite, or a kernel callback registered against an &lt;code&gt;OBJECT_TYPE&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The provable gaps are real. What is the active research direction in 2026 -- where do attackers and defenders actually meet inside the namespace today?&lt;/p&gt;
&lt;h2&gt;9. Open problems in 2026&lt;/h2&gt;
&lt;p&gt;Five open problems sit in active research as of 2026.&lt;/p&gt;
&lt;h3&gt;9.1 Hash-bucket collision pressure&lt;/h3&gt;
&lt;p&gt;The 37-bucket constant has not changed since 1993. On a 2026 Windows 11 25H2 machine with several hundred MSIX packages, each owning an &lt;code&gt;\AppContainerNamedObjects\&amp;lt;package-sid&amp;gt;\&lt;/code&gt; subtree, average chain lengths inside &lt;code&gt;\Sessions\1\AppContainerNamedObjects&lt;/code&gt; exceed two and routinely run higher under load. The structural impact is small per-lookup (O(chain length) at each component), but it compounds across deep path walks and across the per-VM hot loops in &lt;code&gt;ObpLookupObjectName&lt;/code&gt;. Microsoft has not committed to a larger table or a different structure; the constant remains.&lt;/p&gt;
&lt;h3&gt;9.2 Cross-AppContainer object-directory privacy&lt;/h3&gt;
&lt;p&gt;Per-AppContainer isolation is the AppContainer model&apos;s promise; residual cross-package reads erode it. Forshaw&apos;s Project Zero work between 2017 and 2020 documents specific classes; Windows 11 25H2 DACLs are tighter than Windows 10 RTM, but the impersonation-mediated cases survive. The HackSys / CVE-2023-35359 family covered in Section 4.5 is the current realisation of the cross-AppContainer-plus-impersonation surface, and the same broader resource-planting taxonomy Forshaw described in the 2017 Named Pipe Secure Prefixes post [@tiraniddo-named-pipe-secure-prefixes] is still rediscovered every year.&lt;/p&gt;
&lt;h3&gt;9.3 Silo-escape via routines that ignore silo attachment&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Siloscape&lt;/em&gt; (June 7, 2021) showed that &lt;code&gt;NtSetInformationSymbolicLink&lt;/code&gt; could retarget a silo-scoped symbolic link at a host-scoped path. Microsoft patched the specific function; the &lt;em&gt;class&lt;/em&gt; -- kernel routines whose path resolution does not honour &lt;code&gt;Process-&amp;gt;Silo-&amp;gt;RootDirectory&lt;/code&gt; -- remains open. Microsoft&apos;s long-standing position is that Server Silo is not a security boundary; Hyper-V Container is the security-boundary product. Container runtimes that depend on Server Silo for tenant isolation are knowingly running outside the supported boundary.&lt;/p&gt;
&lt;h3&gt;9.4 ObRegisterCallbacks erosion under HVCI&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ObRegisterCallbacks&lt;/code&gt; requires a KMCS-signed driver, and on HVCI-enabled machines the binary must additionally be HVCI-compatible. Microsoft has progressively raised the compatibility bar -- preventing unsigned drivers, banning common runtime-patching idioms, and tightening the W^X policy. EDR vendors depend on the surface staying open; if HVCI&apos;s compatibility bar ever excludes the EDR kernel driver pattern, the in-kernel callback layer is at risk. The CrowdStrike Falcon Sensor outage of July 2024 made the brittleness of in-kernel EDR a public conversation. Microsoft&apos;s &lt;em&gt;Defender for Endpoint&lt;/em&gt; and &lt;em&gt;EDR-on-Linux eBPF&lt;/em&gt; projects point at alternative-mediation futures, but in-kernel &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; is still the primary credential-theft sensor.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As attackers ship Hell&apos;s Gate / Halo&apos;s Gate / direct-syscall stubs to bypass userland EDR hooks, the kernel callback fires regardless. The arms race accordingly shifts to the &lt;em&gt;access-mask-strip vs. impersonate-trusted-parent-PID&lt;/em&gt; layer inside the kernel callback itself, with both sides racing to define the right pre-operation policy for &lt;code&gt;lsass.exe&lt;/code&gt; handle opens. Watch the Microsoft Security Response Center advisories and the EDR-vendor incident postmortems for the bleeding edge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;9.5 Public benchmark vacuum&lt;/h3&gt;
&lt;p&gt;No peer-reviewed benchmark compares per-call namespace-lookup cost across the Windows Object Manager, Linux namespaces, and Mach ports. Choice of namespace design at the OS level is a multi-decade commitment; the absence of an empirical comparison forces architecture decisions on theoretical-only grounds. The Linux Kernel Test Robot, the Phoronix Test Suite, and various academic systems-conference benchmarks measure adjacent properties (filesystem-call latency, system-call vector cost), but none publishes head-to-head numbers on the named-object-lookup hot path. This is an open invitation to systems researchers.&lt;/p&gt;
&lt;p&gt;Five open problems is a research agenda, not a how-to. How do you actually look at this thing on your own machine?&lt;/p&gt;
&lt;h2&gt;10. Reading the namespace from a live system&lt;/h2&gt;
&lt;p&gt;Three tools cover the operational practice: Sysinternals WinObj, Forshaw&apos;s NtObjectManager PowerShell module, and WinDbg in kernel mode.&lt;/p&gt;
&lt;h3&gt;10.1 WinObj on a live system&lt;/h3&gt;
&lt;p&gt;Download &lt;code&gt;winobj.exe&lt;/code&gt; from Sysinternals [@ms-winobj] and run it as administrator. The left pane is the directory tree; the right pane shows the children of the selected directory with their object types. Navigate to &lt;code&gt;\Sessions\1\BaseNamedObjects&lt;/code&gt; and read off the named events and mutants every Win32 app in your interactive session has created. Navigate to &lt;code&gt;\Sessions\1\AppContainerNamedObjects&lt;/code&gt; and pick an &lt;code&gt;S-1-15-2-...&lt;/code&gt; directory; right-click, choose Properties, and read the security descriptor. You will see a single allow-ACE granting full access only to the package SID itself. That ACE is the entire AppContainer sandbox at the namespace layer.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; WinObj cannot traverse &lt;code&gt;\ObjectTypes&lt;/code&gt;, &lt;code&gt;\Security&lt;/code&gt;, or &lt;code&gt;\Sessions\0\&lt;/code&gt; without administrator rights. Without traversal, the enumerate fails silently and the tree looks empty. Always run elevated, and accept that the tool will show the kernel view, not a per-process view.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;10.2 NtObjectManager PowerShell&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;NtObjectManager&lt;/code&gt; is Forshaw&apos;s PowerShell module that exposes the Object Manager namespace through cmdlets (PowerShell Gallery [@powershellgallery-ntobjectmanager]; GitHub [@p0-sandbox-attacksurface-analysis-tools]). Install with &lt;code&gt;Install-Module NtObjectManager&lt;/code&gt;. Useful commands: &lt;code&gt;Get-ChildItem NtObject:\&lt;/code&gt; walks the root; &lt;code&gt;Get-NtType&lt;/code&gt; lists the registered &lt;code&gt;OBJECT_TYPE&lt;/code&gt; singletons; &lt;code&gt;Get-NtObject \BaseNamedObjects&lt;/code&gt; enumerates the global BNO; &lt;code&gt;Get-NtAlpcPort &apos;\RPC Control&apos;&lt;/code&gt; lists every LRPC endpoint on the machine. The module wraps the same NTDLL syscalls WinObj uses, but in a scripting surface that composes into automation.&lt;/p&gt;
&lt;h3&gt;10.3 WinDbg kernel session&lt;/h3&gt;
&lt;p&gt;In a kernel-mode WinDbg session attached to a target machine (or to a live local kernel via Microsoft&apos;s local-kernel debug mode), &lt;code&gt;!object \&lt;/code&gt; dumps the root directory and its children. &lt;code&gt;dt nt!_OBJECT_HEADER &amp;lt;addr&amp;gt;-30&lt;/code&gt; reads the header preceding any object&apos;s body (the offset 0x30 is the size of &lt;code&gt;OBJECT_HEADER&lt;/code&gt; on x64; subtract that from the body pointer to land on the header -- the field layout is documented in &lt;em&gt;Windows Internals 7th Edition* Chapter 8, Microsoft Press Store [@microsoftpressstore-wininternals7-part1]). `dx -r1 ((nt!_OBJECT_TYPE&lt;/em&gt;)nt!PsProcessType[0]).TypeInfo` walks the Process type&apos;s method table and lists all eight procedure pointers and the WaitObjectFlagOffset, including the parse procedure.&lt;/p&gt;
&lt;h3&gt;10.4 The EDR primitive: an ObRegisterCallbacks driver template&lt;/h3&gt;
&lt;p&gt;The minimal sketch of an in-kernel EDR sensor is four steps. Register an &lt;code&gt;OB_CALLBACK_REGISTRATION&lt;/code&gt; for &lt;code&gt;PsProcessType&lt;/code&gt; with &lt;code&gt;OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE&lt;/code&gt; [@ms-obregistercallbacks]. In the pre-operation callback, examine &lt;code&gt;OperationInformation-&amp;gt;Object&lt;/code&gt;, derive the target process&apos;s PID, and compare it against &lt;code&gt;lsass.exe&lt;/code&gt;. If it matches, strip credential-relevant access bits from &lt;code&gt;OperationInformation-&amp;gt;Parameters-&amp;gt;CreateHandleInformation.DesiredAccess&lt;/code&gt; (or duplicate-handle equivalent). The kernel grants the handle with the reduced rights, the attacker&apos;s &lt;code&gt;PROCESS_VM_READ&lt;/code&gt; is gone before the call returns, and the post-operation callback logs the attempt. The parallel API &lt;code&gt;PsSetCreateProcessNotifyRoutineEx&lt;/code&gt; [@ms-pssetcreateprocessnotifyroutineex] covers process creation, which is the other half of the EDR sensor surface.&lt;/p&gt;

sequenceDiagram
    participant A as Attacker process
    participant NT as nt!NtOpenProcess
    participant OM as Object Manager
    participant EDR as EDR Pre-Op Callback
    participant LSASS as lsass.exe (target)
    A-&amp;gt;&amp;gt;NT: NtOpenProcess(lsass PID, PROCESS_VM_READ | PROCESS_QUERY_INFORMATION)
    NT-&amp;gt;&amp;gt;OM: lookup PsProcessType, target by PID
    OM-&amp;gt;&amp;gt;EDR: fire pre-op callback (handle create)
    EDR-&amp;gt;&amp;gt;EDR: target == lsass.exe?
    EDR-&amp;gt;&amp;gt;EDR: strip PROCESS_VM_READ from DesiredAccess
    EDR--&amp;gt;&amp;gt;OM: granted = PROCESS_QUERY_LIMITED_INFORMATION
    OM--&amp;gt;&amp;gt;NT: HANDLE with reduced access
    NT--&amp;gt;&amp;gt;A: open succeeded (but useless rights)
&lt;p&gt;{`
const PROCESS_VM_READ                   = 0x0010;
const PROCESS_VM_WRITE                  = 0x0020;
const PROCESS_VM_OPERATION              = 0x0008;
const PROCESS_QUERY_INFORMATION         = 0x0400;
const PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
const PROCESS_CREATE_THREAD             = 0x0002;
const PROCESS_DUP_HANDLE                = 0x0040;&lt;/p&gt;
&lt;p&gt;function stripForLsass(desired) {
  const STRIPPED =
      PROCESS_VM_READ |
      PROCESS_VM_WRITE |
      PROCESS_VM_OPERATION |
      PROCESS_CREATE_THREAD |
      PROCESS_DUP_HANDLE |
      PROCESS_QUERY_INFORMATION;
  return desired &amp;amp; ~STRIPPED;
}&lt;/p&gt;
&lt;p&gt;const desired = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE;
console.log(&apos;attacker asked for:&apos;, &apos;0x&apos; + desired.toString(16));
const granted = stripForLsass(desired) | PROCESS_QUERY_LIMITED_INFORMATION;
console.log(&apos;EDR pre-op granted:&apos;, &apos;0x&apos; + granted.toString(16));
`}&lt;/p&gt;

```c
OB_OPERATION_REGISTRATION op = {
    .ObjectType = PsProcessType,
    .Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
    .PreOperation = MyPreOp,
    .PostOperation = MyPostOp,
};
OB_CALLBACK_REGISTRATION reg = {
    .Version = OB_FLT_REGISTRATION_VERSION,
    .OperationRegistrationCount = 1,
    .Altitude = RTL_CONSTANT_STRING(L&quot;123456&quot;),
    .OperationRegistration = &amp;amp;op,
};
ObRegisterCallbacks(®, &amp;amp;g_handle);
```
The driver must be KMCS-signed (`IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY`) per the wdm.h documentation; an unsigned image returns `STATUS_ACCESS_DENIED` from `ObRegisterCallbacks`. Two drivers cannot pick the same Altitude; collisions return `STATUS_FLT_INSTANCE_ALTITUDE_COLLISION`.
&lt;p&gt;You can now read the namespace, register an EDR-style callback, and dump the type registry. What are the questions readers ask after they finish reading?&lt;/p&gt;
&lt;h2&gt;11. Frequently asked questions&lt;/h2&gt;


No. The registry is a separate Windows Executive subsystem implemented in `nt!Cm*`, with its own hive on-disk format and its own in-memory hive structures. It hooks into the Object Manager namespace through one and only one mechanism: the `Key` `OBJECT_TYPE` registers a `ParseProcedure` (`CmpParseKey`) that takes over path walking when the namespace walker reaches `\REGISTRY`. The registry is therefore a *consumer* of the Object Manager, but not part of the Object Manager.

Because `\BaseNamedObjects` is the *global* / `Global\`-prefixed-only view, distinct from the per-session BNO at `\Sessions\\BaseNamedObjects`. The Win32 `Local\` prefix routes through `kernel32!BaseGetNamedObjectDirectory` into the per-session BNO; `Global\` routes into the global one [@ms-termserv-kernel-object-namespaces]. Cross-session named-object coordination still needs the global view; per-session isolation lives in the per-session subtree.

Because the lowbox token attached to the UWP app&apos;s process tells `ObpLookupObjectName` to rewrite the path to `\Sessions\\AppContainerNamedObjects\\Global\Foo` before path walking. Two different UWP apps have two different package SIDs and therefore land on two different directories. The Win32 names look the same; the kernel resolves them to different objects.

`\??\C:` is the per-session DosDevices alias; if `C:` is not defined in the current session&apos;s `\??`, the walker falls through to `\GLOBAL??\C:`. `\GLOBAL??\C:` is the machine-wide DosDevices symbolic link to `\Device\HarddiskVolume*` -- the real on-disk volume object. The split matters because the per-session `\??` is where per-session drive-letter remappings (`net use X: \\server\share`, `subst Z: C:\foo`, `DefineDosDevice`) live, and the activation-context resolver class covered in Section 4.5 is the exploit family that lives at this boundary.

Several top-level directories have `Directory`-`TRAVERSE` ACLs that restrict to SYSTEM and the local Administrators group. Without traversal, the directory enumeration silently fails. `\ObjectTypes`, `\Security`, and `\Sessions\0\` are the directories users most often notice as &quot;missing&quot; when running unelevated.

By DACL plus loader-side validation. The directory grants `Directory`-`READ` to everyone but `Directory`-`WRITE` only to SYSTEM and TrustedInstaller. The `Section` objects inside are Authenticode-signed by Microsoft and validated at boot by `smss.exe`. The historical `DefineDosDevice` + `\??` symlink-plant bypass class survived until Windows 10 21H2 build 19044.1826 (July 2022), when an NTDLL patch closed it [@itm4n-the-end-of-ppldump].

`ObRegisterCallbacks` [@ms-obregistercallbacks] and `PsSetCreateProcessNotifyRoutineEx` [@ms-pssetcreateprocessnotifyroutineex] are both fully documented. The HVCI compatibility requirements, the KMCS attestation flow, and the exact policy interactions with Defender for Endpoint&apos;s tamper-protection layer are partly implementation-defined; EDR vendor engineering teams maintain private regression suites against successive Windows feature updates.

When two or more processes that don&apos;t share a session or package must coordinate over a securable directory keyed by a SID-list they agree on at design time. The boundary descriptor is the *agreement primitive*: the kernel requires every SID in the boundary to be in the caller&apos;s token. The namespace&apos;s `OBJECT_DIRECTORY` lives in `\BNOLINKS`, keyed by the alias-prefix string plus a hash of the boundary descriptor&apos;s SID-list (CreatePrivateNamespaceW [@ms-createprivatenamespacew]; Object Namespaces overview [@ms-object-namespaces]; native NtCreatePrivateNamespace [@ntdoc-ntcreateprivatenamespace] and OBJECT_BOUNDARY_DESCRIPTOR [@ntdoc-object-boundary-descriptor] signatures). From inside an AppContainer process the lookup is rewritten into the per-package subtree, so private namespaces are not a substitute for the `windows.applicationModel.*` brokered APIs when cross-package coordination is the goal.


A user-mode structure produced by `CreateBoundaryDescriptor` and populated with `AddSIDToBoundaryDescriptor` (plus the optional `CREATE_BOUNDARY_DESCRIPTOR_ADD_APPCONTAINER_SID` flag). Conceptually the descriptor is a SID-list that the caller and every other participant must share via their tokens. Kernel-side the structure is `OBJECT_BOUNDARY_DESCRIPTOR` (Version, Items, TotalSize, Flags). `NtCreatePrivateNamespace` materialises a directory in `\BNOLINKS` keyed by the `lpAliasPrefix` plus a hash of the boundary descriptor&apos;s SIDs.
&lt;h2&gt;12. Coming back to the WinObj screen&lt;/h2&gt;
&lt;p&gt;Open WinObj one more time. Navigate back to &lt;code&gt;\Sessions\1\AppContainerNamedObjects&lt;/code&gt; and pick the Edge renderer&apos;s &lt;code&gt;S-1-15-2-...&lt;/code&gt; directory. You can now name everything you are looking at. The directory is an &lt;code&gt;_OBJECT_DIRECTORY&lt;/code&gt; instance with 37 hash buckets. You reach it through a token-keyed rewrite that the kernel applies inside &lt;code&gt;ObpLookupObjectName&lt;/code&gt; before path walking begins. Its security descriptor grants &lt;code&gt;GenericAll&lt;/code&gt; only to the package SID. Every EDR loaded on this machine has registered an &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; filter on &lt;code&gt;PsProcessType&lt;/code&gt;, watching for handle creations against &lt;code&gt;lsass.exe&lt;/code&gt;. If you are running on a Server SKU with Windows Server Containers, the directory might also be silo-scoped, with &lt;code&gt;Process-&amp;gt;Silo-&amp;gt;RootDirectory&lt;/code&gt; indirecting your view of the rest of &lt;code&gt;\&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The four pieces of the 1993 Cutler design have shipped without architectural change for thirty-three years. The six generations of partition primitives stacked on top are all simultaneously load-bearing on Windows 11 25H2. The namespace itself is a coordination mechanism, in Anderson 1972&apos;s sense of the reference-validation mechanism, with Saltzer-Schroeder 1975&apos;s complete-mediation principle as the design constraint it must satisfy. Containment lives in the partition layers above it: the session, the package, the integrity level, the silo, and the VTL split. Every other article in this corpus -- the Credential Guard piece, the AppContainer piece, the VBS Trustlets piece, the Hyper-V piece, the App Identity piece, the TPM piece -- quietly assumes this tree underneath them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every Windows security boundary is a path rewrite, a per-directory ACL, a token-keyed name substitution, or a kernel callback against an &lt;code&gt;OBJECT_TYPE&lt;/code&gt;. The Object Manager is the data structure underneath them all.&lt;/p&gt;
&lt;/blockquote&gt;

**Key terms.** Object Manager (`Ob`), `OBJECT_HEADER`, `OBJECT_TYPE`, `ParseProcedure`, `OBJECT_DIRECTORY`, Lowbox token, AppContainer, Server Silo, Trustlet / IUM, Boundary descriptor, Session 0 isolation, Mandatory Integrity Control, `ObRegisterCallbacks`, KMCS, HVCI, `\BaseNamedObjects`, `\Sessions\\AppContainerNamedObjects`, `\RPC Control`, `\KnownDlls`, `\BNOLINKS`, `\GLOBAL??`, `\??`.&lt;p&gt;&lt;strong&gt;Review questions.&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Why does AppContainer isolation work even when the calling UWP app explicitly asks for &lt;code&gt;Global\X&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;What is the relationship between &lt;code&gt;IopParseDevice&lt;/code&gt;, &lt;code&gt;\Device\HarddiskVolume1&lt;/code&gt;, and &lt;code&gt;IRP_MJ_CREATE&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Which of Anderson 1972&apos;s four NEAT properties does the Object Manager achieve cleanly, and which does it provably fail?&lt;/li&gt;
&lt;li&gt;Why is &lt;code&gt;ObRegisterCallbacks&lt;/code&gt; an enforcement gate only against handle creation and duplication, not against handle use?&lt;/li&gt;
&lt;li&gt;Why does the canonical MS15-090 OM-symlink CVE point at CVE-2015-2428 [@nvd-cve-2015-2428] rather than CVE-2015-2528 or CVE-2015-1463?&lt;/li&gt;
&lt;li&gt;What is the structural difference between &lt;code&gt;\??\C:&lt;/code&gt; and &lt;code&gt;\GLOBAL??\C:&lt;/code&gt;, and which one does the HackSys / CVE-2023-35359 worked example abuse?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Recommended reading.&lt;/strong&gt; Russinovich, Ionescu, and Solomon, &lt;em&gt;Windows Internals, Part 1&lt;/em&gt; (7th edition, Microsoft Press, 2017), Chapter 8 [@microsoftpressstore-wininternals7-part1]. James Forshaw, &lt;em&gt;Windows Security Internals&lt;/em&gt; (No Starch Press, 2024), Chapter 8 [@nostarch-windows-security-internals]. Alex Ionescu, &lt;em&gt;Battle of SKM and IUM&lt;/em&gt;, Black Hat USA 2015 [@ionescu-bh2015-pdf]. The Google Project Zero blog&apos;s symlink mitigations [@p0-symlink-mitigations], arbitrary directory creation [@p0-issue1550], and who contains the containers [@p0-who-contains-containers] posts. James P. Anderson, &lt;em&gt;Computer Security Technology Planning Study&lt;/em&gt; [@csrc-nist-ande72].
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
</content:encoded><category>windows-internals</category><category>object-manager</category><category>kernel</category><category>sandbox</category><category>appcontainer</category><category>security-boundaries</category><category>edr</category><category>vbs</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Above Ring Zero: How the Windows Hypervisor Became a Security Primitive</title><link>https://paragmali.com/blog/above-ring-zero-how-the-windows-hypervisor-became-a-security/</link><guid isPermaLink="true">https://paragmali.com/blog/above-ring-zero-how-the-windows-hypervisor-became-a-security/</guid><description>A deep tour of the Windows hypervisor as the substrate of VBS, HVCI, Credential Guard, and Secure Launch -- its five primitives, the boundary it commits to, and the public failures that calibrate it.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>
**The Windows hypervisor is the program that loaded before Windows did.** It runs at a privilege level the Windows kernel cannot reach and owns the page tables that decide which memory the Windows kernel may even see. Virtualization-Based Security, Credential Guard, HVCI (Memory Integrity in Windows Security), Application Control, VBS Enclaves, and System Guard Secure Launch are all built by composing five primitives the hypervisor exposes -- partitions, hypercalls, intercepts, SynIC, and per-VTL SLAT. The substrate is real, alive, and producing two to four public CVEs per year; the residual attack surface (firmware below, side channels above, IOMMU bypass beside, hypervisor rollback) is where Windows security still earns its hardest miles.
&lt;h2&gt;1. Above Ring Zero&lt;/h2&gt;
&lt;p&gt;On a Windows 11 machine with VBS turned on, a kernel-mode driver running with full Ring-0 privilege cannot read a single byte of the LSASS process&apos;s credential cache. It cannot load an unsigned driver. It cannot patch &lt;code&gt;ntoskrnl.exe&lt;/code&gt;. It cannot disable HVCI without a reboot. None of this is enforced by Windows. It is enforced by a different program -- one that loaded before Windows did, that runs at a privilege level the Windows kernel cannot reach, and that owns the page tables that say which memory the Windows kernel may even &lt;em&gt;see&lt;/em&gt;. That program is the Windows hypervisor [@ms-hyperv-architecture, @ms-tlfs-vsm].&lt;/p&gt;
&lt;p&gt;The intuition this fact violates is older than most readers&apos; careers. &quot;SYSTEM owns the box.&quot; Every introductory security course teaches it. Local administrator escalates to SYSTEM, SYSTEM loads a driver, the driver runs in the kernel, and the kernel can do anything to the machine. That model is correct for a Windows installation running without Virtualization-Based Security. It is wrong, in three specific and load-bearing ways, for a Windows installation that has VBS turned on.&lt;/p&gt;

A Windows security architecture that uses the Hyper-V hypervisor to create a small, isolated execution environment alongside the normal Windows operating system. The hypervisor allocates a portion of memory, configures its second-level page tables to make that memory unreadable and unwritable from normal kernel mode, and runs Microsoft-signed code there -- the Secure Kernel and isolated user-mode trustlets -- that the regular NT kernel cannot reach. Credential Guard, HVCI, Application Control, and System Guard all sit on top of this primitive [@ms-tlfs-vsm].
&lt;p&gt;The binary in question is named &lt;code&gt;hvix64.exe&lt;/code&gt; on Intel hosts and &lt;code&gt;hvax64.exe&lt;/code&gt; on AMD hosts.Loose security writing sometimes calls the hypervisor&apos;s privilege level &quot;Ring -1.&quot; That phrase is colloquial. Intel&apos;s manuals say &quot;VMX root operation&quot;; AMD&apos;s manuals say &quot;SVM host mode.&quot; Both terms denote a CPU operating mode that sits architecturally outside the four-ring privilege stack the guest OS sees, not a fifth ring inside it. It is loaded by &lt;code&gt;hvloader.efi&lt;/code&gt; before &lt;code&gt;winload.exe&lt;/code&gt; ever runs. By the time the Windows boot manager hands control to the NT kernel, the hypervisor has already configured the CPU&apos;s virtualization extensions, allocated its own private memory, taken ownership of the IOMMU, and set up the per-partition second-level page tables that decide which physical pages each partition can see [@ms-tlfs-pdf]. From the NT kernel&apos;s point of view, the machine starts up already inside a guest partition. There is no escape upward.&lt;/p&gt;
&lt;p&gt;This article is about the program that loaded first. The siblings in this series -- on the &lt;a href=&quot;https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel&lt;/a&gt;, on &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;Credential Guard and NTLMless&lt;/a&gt;, on &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;, and on &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Adminless&lt;/a&gt; -- all assume what this article explains. Each of them describes a policy: the Secure Kernel enforces code integrity; Credential Guard isolates LSASS; Adminless raises the bar on local administrator. None of those policies would be enforceable without a piece of software running at a privilege level the policy&apos;s adversary cannot reach. The hypervisor is that piece of software, and &quot;security primitive&quot; is how Microsoft, the security research community, and the bug-bounty market all describe its current role.&lt;/p&gt;
&lt;p&gt;By the end of this article you will know five things. First, &lt;em&gt;why&lt;/em&gt; the hypervisor became a security primitive -- the architectural failure of Ring-0 defenses that Microsoft fought for a decade and finally gave up on in 2015. Second, &lt;em&gt;how&lt;/em&gt; it became one, in three steps: Popek and Goldberg&apos;s 1974 virtualizability theorem; Intel VT-x and AMD-V in 2005-2006; and David Hepkin and Arun Kishan&apos;s 2013 patent on hierarchical Virtual Trust Levels [@us9430642b2-patent]. Third, &lt;em&gt;what&lt;/em&gt; it enforces, feature by feature, with the hypervisor primitive that backs each: HVCI rides on per-VTL SLAT; Credential Guard rides on SynIC plus the secure-call ABI; System Guard Secure Launch rides on DRTM [@ms-system-guard-secure-launch]. Fourth, &lt;em&gt;where&lt;/em&gt; it has actually failed in public -- six worked CVEs across three distinct attack classes, all narrowly localized. Fifth, &lt;em&gt;what&lt;/em&gt; is structurally outside its mandate: firmware below the hypervisor, microarchitectural side channels above it, IOMMU bypass beside it, and hypervisor rollback through the update pipeline.&lt;/p&gt;
&lt;p&gt;The story is half engineering and half conceptual inversion. How did a server-consolidation hypervisor that shipped in 2008 with &lt;code&gt;Windows Server 2008&lt;/code&gt; -- a product whose original marketing pitch was &quot;run more VMs per box&quot; -- become the architectural substrate that protects every load-bearing Windows security boundary in 2026? The answer begins in 1974, with a paper that defined what a hypervisor even &lt;em&gt;is&lt;/em&gt;. But the political and engineering thread begins five years before that, in San Mateo, California.&lt;/p&gt;
&lt;h2&gt;2. Origins -- Connectix to Viridian to Hyper-V&lt;/h2&gt;
&lt;p&gt;Microsoft entered the virtualization market three years late and by acquisition. On February 19, 2003, the company bought Connectix, a small San Mateo software house founded in 1988 that had built Virtual PC for Macintosh and, later, Virtual PC for Windows. The Connectix engineers became the nucleus of what Microsoft would internally call the Windows Server Virtualization team. The acquired products shipped as Microsoft Virtual PC 2004 and Microsoft Virtual Server 2005. Both were Type-2 hypervisors -- user-mode applications that ran on top of Windows, using software techniques rather than CPU virtualization extensions, because the CPU virtualization extensions did not yet exist on shipping x86 hardware.&lt;/p&gt;

A hypervisor that runs directly on hardware rather than as an application on top of a host operating system. The hypervisor owns the CPU, the second-level page tables, and (in the security-relevant case) the IOMMU; guest operating systems run at a lower privilege level, in partitions or virtual machines that the hypervisor schedules and isolates. IBM&apos;s CP-67/CMS in 1968 is the genre&apos;s origin; VMware ESX, Xen, and the Microsoft hypervisor (`hvix64.exe`/`hvax64.exe`) are the modern examples [@wp-hypervisor].
&lt;p&gt;In 2005, the team began a new project under the codename &quot;Viridian.&quot; The goal was a Type-1 micro-kernelized hypervisor for x86-64 -- a fresh build, not a derivative of Virtual Server -- that required hardware virtualization extensions at install time. Intel&apos;s VT-x had shipped in November 2005 with the Pentium 4 662/672; AMD-V had shipped on May 23, 2006 with the Socket AM2 platform, initially available across Athlon 64 X2 and Athlon 64 FX and select Athlon 64 models. Both were now broadly enough deployed that Microsoft could make hardware virtualization a system requirement rather than a configuration option. Three years later, on June 26, 2008 (Wikipedia&apos;s body text gives this date; the infobox states June 28), Hyper-V reached RTM and was delivered as a Windows Server 2008 feature through Windows Update [@wp-hyperv].Microsoft ships two hypervisor binaries: &lt;code&gt;hvix64.exe&lt;/code&gt; for Intel hosts (using VT-x) and &lt;code&gt;hvax64.exe&lt;/code&gt; for AMD hosts (using AMD-V). The instruction-set-architecture divergence is real -- Intel uses &lt;code&gt;vmcall&lt;/code&gt; to enter the hypervisor; AMD uses &lt;code&gt;vmmcall&lt;/code&gt; -- but the hypercall ABI surface above that single instruction is identical, so the rest of the Microsoft hypervisor codebase is shared between the two binaries.&lt;/p&gt;
&lt;p&gt;The 2008 design choices are worth naming individually because the ones that mattered for &lt;em&gt;server consolidation&lt;/em&gt; turned out, twelve years later, to also be the ones that mattered for &lt;em&gt;security&lt;/em&gt;. Three deserve flagging:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Micro-kernelized architecture.&lt;/strong&gt; The hypervisor binary contains only the minimum machinery needed to virtualize the CPU, schedule VMs, and enforce memory isolation. It does not contain device drivers. It does not contain a network stack. It does not contain a filesystem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Root partition plus child partitions.&lt;/strong&gt; From the Microsoft architecture documentation: &quot;&lt;em&gt;The Microsoft hypervisor must have at least one parent, or root, partition, running Windows. The virtualization management stack runs in the parent partition and has direct access to hardware devices. The root partition then creates the child partitions which host the guest operating systems&lt;/em&gt;&quot; [@ms-hyperv-architecture]. The root partition is a full Windows install; the child partitions are guest VMs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VMBus, VSP, and VSC.&lt;/strong&gt; Inter-partition I/O happens over the VMBus -- a paravirtualized message channel. A Virtualization Service Provider (VSP) runs in the root partition and owns the real device; a Virtualization Service Client (VSC) runs in each child partition and talks to the VSP over VMBus. Device emulation lives in the root partition&apos;s user-mode and kernel-mode code, &lt;em&gt;not in the hypervisor binary itself&lt;/em&gt;. This is the choice that, twelve years later, kept the hypervisor&apos;s Trusted Computing Base small enough to be defensible.&lt;/li&gt;
&lt;/ul&gt;

flowchart TD
    subgraph Root[&quot;Root partition (Windows Server)&quot;]
        RD[&quot;Real device drivers&quot;]
        VSP[&quot;Virtualization Service Providers&quot;]
        VMM[&quot;VM Worker Processes (vmwp.exe)&quot;]
    end
    subgraph Child1[&quot;Child partition 1 (guest OS)&quot;]
        VSC1[&quot;Virtualization Service Clients&quot;]
        Guest1[&quot;Guest kernel + apps&quot;]
    end
    subgraph Child2[&quot;Child partition 2 (guest OS)&quot;]
        VSC2[&quot;Virtualization Service Clients&quot;]
        Guest2[&quot;Guest kernel + apps&quot;]
    end
    HV[&quot;Microsoft Hypervisor (hvix64.exe / hvax64.exe)&quot;]
    HW[&quot;Hardware (CPU, RAM, NIC, disk)&quot;]
    Root -. VMBus .- Child1
    Root -. VMBus .- Child2
    Root --&amp;gt; HV
    Child1 --&amp;gt; HV
    Child2 --&amp;gt; HV
    HV --&amp;gt; HW
&lt;p&gt;The micro-kernel, root-plus-child, and VMBus choices were defensible &lt;em&gt;server&lt;/em&gt; engineering. Their server engineering rationale was that emulating a NIC, or a SCSI controller, or a graphics adapter inside a hypervisor binary would balloon the binary&apos;s size, lock its code-review cycles to those of every device the company shipped, and force the same security-critical code that scheduled CPUs to also handle Ethernet frame parsing. Putting device emulation in a normal Windows process inside the root partition -- the VM Worker Process &lt;code&gt;vmwp.exe&lt;/code&gt; -- meant the hypervisor binary could stay small enough to reason about.&lt;/p&gt;
&lt;p&gt;The 2008 design goal was, again, server consolidation. Microsoft&apos;s positioning materials at the time named &quot;run more VMs per box, get better hardware use&quot; as the customer pitch. Nothing in the 2008 Hyper-V documentation describes the hypervisor as a security primitive for the host OS. The security re-purposing -- the moment Hyper-V&apos;s hardware-privilege isolation became the way Windows itself protected its own kernel from itself -- did not arrive until 2015. To understand why it arrived at all, we have to back up thirty-four years to a 1974 paper that defined what virtualization formally requires.&lt;/p&gt;
&lt;h2&gt;3. The Theoretical Anchor -- Popek, Goldberg, and SLAT&lt;/h2&gt;
&lt;p&gt;Before Microsoft could build a hypervisor that ran security-critical code at a higher privilege than the Windows kernel, two unrelated decisions had to land. One was made in 1974, by two researchers who would never see Windows. The other was made in 2005, by Intel.&lt;/p&gt;
&lt;p&gt;In July 1974, Gerald Popek of UCLA and Robert Goldberg of Harvard published &quot;Formal Requirements for Virtualizable Third Generation Architectures&quot; in &lt;em&gt;Communications of the ACM&lt;/em&gt;. The paper laid down three properties any &quot;true&quot; virtual machine monitor must satisfy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Equivalence.&lt;/strong&gt; Programs run on the VMM exhibit behavior essentially identical to behavior on the bare machine, except for differences due to timing and resource availability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource control.&lt;/strong&gt; The VMM, not the guest, controls the system resources -- CPU time slices, memory, devices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efficiency.&lt;/strong&gt; A statistically dominant subset of the instruction stream executes directly on hardware, without VMM intervention.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The theorem that gave the paper its lasting reputation followed from those properties. Let a &lt;em&gt;sensitive instruction&lt;/em&gt; be one that either reads or modifies privileged state (the processor&apos;s mode bits, page-table base register, interrupt mask). Let a &lt;em&gt;privileged instruction&lt;/em&gt; be one that traps when executed in user mode. Then a sufficient condition for an ISA to be virtualizable is that every sensitive instruction is privileged. The intuition is simple: the VMM must get a chance to see -- and to handle -- every guest action that touches the machine&apos;s privileged state. If the CPU silently lets the guest do something privileged-feeling without trapping, the VMM cannot maintain equivalence and control simultaneously.&lt;/p&gt;

A property of a processor architecture: every sensitive instruction in the instruction set is privileged. An architecture with this property can be virtualized &quot;classically&quot; -- with a thin trap-and-emulate hypervisor whose only entry points are the traps the CPU raises on privileged-instruction violations. An architecture without this property requires software workarounds (binary translation, paravirtualization) or hardware extensions (VT-x, AMD-V) before a Popek-Goldberg-style VMM can be built.
&lt;p&gt;For three decades, x86 was famously &lt;em&gt;not&lt;/em&gt; virtualizable in the Popek-Goldberg sense. John Robin and Cynthia Irvine enumerated the problem in their 2000 USENIX Security paper: seventeen protected-mode instructions on the IA-32 architecture either read or modified privileged state without trapping from user mode.The Robin and Irvine enumeration includes instructions like &lt;code&gt;SGDT&lt;/code&gt; (store global descriptor table register), &lt;code&gt;SIDT&lt;/code&gt; (store interrupt descriptor table register), &lt;code&gt;SLDT&lt;/code&gt; (store local descriptor table register), &lt;code&gt;SMSW&lt;/code&gt; (store machine status word), and &lt;code&gt;PUSHF/POPF&lt;/code&gt; (push/pop flags including IOPL). Each of these silently returned or accepted privileged state from user mode without raising a fault. The aggregate effect was that no classical Popek-Goldberg VMM could correctly virtualize an unmodified x86 guest -- every one of those seventeen instructions was a hole the VMM could not see through. VMware Workstation, released in 1999 by VMware Inc. (which had been founded the year prior by Mendel Rosenblum, Diane Greene, Scott Devine, Ellen Wang, and Edouard Bugnion), worked around the problem with &lt;em&gt;binary translation&lt;/em&gt;: it dynamically rewrote each protected-mode guest instruction stream to substitute or trap the seventeen offenders. The technique imposed double-digit overhead, made debugging miserable, and was a security liability in its own right -- the binary translator itself was a parser of arbitrary attacker-controlled code.&lt;/p&gt;
&lt;p&gt;Intel and AMD ended the problem in hardware. Intel VT-x (codename Vanderpool, November 2005) and AMD-V (codename Pacifica, May 2006) added a new CPU mode -- &lt;em&gt;VMX root operation&lt;/em&gt; for Intel, &lt;em&gt;SVM host mode&lt;/em&gt; for AMD -- and a new instruction-emulation mechanism. A &lt;em&gt;VM exit&lt;/em&gt; could be configured to fire on every sensitive instruction the hypervisor wished to intercept, transferring control to the host with a structured exit reason and an opaque, host-controlled snapshot of guest state. After 2006, x86-64 became Popek-Goldberg-virtualizable in hardware [@wp-x86-virtualization].&lt;/p&gt;

sequenceDiagram
    participant Guest as Guest OS (VMX non-root)
    participant CPU as CPU hardware
    participant HV as Hypervisor (VMX root)
    Guest-&amp;gt;&amp;gt;CPU: MOV CR3, rax  (sensitive instr)
    CPU-&amp;gt;&amp;gt;HV: VM-EXIT (reason 28: CR access)
    HV-&amp;gt;&amp;gt;HV: Read VMCS exit-qualification
    HV-&amp;gt;&amp;gt;HV: Validate, emulate, update SLAT
    HV-&amp;gt;&amp;gt;CPU: VMRESUME
    CPU-&amp;gt;&amp;gt;Guest: Continue guest at next instruction
&lt;p&gt;One architectural element more was needed before any of this could be a &lt;em&gt;security&lt;/em&gt; primitive rather than just a virtualization primitive. Classical x86 paging maps a guest virtual address to a physical address through a single CPU-walked page table. In a virtualized system that single table cannot be enough, because the guest needs its own virtual-to-physical map and the host needs to remap the guest&apos;s &quot;physical&quot; address to a real machine-physical address. The first generations of VT-x simulated this two-level mapping in software through &lt;em&gt;shadow page tables&lt;/em&gt;, which the hypervisor had to maintain alongside the guest&apos;s tables on every page-table edit. Shadow paging was correct but slow, and it gave the hypervisor no clean way to enforce a &lt;em&gt;different&lt;/em&gt; memory map for different parts of the same guest.&lt;/p&gt;
&lt;p&gt;Second-Level Address Translation (SLAT) -- Intel&apos;s Extended Page Tables (EPT, shipped with Nehalem in November 2008) and AMD&apos;s Nested Page Tables (NPT, shipped with the Barcelona-generation Opteron on September 10, 2007) -- solved both problems in hardware. The guest walks its own page table from virtual to &quot;guest physical&quot;; the CPU then walks a second, hypervisor-owned page table from &quot;guest physical&quot; to &quot;system physical.&quot; Two key properties follow. First, the hypervisor has exclusive control of the second-level mapping; the guest cannot read, write, or even know that it exists. Second, because the second-level mapping is per-partition, the hypervisor can give two partitions different views of the same machine physical memory -- the same page can be readable in one partition and entirely absent in another.&lt;/p&gt;

A hardware feature on Intel (EPT) and AMD (NPT) CPUs that lets the hypervisor maintain a second page table mapping guest-physical addresses to system-physical addresses. The CPU walks the guest&apos;s own page table for the virtual-to-guest-physical mapping, then walks the hypervisor&apos;s table for the guest-physical-to-system-physical mapping. Because the second table is hypervisor-controlled and per-partition, the hypervisor can give different partitions -- and, in VBS, different Virtual Trust Levels inside the same partition -- different views of physical memory. SLAT is the bedrock of VTL memory protection [@ms-tlfs-pdf].
&lt;p&gt;Hyper-V required VT-x or AMD-V at install time from day one. SLAT became mandatory with Windows Server 2016 and Windows 10 1607 [@ms-hyperv-architecture].&lt;/p&gt;
&lt;p&gt;Popek and Goldberg gave us the property. Intel and AMD gave us the hardware. Microsoft used both to build a server hypervisor in 2008. But for the first seven years of Hyper-V&apos;s life, none of that machinery protected Windows from itself. Microsoft hadn&apos;t yet noticed the architectural problem that made it necessary -- or rather, they had noticed the problem (PatchGuard&apos;s bypass record was public) and had not yet conceded that the problem was structural. The concession came in 2015. What forced it was the same-privilege paradox.&lt;/p&gt;
&lt;h2&gt;4. The Same-Privilege Paradox -- Why PatchGuard Was Never Enough&lt;/h2&gt;
&lt;p&gt;PatchGuard, which Microsoft shipped in 2005 with Windows Server 2003 SP1 x64, ran inside &lt;code&gt;ntoskrnl.exe&lt;/code&gt; at Ring 0 and scanned a curated list of kernel structures -- the system service dispatch table, the interrupt descriptor table, the kernel image&apos;s &lt;code&gt;.text&lt;/code&gt; section -- at randomized intervals to detect tampering. It was bypassed within months by Skywing&apos;s &lt;em&gt;Uninformed&lt;/em&gt; writeups. Microsoft kept shipping it. Researchers kept bypassing it. The pattern lasted a decade. The reason is not that PatchGuard&apos;s authors were sloppy [@wp-kpp]. The reason is structural, and naming it correctly is the first of the three insights this article is built around.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Any defense reachable by &lt;code&gt;mov&lt;/code&gt; from Ring 0 is defeasible by &lt;code&gt;mov&lt;/code&gt; from Ring 0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The intuition is simple. PatchGuard is a piece of code. It lives in the kernel&apos;s virtual address space at some page. It owns a timer that re-runs it periodically. It maintains a randomization seed for which structures it checks next. It has a callback path into &lt;code&gt;KeBugCheckEx&lt;/code&gt; if it detects tampering. Every one of those four assets -- the code page, the timer callback, the randomization seed, the bug-check path -- is a kernel data structure or a kernel virtual address. An attacker with Ring-0 code execution can locate each of them by searching the same kernel address space PatchGuard searches. They can patch the callback so the timer no-ops. They can patch the seed so the randomization is predictable. They can patch the bug-check path so it reports success. They can do all of this with a sequence of plain &lt;code&gt;mov&lt;/code&gt; instructions. PatchGuard cannot defend against this, because PatchGuard&apos;s defenses live in the same place its attacker&apos;s writes do.&lt;/p&gt;

PatchGuard and its attacker are colleagues, not adversaries. They share an office. The office is `ntoskrnl.exe`&apos;s virtual address space, and there is no key on the door.
&lt;p&gt;This is the &lt;em&gt;same-privilege paradox&lt;/em&gt;. It is not an implementation bug. It does not yield to better obfuscation, more randomization, or harder-to-find timers. It is an architectural ceiling. A defense at privilege level $P$ cannot be enforced against an attacker who also runs at privilege level $P$, because the defender&apos;s state lives in the attacker&apos;s address space. The defender can be made &lt;em&gt;expensive&lt;/em&gt; to find; it cannot be made impossible to find, because the attacker has the same instructions, the same address-space view, and the same MMU privileges as the defender.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The same-privilege paradox is a property of where the defense &lt;em&gt;lives&lt;/em&gt;, not of how clever the defense is. PatchGuard&apos;s authors did add randomization. They did add multiple decoy callbacks. They did add cryptographically derived integrity checks. None of those reductions changes the basic fact that the attacker, holding the same Ring-0 privilege, can locate and edit each of them. The architectural fix is not better PatchGuard. The architectural fix is moving the defender to a privilege level the attacker cannot reach.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the paradox is named, the defender&apos;s choice is binary. Either give up on having a defense at all -- treat Ring 0 as a free-fire zone where any malware that gets there has won -- or move the defender to a privilege level &lt;em&gt;above&lt;/em&gt; Ring 0, at a hardware boundary the attacker&apos;s &lt;code&gt;mov&lt;/code&gt; instructions cannot cross. Microsoft picked the second. It is the only architecturally honest choice.&lt;/p&gt;
&lt;p&gt;To make it work, Microsoft needed three things. The first was a hypervisor already deployed on every Windows install. They had that since 2008. The second was a way to put a piece of Windows itself -- code, data, secrets -- &lt;em&gt;inside&lt;/em&gt; the hypervisor&apos;s protection without spawning a separate VM, because spawning a separate VM doubles the system&apos;s resource cost and forces every Windows process to choose between living on the normal side or the secure side. That required an architectural idea that did not yet exist in 2010: a way to split a single partition into two privilege levels, each with its own SLAT mapping and its own register state. The third was a way to ensure the hypervisor itself could not be silently replaced or rolled back beneath the OS. That required a hardware-rooted measurement -- a DRTM event -- that the OS could attest to.&lt;/p&gt;
&lt;p&gt;The architectural idea is the subject of section 6. The DRTM measurement is the subject of section 11. Both of them required a decade-long conversation about whether the &lt;em&gt;hypervisor itself&lt;/em&gt; could be trusted at all -- a conversation that ran in parallel during the same years and that briefly seemed to argue the opposite case. We turn to that conversation next.&lt;/p&gt;
&lt;h2&gt;5. The Hyperjacking Era -- SubVirt, Blue Pill, and CloudBurst&lt;/h2&gt;
&lt;p&gt;While Microsoft was finishing Hyper-V, the security community was establishing that a hypervisor was not just a defense -- it was also the most powerful possible attacker against the OS sitting above it. Three demonstrations in three years made the point unmistakable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SubVirt.&lt;/strong&gt; In May 2006, Samuel King and Peter Chen at the University of Michigan, joined by Yi-Min Wang, Chad Verbowski, Helen Wang, and Jacob Lorch at Microsoft Research, presented &quot;SubVirt: Implementing Malware with Virtual Machines&quot; at IEEE S&amp;amp;P [@king-subvirt-2006]. Their construction was a &lt;em&gt;Virtual Machine Based Rootkit&lt;/em&gt; (VMBR). A privileged installer running inside a legitimate OS installed a malicious VMM at boot time; on the next reboot, the malicious VMM ran first, brought up the original OS as a guest underneath it, and gained the privileged position of seeing every CPU instruction, every memory access, and every I/O the OS performed. The original OS had no architectural way to tell it was no longer the most-privileged software on the box. SubVirt was demonstrated against Windows XP (using Microsoft Virtual PC as the malicious VMM substrate) and against Linux (using VMware Workstation), specifically to show that the technique was not tied to any one operating system or any one hypervisor product.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blue Pill.&lt;/strong&gt; Three months later, at Black Hat USA 2006, Joanna Rutkowska of COSEINC demonstrated &quot;Subverting Vista Kernel for Fun and Profit&quot; [@wp-blue-pill]. Her tool, codenamed &lt;em&gt;Blue Pill&lt;/em&gt;, took a step beyond SubVirt by doing the VMM insertion at &lt;em&gt;runtime&lt;/em&gt; rather than at boot. The technique: a Ring-0 driver, running inside an already-booted Windows install on an AMD-V capable host, executed &lt;code&gt;VMRUN&lt;/code&gt; against an attacker-controlled Virtual Machine Control Block (VMCB) whose initial state matched the current physical CPU. The CPU dropped out of SVM root mode and re-entered as a guest under the attacker&apos;s VMM. The OS continued running normally, with no boot-loader modification and no reboot.&lt;/p&gt;
&lt;p&gt;By 2007, Rutkowska and Alexander Tereshkin returned to Black Hat USA with the more polished &quot;IsGameOver(,) Anyone?&quot; presentation, refining the technique and addressing the early critics&apos; detection ideas [@wp-blue-pill].Rutkowska&apos;s marketing claim that Blue Pill was &quot;100% undetectable&quot; attracted a public counter-effort: in 2007, Edgar Barbosa, Nate Lawson, Peter Ferrie, and Tom Ptacek all proposed detection techniques relying on side channels (timing artifacts of trapped instructions, TSC skew, structural differences in how &lt;code&gt;RDTSC&lt;/code&gt; behaves under VT-x). The claim softened in subsequent publications, but the underlying point survived: a hostile thin hypervisor below a victim OS can be made arbitrarily difficult to detect from inside that OS, and the only architecturally clean way to know what you are running under is to measure the boot chain before the OS starts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CloudBurst.&lt;/strong&gt; At Black Hat USA 2009, Kostya Kortchinsky of Immunity Inc. presented CLOUDBURST. It was the first publicly demonstrated arbitrary-code-execution guest-to-host escape against a commercial hypervisor: a heap overflow in VMware&apos;s emulated SVGA-II graphics adapter, tracked as CVE-2009-1244 [@nvd-cve-2009-1244]. A guest VM, executing entirely inside a VMware-managed user-mode process on the host, could overflow a buffer in that process and gain host code execution. CloudBurst&apos;s lasting operational lesson was not the specific bug but the &lt;em&gt;attack surface&lt;/em&gt;: device emulation -- not the trap-and-emulate core of the hypervisor -- is the largest piece of guest-attacker-controlled code in any commercial VMM. Every Hyper-V guest-to-host escape Microsoft has shipped a patch for since 2018 lands in either this device-emulation surface or the hypercall input-validation surface that mediates the same kinds of structured guest-controlled input.&lt;/p&gt;

flowchart TD
    subgraph Before[&quot;Before hyperjacking&quot;]
        OS1[&quot;Victim OS&quot;]
        FW1[&quot;Firmware (UEFI)&quot;]
        HW1[&quot;Hardware&quot;]
        OS1 --&amp;gt; FW1
        FW1 --&amp;gt; HW1
    end
    subgraph After[&quot;After hyperjacking&quot;]
        OS2[&quot;Victim OS (now a guest)&quot;]
        VMM[&quot;Hostile VMM (SubVirt / Blue Pill)&quot;]
        FW2[&quot;Firmware (UEFI)&quot;]
        HW2[&quot;Hardware&quot;]
        OS2 --&amp;gt; VMM
        VMM --&amp;gt; FW2
        FW2 --&amp;gt; HW2
    end
&lt;p&gt;The three demonstrations established a difficult dual truth. The hypervisor is the most powerful defender against an OS-level attacker, &lt;em&gt;and&lt;/em&gt; it is the most powerful attacker against an OS-level defender. The same primitive can play either role; which role it plays in any given system depends only on &lt;em&gt;whose&lt;/em&gt; hypervisor it is and whether the OS above it can prove that. SubVirt-style attacks did not require Microsoft to invent anything new -- they only had to be a possibility -- to force Microsoft into a design constraint: any &quot;hypervisor as security primitive&quot; architecture has to start by being &lt;em&gt;the only&lt;/em&gt; hypervisor on the box, with a measurement of the hypervisor binary recorded in a &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM platform configuration register&lt;/a&gt; so that any malicious VMBR underneath could be detected at attestation time. This is the role that System Guard Secure Launch (DRTM) plays in the architecture, and we will return to it in section 11.&lt;/p&gt;

Blue Pill (offense) and VBS (defense) are architecturally identical. Each is a thin Type-1 hypervisor that interposes between firmware and OS. Each owns the CPU&apos;s virtualization mode, the second-level page tables, and the IOMMU. Each is invisible to the OS unless the OS can prove what is underneath it. The only differences between them are whose hypervisor it is, whether it was measured at load time, and what it does with its privilege. The defense is the offense, run by the right people, in the right order, and attested to.
&lt;p&gt;By 2010 the security community had agreed: the hypervisor is the most powerful primitive in the system, and whoever owns the SLAT page tables owns the box. Joanna Rutkowska&apos;s Invisible Things Lab launched Qubes OS, an explicitly hypervisor-rooted security OS, on April 7, 2010 [@qubes-introducing-2010]. Microsoft owned the SLAT page tables. They had a hypervisor on every Windows install. They had a server-consolidation product. What they did not yet have was a &lt;em&gt;reason&lt;/em&gt; to re-purpose any of it for security. The reason was already being filed at the United States Patent and Trademark Office. The priority date was September 17, 2013.&lt;/p&gt;
&lt;h2&gt;6. The Pivot -- VSM, VTLs, and the Hepkin-Kishan Patent&lt;/h2&gt;
&lt;p&gt;On September 17, 2013, David Hepkin and Arun Kishan filed United States patent application 14/186,415, which would issue on August 30, 2016 as US Patent 9,430,642 B2 [@us9430642b2-patent]. The patent&apos;s title, &quot;Providing virtual secure mode with different virtual trust levels,&quot; reads like marketing now because the words it introduced -- &quot;Virtual Trust Level,&quot; &quot;VTL,&quot; &quot;Virtual Secure Mode&quot; -- became Microsoft&apos;s own canonical terminology. In 2013 the words did not exist. The patent describes, in 2013, exactly what Microsoft shipped twenty-two months later in Windows 10 build 10240 [@ms-tlfs-vsm].&lt;/p&gt;
&lt;p&gt;The patent&apos;s claim language is unusually specific. It teaches a virtual-machine manager that makes &quot;&lt;em&gt;multiple different virtual trust levels available to virtual processors of a virtual machine&lt;/em&gt;&quot;; it teaches that &quot;&lt;em&gt;different memory access protections (such as the ability to read, write, and/or execute memory) can be associated with different portions of memory (e.g., memory pages) for each virtual trust level&lt;/em&gt;&quot;; and it teaches that &quot;&lt;em&gt;the virtual trust levels are organized as a hierarchy with a higher level virtual trust level being more privileged than a lower virtual trust level.&lt;/em&gt;&quot; Each of those phrases is now a feature of the shipping Microsoft hypervisor.&lt;/p&gt;

A hypervisor-managed privilege level inside a single partition. Each VTL has its own SLAT mapping (so the same machine page can be readable in one VTL and absent in another), its own virtual-processor register state (so a VTL transition is a context switch, not a procedure call), and its own interrupt subsystem (so interrupts targeted at one VTL do not preempt code running in another). VTLs are hierarchical: a higher VTL can read all of a lower VTL&apos;s memory, but not vice versa. The shipping Microsoft hypervisor implements two VTLs (VTL0 = Normal world, VTL1 = Secure world); the architecture admits up to sixteen [@ms-tlfs-vsm].
&lt;p&gt;Windows 10 RTM on July 29, 2015, and Windows Server 2016, shipped VBS atop the &lt;em&gt;existing&lt;/em&gt; Hyper-V hypervisor [@wp-windows-10]. The architectural innovation -- the thing the patent was for -- was that VTL0 (Normal world, containing the NT kernel, user mode, and LSASS) and VTL1 (Secure world, containing the Secure Kernel and Isolated User Mode trustlets) ran &lt;em&gt;inside the same partition&lt;/em&gt; rather than in two separate partitions. VBS is not a second VM. It is a per-VTL SLAT split inside the root partition, plus a per-VTL register-state snapshot, plus a per-VTL interrupt delivery surface. The hypervisor switches SLAT contexts on VTL transitions, exactly as it would switch SLAT contexts on a partition switch -- but the switch happens inside a single partition&apos;s address space, so there is no extra VM scheduling and no extra OS image to manage.&lt;/p&gt;

flowchart TD
    subgraph Root[&quot;Root partition&quot;]
        subgraph VTL0[&quot;VTL0 -- Normal world&quot;]
            NT[&quot;NT kernel (ntoskrnl.exe)&quot;]
            User[&quot;User mode (lsass.exe, applications)&quot;]
        end
        subgraph VTL1[&quot;VTL1 -- Secure world&quot;]
            SK[&quot;Secure Kernel (securekernel.exe)&quot;]
            IUM[&quot;Isolated User Mode trustlets&quot;]
            LSAISO[&quot;LSAISO.EXE&quot;]
            VTPM[&quot;vTPM trustlet&quot;]
            IUM --- LSAISO
            IUM --- VTPM
        end
    end
    HV[&quot;Microsoft Hypervisor (hvix64 / hvax64)&quot;]
    HW[&quot;Hardware (CPU, RAM, IOMMU, TPM)&quot;]
    VTL0 -. &quot;Secure call (hypercall + SynIC)&quot; .-&amp;gt; VTL1
    VTL1 --&amp;gt; HV
    VTL0 --&amp;gt; HV
    HV --&amp;gt; HW
&lt;p&gt;The Hyper-V Top-Level Functional Specification, chapter 15, names the architectural facts verbatim. &quot;&lt;em&gt;VSM achieves and maintains isolation through Virtual Trust Levels (VTLs). VTLs are enabled and managed on both a per-partition and per-virtual processor basis.&lt;/em&gt;&quot; &quot;&lt;em&gt;Virtual Trust Levels are hierarchical, with higher levels being more privileged than lower levels.&lt;/em&gt;&quot; &quot;&lt;em&gt;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.&lt;/em&gt;&quot; The C-level definition &lt;code&gt;#define HV_NUM_VTLS 2&lt;/code&gt; is published in the same specification [@ms-tlfs-vsm]. Two VTLs are what ships; the architecture has room for more.&lt;/p&gt;

VSM enables operating system software in the root and guest partitions to create isolated regions of memory for storage and processing of system security assets. Access to these isolated regions is controlled and granted solely through the hypervisor, which is a highly privileged, highly trusted part of the system&apos;s Trusted Compute Base (TCB). -- Microsoft, *Hyper-V Top-Level Functional Specification*, chapter 15 [@ms-tlfs-vsm]
&lt;p&gt;This is the second insight the article is built around: VBS is not a re-architecture. It is a re-purposing. The hypervisor was already on every Windows install for unrelated reasons. The 2015 pivot did not require new hardware, new VMs, or new CPUs. It required a new way to &lt;em&gt;organize&lt;/em&gt; what was already there -- two SLAT mappings instead of one, two register snapshots instead of one, a secure-call ABI on top of the SynIC -- and a Windows-side Secure Kernel binary to run inside the new VTL1 view. The patent gave the design its formal expression; the engineering had been waiting since 2008 for the right architectural insight.David Hepkin spent over a decade on the NT kernel architecture team before the VSM design; Arun Kishan was an NT kernel architect and is now Microsoft&apos;s Corporate Vice President for the Operating Systems Platform group. Neither is a virtualization specialist by background. Their patent is, in retrospect, a kernel-team idea about how to put a piece of the kernel itself behind a hardware boundary the kernel cannot cross -- exactly the kind of design that an architect who had lived inside &lt;code&gt;ntoskrnl.exe&lt;/code&gt; for years would invent.&lt;/p&gt;
&lt;p&gt;Alex Ionescu&apos;s Black Hat USA 2015 deck &quot;Battle of SKM and IUM: How Windows 10 Rewrites OS Architecture&quot; reverse-engineered the entire VSM stack within four weeks of Windows 10 RTM [@ionescu-bh-2015]. The vocabulary Ionescu introduced has become the canonical research language for talking about VBS: VTL as &quot;synthetic ring level managed by the hypervisor&quot;; &lt;em&gt;trustlets&lt;/em&gt; for the user-mode processes that run inside VTL1&apos;s Isolated User Mode; Signature Level 12 plus the IUM EKU &lt;code&gt;1.3.6.1.4.1.311.10.3.37&lt;/code&gt; as the loader&apos;s signing requirement. Microsoft&apos;s own developer documentation now uses the same terms [@ms-iso-user-mode-trustlets].&lt;/p&gt;
&lt;p&gt;The pivot, then, was not a sudden re-architecture. It was the cash-out of a deliberate multi-year engineering plan that began at least twenty-two months before Windows 10 RTM. To see what VBS actually enforces -- and which hypervisor primitive backs each piece of that enforcement -- we need to walk the hypervisor&apos;s public surface. There are five surfaces. They are the architectural body of the article.&lt;/p&gt;
&lt;h2&gt;7. Architecture Tour -- The Hypervisor&apos;s Public Surface&lt;/h2&gt;
&lt;p&gt;What does the Windows hypervisor actually look like as a piece of software? It is a small kernel, on the order of one to two hundred thousand lines of C and C++ by community estimate; Microsoft has not published a primary line count. It has five externally visible surfaces, all of which are documented in the Hyper-V Top-Level Functional Specification (TLFS) v6.0b [@ms-tlfs-pdf]. We walk them in turn.&lt;/p&gt;
&lt;h3&gt;7.1 Partitions, VMBus, and the VSP/VSC pair&lt;/h3&gt;
&lt;p&gt;A &lt;em&gt;partition&lt;/em&gt; is the hypervisor&apos;s unit of isolation. From the Microsoft architecture page: &quot;&lt;em&gt;The Microsoft hypervisor must have at least one parent, or root, partition, running Windows. The virtualization management stack runs in the parent partition and has direct access to hardware devices. The root partition then creates the child partitions which host the guest operating systems&lt;/em&gt;&quot; [@ms-hyperv-architecture]. The root partition is a full Windows install with privileged hypercalls and direct access to hardware; each child partition is a guest VM with only the hardware the root has chosen to expose.&lt;/p&gt;
&lt;p&gt;A guest VM does I/O over the VMBus. A network packet, for example, travels from the guest application down to the guest&apos;s Windows NDIS stack; through the synthetic NIC miniport driver (the VSC) in the guest&apos;s kernel; over the VMBus message channel; into the network VSP in the root partition; into the root&apos;s real NDIS stack; into the physical NIC driver; out the wire. The hypervisor&apos;s role in this chain is structural: it owns the VMBus message channel, the SynIC interrupts that notify the VSP and VSC of new traffic, and the per-partition SLAT mappings that decide which bytes either side can read.&lt;/p&gt;
&lt;p&gt;The architectural implication is that &lt;em&gt;device emulation lives in the root partition, not in the hypervisor binary&lt;/em&gt;. The TCB the hypervisor binary itself has to protect is narrow. The TCB the root partition&apos;s drivers have to protect is much wider -- but those drivers live in normal Windows kernel mode, where Microsoft has thirty years of tooling. This is why almost every public Hyper-V CVE since 2018 has landed in &lt;code&gt;vmswitch.sys&lt;/code&gt;, &lt;code&gt;storvsp.sys&lt;/code&gt;, or the NT Kernel Integration VSP, rather than in &lt;code&gt;hvix64.exe&lt;/code&gt; itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Putting device emulation in the root partition means the hypervisor binary does not need to parse Ethernet frames, SCSI commands, USB descriptors, or graphics-adapter command rings. The trade-off is that the root partition becomes part of the TCB -- a root-partition kernel-mode bug is a hypervisor-equivalent break -- but the small hypervisor binary itself can be reviewed, fuzzed, and reasoned about as a single piece of code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;7.2 The hypercall ABI&lt;/h3&gt;
&lt;p&gt;Hypercalls are how partitions request services from the hypervisor. The TLFS documents two flavors. A &lt;em&gt;fast&lt;/em&gt; hypercall passes its parameters inline in CPU registers: on x64, &lt;code&gt;rcx&lt;/code&gt; carries a 64-bit hypercall input value (the low 16 bits are the call code; the upper 48 bits are a control word with fields for the Fast flag, variable-header size, Rep Count, and Rep Start Index), &lt;code&gt;rdx&lt;/code&gt; carries the first input parameter, and &lt;code&gt;r8&lt;/code&gt; carries the second. A &lt;em&gt;slow&lt;/em&gt; hypercall instead passes the GPA (guest physical address) of an input-parameter page in &lt;code&gt;rdx&lt;/code&gt;, and the GPA of an output-parameter page in &lt;code&gt;r8&lt;/code&gt;; the actual parameter content lives in those pages. The instruction that triggers the hypercall is &lt;code&gt;vmcall&lt;/code&gt; on Intel and &lt;code&gt;vmmcall&lt;/code&gt; on AMD; the hypervisor maps both onto the same internal entry point [@ms-tlfs-pdf].&lt;/p&gt;

A guest-to-hypervisor call. The guest issues `vmcall` (Intel) or `vmmcall` (AMD); the CPU traps via VM-EXIT into the hypervisor in VMX root mode; the hypervisor reads the call code from `rcx`, reads the inputs from registers (fast) or from a GPA-pointed page (slow), services the request, writes outputs back, and returns via VM-ENTRY. Hypercalls are the only legitimate way for a partition to invoke hypervisor services [@ms-tlfs-pdf].
&lt;p&gt;{&lt;code&gt;// A JavaScript model of the rcx hypercall input value layout. // In a real hypercall the guest sets rcx, rdx, r8 and issues vmcall / vmmcall. function packHypercallInput({ callCode, fastFlag, varHeaderSize, isNested, repCount, repStartIdx }) {   // rcx layout (TLFS section 3 &quot;Hypercall Interface&quot;, verbatim bit map)   //   bits  0..15  Call Code   //   bit      16  Fast (1 = inline params in rdx/r8)   //   bits 17..26  Variable header size (in QWORDs)   //   bits 27..30  RsvdZ   //   bit      31  Is Nested   //   bits 32..43  Rep Count   //   bits 44..47  RsvdZ   //   bits 48..59  Rep Start Index   //   bits 60..63  RsvdZ   let rcx = 0n;   rcx |= BigInt(callCode) &amp;amp; 0xFFFFn;   if (fastFlag) rcx |= 1n &amp;lt;&amp;lt; 16n;   rcx |= (BigInt(varHeaderSize) &amp;amp; 0x3FFn) &amp;lt;&amp;lt; 17n;   if (isNested) rcx |= 1n &amp;lt;&amp;lt; 31n;   rcx |= (BigInt(repCount) &amp;amp; 0xFFFn) &amp;lt;&amp;lt; 32n;   rcx |= (BigInt(repStartIdx) &amp;amp; 0xFFFn) &amp;lt;&amp;lt; 48n;   return rcx; } // HvCallPostMessage = 0x005C, fast hypercall (TLFS section 11) const rcx = packHypercallInput({   callCode: 0x005C,   fastFlag: 1,   varHeaderSize: 0,   isNested: 0,   repCount: 0,   repStartIdx: 0, }); console.log(&apos;rcx = 0x&apos; + rcx.toString(16).padStart(16, &apos;0&apos;)); // Output: rcx = 0x000000000001005c&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;The call-code space is small and well-documented: a few hundred codes, each one a structured request with typed inputs and outputs. The hypercall path is also where the most consequential 2024 Hyper-V CVE lived. CVE-2024-21407 was a use-after-free in &lt;code&gt;hvix64.exe&lt;/code&gt;&apos;s handling of a specific file-operation hypercall, the rare case where the bug was in the hypervisor binary itself rather than in a root-partition driver [@nvd-cve-2024-21407].&lt;/p&gt;
&lt;h3&gt;7.3 Intercepts&lt;/h3&gt;
&lt;p&gt;Intercepts are how the hypervisor virtualizes guest behavior. The TLFS distinguishes four categories: &lt;em&gt;instruction&lt;/em&gt; intercepts (&lt;code&gt;CPUID&lt;/code&gt;, MSR reads/writes, I/O-port instructions), &lt;em&gt;exception&lt;/em&gt; intercepts (page faults, general protection faults), &lt;em&gt;memory-access&lt;/em&gt; intercepts (a guest tries to read or write a specific guest-physical-address region), and &lt;em&gt;partition-state&lt;/em&gt; intercepts (a guest hits a state that the hypervisor wants to be notified about). Each is configured per-partition through the Intel VMCS execution-control bits or the AMD VMCB control fields [@ms-tlfs-pdf].&lt;/p&gt;

A configurable hypervisor notification on a specific guest event. The hypervisor programs the VMCS or VMCB to fire a VM-EXIT when the guest issues a particular instruction, raises a particular exception, accesses a particular memory region, or transitions to a particular state. Intercepts are the policy mechanism that lets the hypervisor implement device emulation, security checks, and VTL transitions [@ms-tlfs-pdf].
&lt;p&gt;For VBS, the load-bearing intercept is the memory-access intercept. When VTL0 code tries to access a region whose VTL0 SLAT mapping is unreadable or unwritable, the access traps to the hypervisor with the offending GPA; the hypervisor can deliver the intercept to the VTL1 Secure Kernel as a &lt;em&gt;secure call&lt;/em&gt;, letting VTL1 see what VTL0 was trying to do and decide whether to allow it. This is how HVCI&apos;s W^X enforcement is wired: a VTL0 page that is marked writable in VTL0&apos;s SLAT is marked non-executable in the same SLAT; an attempt to switch the same page to executable becomes a memory-access intercept that VTL1 must approve.&lt;/p&gt;
&lt;h3&gt;7.4 The Synthetic Interrupt Controller (SynIC)&lt;/h3&gt;
&lt;p&gt;The Synthetic Interrupt Controller, SynIC, is the hypervisor&apos;s per-virtual-processor event delivery surface. Each VP has 16 Synthetic Interrupt Source (SINT) lines, a message page (where the hypervisor places message-shaped events), an event-flag page (where it places bit-flag events), and a set of synthetic timers. SynIC is the bus on which VMBus traffic between VSP and VSC moves; it is also the bus on which VTL transitions between VTL0 and VTL1 are delivered inside the root partition [@ms-tlfs-pdf].&lt;/p&gt;

A hypervisor-emulated interrupt controller, parallel to the hardware APIC, that delivers hypervisor-originated events to a virtual processor. Each VP has 16 SINT lines, a message page, an event-flag page, and synthetic timers. VMBus signaling rides on SynIC; secure-call delivery between VTL0 and VTL1 rides on SynIC; vTPM, virtual-PCI, and other paravirtualized device events ride on SynIC [@ms-tlfs-pdf].
&lt;p&gt;For VBS, the secure-call ABI -- the way VTL0 code asks VTL1 to do something -- is built on SynIC. A VTL0 caller writes a request into a shared message page, signals a SINT, and yields the CPU; the hypervisor switches SLAT context to VTL1, delivers the message, and lets VTL1 read the request. When VTL1 finishes, it signals a SINT back to VTL0 and the hypervisor switches contexts again. Credential Guard&apos;s whole communication path between VTL0 LSASS and VTL1 LSAISO is one of these secure-call channels.&lt;/p&gt;
&lt;h3&gt;7.5 Memory and per-VTL SLAT&lt;/h3&gt;
&lt;p&gt;The last surface is also the most important: memory. Guest physical addresses (GPAs) are translated to system physical addresses (SPAs) by per-partition SLAT page tables. The hypervisor has exclusive control of these tables; no partition, including the root, can read or modify them directly. For VBS specifically, the hypervisor maintains &lt;em&gt;two&lt;/em&gt; SLAT mappings per partition -- one for VTL0 and one for VTL1 -- and switches between them on VTL transitions.&lt;/p&gt;

flowchart LR
    GPA[&quot;Guest physical address (GPA)&quot;]
    SLAT0[&quot;VTL0 SLAT mapping&quot;]
    SLAT1[&quot;VTL1 SLAT mapping&quot;]
    SPA[&quot;System physical address (SPA)&quot;]
    HV[&quot;Hypervisor (owns both SLAT trees)&quot;]
    GPA --&amp;gt;|VTL0 active| SLAT0
    GPA --&amp;gt;|VTL1 active| SLAT1
    SLAT0 --&amp;gt;|&quot;normal pages&quot;| SPA
    SLAT1 --&amp;gt;|&quot;secret pages, +rwx&quot;| SPA
    SLAT0 -.-&amp;gt;|&quot;VTL1 secret pages: not present&quot;| SPA
    HV -.-&amp;gt;|&quot;switches context on VTL transition&quot;| SLAT0
    HV -.-&amp;gt;|&quot;switches context on VTL transition&quot;| SLAT1
&lt;p&gt;This is the architectural reason VTL0 kernel mode, even with full Ring-0 code execution, cannot read or execute VTL1 memory. The VTL0 page-table walker on a load from a VTL1-only page does not see the page at all; the SLAT walker on the host returns &lt;em&gt;no mapping&lt;/em&gt;; the hardware MMU raises an EPT/NPT violation; the hypervisor handles the violation according to the VTL0 partition&apos;s intercept policy. In the security-relevant case, the hypervisor delivers an access-denied result to VTL0 and continues. There is no kernel-mode &lt;code&gt;mov&lt;/code&gt; instruction sequence that can defeat this, because the gating happens in hardware page-table walks that VTL0 kernel mode cannot influence.&lt;/p&gt;
&lt;p&gt;Five surfaces. Two of them -- the hypercall ABI and the device-emulation paths that surface over VMBus -- are where every public Hyper-V escape since 2018 has lived. The other three (intercepts, SynIC, per-VTL SLAT) are the substrate on which VBS, HVCI, Credential Guard, and System Guard Secure Launch are built. We turn to those next.&lt;/p&gt;
&lt;h2&gt;8. How the Hypervisor Enforces Each VBS Feature&lt;/h2&gt;
&lt;p&gt;The hypervisor itself does not know anything about credentials, code signing, application allowlisting, or DMA protection. It knows about partitions, VTLs, intercepts, SLAT entries, and hypercalls. Each Windows security feature is built by &lt;em&gt;composing&lt;/em&gt; those primitives in a specific way. The mapping is precise and worth walking, because it is what makes the substrate a &lt;em&gt;security&lt;/em&gt; primitive rather than just a virtualization product [@ms-hardware-root-of-trust].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HVCI / Memory Integrity.&lt;/strong&gt; &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Hypervisor-protected Code Integrity&lt;/a&gt; is the most consequential VBS feature on a per-byte basis: it changes Windows from a system that lets the kernel execute any signed driver to one where the kernel cannot execute &lt;em&gt;any&lt;/em&gt; page until VTL1 has approved it. VTL1&apos;s code-integrity service inspects every kernel-mode page mapping change request before the SLAT entry that would make the page executable in VTL0 is granted. The W^X invariant -- a single page can be writable or executable, but never both -- is enforced not by NT kernel cooperation but by the per-VTL SLAT, exactly as described in section 7.5. An NT-kernel attempt to mark a writable page executable becomes a memory-access intercept that VTL1&apos;s CI service evaluates [@ms-enable-vbs-hvci]. The hypervisor primitives composed: per-VTL SLAT + memory-access intercepts + secure-call ABI.&lt;/p&gt;

A user-mode process that runs inside VTL1&apos;s Isolated User Mode (IUM). Trustlets must be signed with the Windows System Component Verification certificate (Signature Level 12) and carry the IUM EKU `1.3.6.1.4.1.311.10.3.37`. The shipping inbox trustlets include `LSAISO.EXE` (Credential Guard), `VMSP.EXE` (host side of virtual TPM), and the vTPM provisioning trustlet [@ms-iso-user-mode-trustlets, @ionescu-bh-2015].
&lt;p&gt;&lt;strong&gt;Credential Guard.&lt;/strong&gt; &lt;code&gt;LSAISO.EXE&lt;/code&gt; -- the LSA-Isolated trustlet -- runs in VTL1 Isolated User Mode. NTLM password hashes and Kerberos Ticket-Granting Tickets that LSASS used to keep in normal VTL0 memory are moved to VTL1 memory that VTL0 cannot read. VTL0 LSASS performs credential operations by sending a request to LSAISO over a secure-call channel mediated by the hypervisor&apos;s SynIC; LSAISO does the cryptographic work and returns a result. The plaintext of the credential never leaves VTL1. This is why a Ring-0 attacker on a Credential Guard-enabled Windows install cannot dump LSASS hashes -- they aren&apos;t in LSASS [@ms-iso-user-mode-trustlets]. The hypervisor primitives composed: per-VTL SLAT (to hide LSAISO&apos;s memory) + SynIC (to deliver secure calls) + intercepts (to catch VTL0 attempts to access LSAISO memory). See the sibling &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;Credential Guard / NTLMless&lt;/a&gt; article for VTL1 internals.&lt;/p&gt;

The VTL0-to-VTL1 calling convention. A VTL0 caller fills in a shared parameter page, signals a SynIC interrupt configured for VTL transition, and yields. The hypervisor switches SLAT context to VTL1, delivers the message, and lets the Secure Kernel dispatch it via `IumInvokeSecureService` to a registered VTL1 service. On return, the hypervisor switches contexts back. The whole round-trip is mediated by hypervisor primitives the calling VTL cannot bypass [@ionescu-bh-2015].
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;Application Control (WDAC)&lt;/a&gt;.&lt;/strong&gt; The same VTL1 code-integrity service that backs HVCI also evaluates user-mode policy. When VTL0 user mode tries to load a binary that is restricted by WDAC policy, the load becomes a secure call into VTL1; VTL1&apos;s policy engine evaluates the signature, the certificate chain, and the configured policy; the secure call returns approval or denial. WDAC policy lives in VTL1, the policy database lives in VTL1, and a VTL0 administrator who has been compromised cannot edit either. The hypervisor primitives composed: same as HVCI, plus a richer secure-call API for policy evaluation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VBS Enclaves.&lt;/strong&gt; A third-party application can load native code into a VTL1 IUM enclave. The enclave executes in VTL1, with its memory hidden from VTL0; the application talks to the enclave through a secure-call ABI exposed by the Secure Kernel. Architecturally parallel to Credential Guard but available to ordinary application developers. The hypervisor primitives composed: per-VTL SLAT (to hide enclave memory) + secure-call ABI (to invoke enclave code) + a Secure Kernel API for enclave creation, attestation, and destruction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;System Guard Secure Launch (DRTM).&lt;/strong&gt; Intel TXT&apos;s &lt;code&gt;SENTER&lt;/code&gt; instruction (and AMD&apos;s &lt;code&gt;SKINIT&lt;/code&gt; on AMD platforms) executes a hardware-rooted dynamic measurement of the hypervisor and the Secure Kernel into TPM PCRs 17-22 &lt;em&gt;after&lt;/em&gt; firmware initialization [@ms-system-guard-secure-launch]. This re-establishes the trust root post-firmware: a pre-boot firmware compromise that survived UEFI Secure Boot cannot silently poison the hypervisor&apos;s launch state without showing up as an unexpected measurement in a PCR that VTL1 can read. The hypervisor primitives composed: DRTM event registration with the hardware + TPM PCR extension + a VTL1-side attestation API. See the sibling &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; article for the static-RTM half of the same story.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kernel DMA Protection.&lt;/strong&gt; External devices over Thunderbolt, USB4, or hot-plug PCIe can issue DMA to arbitrary physical addresses, bypassing the CPU&apos;s MMU entirely. The hypervisor configures the IOMMU (Intel VT-d / AMD-Vi) to deny DMA from externally-attached devices outside of explicitly-authorized memory regions, and to refuse DMA from any device before its kernel-mode driver has been loaded under a trusted policy [@ms-kernel-dma-protection]. The hypervisor primitives composed: hypervisor-owned IOMMU configuration + memory-access intercepts on the IOMMU configuration MMIO region.&lt;/p&gt;
&lt;p&gt;The shape of the table is the point.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Composed primitives&lt;/th&gt;
&lt;th&gt;Verbatim hypervisor mechanism&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;HVCI&lt;/td&gt;
&lt;td&gt;per-VTL SLAT + memory-access intercepts + secure-call ABI&lt;/td&gt;
&lt;td&gt;VTL1 vets each VTL0 page-mapping change before granting +X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credential Guard&lt;/td&gt;
&lt;td&gt;per-VTL SLAT + SynIC + intercepts&lt;/td&gt;
&lt;td&gt;LSAISO trustlet memory absent from VTL0 SLAT mapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WDAC (AppControl)&lt;/td&gt;
&lt;td&gt;secure-call ABI + VTL1 policy engine&lt;/td&gt;
&lt;td&gt;VTL0 binary load = secure call into VTL1 CI service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VBS Enclaves&lt;/td&gt;
&lt;td&gt;per-VTL SLAT + secure-call ABI&lt;/td&gt;
&lt;td&gt;Third-party VTL1 IUM enclave invoked over secure call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;System Guard Secure Launch&lt;/td&gt;
&lt;td&gt;hardware DRTM (TXT/SKINIT) + TPM PCR extension&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SENTER&lt;/code&gt; / &lt;code&gt;SKINIT&lt;/code&gt; measures hypervisor into PCRs 17-22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel DMA Protection&lt;/td&gt;
&lt;td&gt;hypervisor-owned IOMMU + MMIO intercepts&lt;/td&gt;
&lt;td&gt;VT-d/AMD-Vi denies DMA outside authorized regions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The hypervisor knows nothing about NTLM hashes, Kerberos tickets, code-signing certificates, WDAC policy XML, or DMA-region authorization. All of that policy lives in VTL1 -- in the Secure Kernel, in LSAISO, in the WDAC service. The hypervisor only provides the *mechanism* for one piece of policy to evaluate a request from another piece of policy in isolation. This is the architectural separation that lets the hypervisor binary stay small and the Windows-side security feature set keep growing.
&lt;p&gt;The pattern: each feature is a different &lt;em&gt;composition&lt;/em&gt; of the same five primitives (partitions, hypercalls, intercepts, SynIC, per-VTL SLAT). The hypervisor is genuinely a primitive in the formal sense -- a small set of mechanisms that compose into many security policies. If the hypervisor is the mechanism, the &lt;em&gt;boundary&lt;/em&gt; the hypervisor enforces is the contract. Microsoft commits to servicing certain attacks against that boundary and explicitly excludes others. To know what we are getting, we need to read the contract.&lt;/p&gt;
&lt;h2&gt;9. The Security Boundary Microsoft Commits To&lt;/h2&gt;
&lt;p&gt;The Microsoft Security Servicing Criteria for Windows is a public document. It enumerates which classes of attack Microsoft will issue a CVE and an out-of-band patch for, and which it will not. For the hypervisor, the document is unusually specific [@ms-msrc-servicing-criteria].&lt;/p&gt;
&lt;p&gt;The two relevant boundaries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hypervisor / virtualization boundary.&lt;/strong&gt; An L1-guest-to-host or guest-to-guest break is a serviced boundary. If a guest VM can execute code in the root partition or in another guest&apos;s address space, Microsoft will issue a CVE.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual Secure Mode (VBS) boundary.&lt;/strong&gt; VTL0 kernel-mode code reading or writing VTL1 memory, or executing VTL1 code, is a serviced break. If a Ring-0 attacker in VTL0 can defeat the per-VTL SLAT, Microsoft will issue a CVE.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What the servicing criteria &lt;em&gt;does not&lt;/em&gt; commit to is also worth naming. A same-VTL elevation of privilege inside a guest (a guest user becoming guest SYSTEM) is not a hypervisor break -- it is a Windows EoP, serviced under the Windows kernel boundary, not the hypervisor boundary. A denial-of-service of the host from a guest is generally not a serviced hypervisor break unless it produces a memory corruption that an attacker can ride to RCE. An administrator in the root partition reading guest memory is not a break at all -- the root partition is part of the hypervisor&apos;s TCB by definition, and root-partition admin is hypervisor-admin in the threat model.&lt;/p&gt;
&lt;p&gt;The dollar figures for these boundaries are documented in the Microsoft Hyper-V Bounty Program [@ms-msrc-bounty-hyperv]. The program ranges from $5,000 for the lowest-impact qualifying submission up to $250,000 for the highest. The eligibility language is verbatim:&lt;/p&gt;

An eligible submission includes a Remote Code Execution (RCE) vulnerability in Microsoft Hyper-V that enables a L1 guest virtual machine to compromise the hypervisor, escape from the guest virtual machine to the host, or escape to another L1 guest virtual machine. -- Microsoft Hyper-V Bounty Program [@ms-msrc-bounty-hyperv]
&lt;p&gt;$250,000 is the highest standing Hyper-V bounty in the industry. Comparable programs from the other major hypervisor vendors do not publish the same calibration. KVM is a community project with no vendor-paid bounty pool of equivalent size. Xen is a Linux Foundation project that runs a bug bounty through HackerOne but does not publicly attach a $250,000 figure to a guest-to-host RCE. ESXi (Broadcom) does not publish a standing bounty program with a per-bug ceiling; bounty payments for ESXi RCEs typically flow through Pwn2Own and similar marketplaces, where Trend Micro&apos;s Zero Day Initiative sets the prize for any given competition.The bounty calibration is itself a data point. If $250,000 were too high, Microsoft would be drowning in submissions; if it were too low, the public CVE record would show more hypervisor breaks reported through Pwn2Own than directly to MSRC. The current equilibrium -- two to four Microsoft-direct Hyper-V CVEs per year, plus zero Pwn2Own Hyper-V guest-to-host escapes through Pwn2Own Berlin 2025 [@zdi-pwn2own-day3] -- is consistent with the bounty being calibrated roughly correctly relative to the cost of finding a real bug.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;Hypervisor&lt;/th&gt;
&lt;th&gt;Published bounty&lt;/th&gt;
&lt;th&gt;Ceiling&lt;/th&gt;
&lt;th&gt;Servicing-criteria boundary published&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Hyper-V / &lt;code&gt;hvix64.exe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;$250,000&lt;/td&gt;
&lt;td&gt;Yes, verbatim language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xen Project&lt;/td&gt;
&lt;td&gt;Xen&lt;/td&gt;
&lt;td&gt;Yes (HackerOne)&lt;/td&gt;
&lt;td&gt;Lower, varies&lt;/td&gt;
&lt;td&gt;Yes, security policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KVM&lt;/td&gt;
&lt;td&gt;KVM (community)&lt;/td&gt;
&lt;td&gt;No standing program&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;No vendor-published criteria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broadcom/VMware&lt;/td&gt;
&lt;td&gt;ESXi&lt;/td&gt;
&lt;td&gt;No standing public bounty&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;Vendor advisories per CVE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;seL4 Project&lt;/td&gt;
&lt;td&gt;seL4&lt;/td&gt;
&lt;td&gt;No (proof-rooted argument)&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;Functional-correctness proof [@sel4-whitepaper]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The seL4 row is included because seL4 is the only hypervisor in the table whose claim to a security boundary is &lt;em&gt;mathematical&lt;/em&gt; rather than operational. seL4 ships approximately ten thousand lines of C and assembly with a machine-checked proof of functional correctness against a higher-level specification. The proof took roughly twenty-five person-years and covers a microkernel that does not by itself ship the full surface area of Hyper-V. The Microsoft hypervisor is unverified at the §7-estimated line count an order of magnitude larger; its security argument is operational (a small TCB, heavy fuzzing, a standing bounty, public servicing) rather than mathematical.&lt;/p&gt;
&lt;p&gt;A serviced boundary is a contract. Contracts are not promises; they are obligations that come due when an attacker finds a way around them. To see what the contract has actually had to pay out, we read the public CVE record.&lt;/p&gt;
&lt;h2&gt;10. The Public Track Record -- Six Worked CVEs Across Three Classes&lt;/h2&gt;
&lt;p&gt;We do not need an exhaustive Hyper-V CVE catalog to understand the boundary&apos;s real shape. Six worked examples, drawn from three distinct attack classes, cover every public failure mode the boundary has produced since 2018. We walk them in order.&lt;/p&gt;
&lt;h3&gt;Class A: Device emulation in the root partition&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CVE-2021-28476 (vmswitch.sys, May 2021, CVSS 9.9).&lt;/strong&gt; Discovered by Ophir Harpaz at Guardicore Labs and Peleg Hadar at SafeBreach Labs using Guardicore&apos;s &lt;code&gt;hAFL1&lt;/code&gt; hypervisor fuzzer, this was a guest-controlled &lt;code&gt;OID_SWITCH_NIC_REQUEST&lt;/code&gt; OID parameter passed to the host-side &lt;code&gt;vmswitch.sys&lt;/code&gt; driver. The driver dereferenced an attacker-influenced object pointer; the host kernel performed an arbitrary pointer dereference; the guest gained RCE in the root partition&apos;s kernel mode. The CVSS 9.9 score (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H) reflects guest-to-host RCE with Azure-scale blast radius: the bug was reachable from the vmswitch driver shipped in Windows builds well before the May 2021 patch, per the Guardicore Labs technical analysis [@nvd-cve-2021-28476]. The bug is the canonical anchor for &quot;device emulation in the root partition is the largest Hyper-V attack surface.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2025-21333 (NT Kernel Integration VSP, January 2025, CWE-122).&lt;/strong&gt; The first publicly-acknowledged in-the-wild exploited Hyper-V CVE. The &quot;Hyper-V NT Kernel Integration VSP&quot; is a relatively new component that ties the Windows kernel-mode container architecture to Hyper-V&apos;s VSP/VSC pattern. A guest-controlled input triggered a heap-based buffer overflow on the host side of the integration; the host&apos;s address space was corruptible from a guest [@nvd-cve-2025-21333]. The operational pattern matches the vmswitch family: a host-side component receives structured, attacker-shaped input from a guest, and the host-side component overflows.&lt;/p&gt;
&lt;h3&gt;Class B: The hypercall input-validation path&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CVE-2024-21407 (Hyper-V hypercall UAF, March 2024, CVSS 8.1, CWE-416).&lt;/strong&gt; The rare case where the bug is in &lt;code&gt;hvix64.exe&lt;/code&gt; / &lt;code&gt;hvax64.exe&lt;/code&gt; itself, not in a root-partition driver. A guest crafted specially-formed file-operation hypercalls; the hypervisor dereferenced freed memory; the guest gained arbitrary host code execution [@nvd-cve-2024-21407].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2024-30092 (Hyper-V RCE, October 2024, CWE-20 + CWE-829).&lt;/strong&gt; A Hyper-V remote code execution that combined improper input validation with inclusion of functionality from an untrusted control sphere -- another hypercall-path-class bug [@nvd-cve-2024-30092].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CVE-2024-49117 (Hyper-V RCE, December 2024, CVSS 8.8).&lt;/strong&gt; A third 2024 Hyper-V RCE; the December Patch Tuesday entry rounded out a year in which three publicly-disclosed Hyper-V RCEs landed in twelve months, the most since the 2018 vmswitch family [@nvd-cve-2024-49117].&lt;/p&gt;
&lt;h3&gt;Class C: VTL0-to-VTL1 (the VBS break, not the hypervisor break)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;CVE-2020-0917 and CVE-2020-0918 -- Amar and King, Black Hat USA 2020.&lt;/strong&gt; Saar Amar and Daniel King&apos;s &quot;Breaking VSM by Attacking SecureKernel&quot; disclosed two paired vulnerabilities discovered with their Hyperseed hypercall fuzzer retargeted at &lt;code&gt;securekernel!IumInvokeSecureService&lt;/code&gt;, the secure-call entry point. Vulnerability #1 -- which maps to CVE-2020-0917 -- is an &lt;em&gt;out-of-bounds write&lt;/em&gt; in &lt;code&gt;securekernel!SkmmObtainHotPatchUndoTable&lt;/code&gt;, the function that parses the hot-patch undo table at secure-call invocation time.The Black Hat USA 2020 deck (verified via pdftotext at the canonical MSRC-Security-Research GitHub URL) explicitly labels Vulnerability #1 as &lt;strong&gt;OOB Write&lt;/strong&gt;, in slides titled &quot;The Vulnerable Function&quot; and &quot;The OOB&quot; in the &quot;Hardening SK&quot; section [@amar-king-bh-2020]. Several secondary writeups across the web have transcribed the bug class as &quot;OOB read,&quot; which is incorrect; the deck itself is the primary source and says write. The functions involved are also commonly conflated: &lt;code&gt;IumInvokeSecureService&lt;/code&gt; is the secure-call dispatcher Hyperseed retargets to reach the buggy code; the actual bug is in &lt;code&gt;SkmmObtainHotPatchUndoTable&lt;/code&gt;. The NVD entries for both CVEs are tracked as CWE-269 (Improper Privilege Management). Vulnerability #2 -- CVE-2020-0918 -- is a design flaw in &lt;code&gt;SkmmUnmapMdl&lt;/code&gt; that lets VTL0 pass a fully attacker-controlled Memory Descriptor List to &lt;code&gt;SkmiReleaseUnknownPTEs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The Microsoft response is documented end-to-end in the same deck: the Secure Kernel pool was migrated to segment heap in mid-2019, four W+X regions were reduced to +X only, and &lt;code&gt;SkpgContext&lt;/code&gt; -- a HyperGuard equivalent for Secure Kernel -- was introduced.&lt;/p&gt;
&lt;p&gt;This is a different failure class than vmswitch RCE: not guest-to-host, but VTL0-to-VTL1 -- a Secure Kernel break reached through the hypervisor&apos;s secure-call dispatch from a privileged VTL0 attacker. Microsoft services it under the VBS / VSM boundary in the servicing criteria document, even though no guest VM is involved.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every public Hyper-V CVE since 2018 lives in one of three narrow code paths -- device emulation, hypercall input validation, or VTL0-to-VTL1 secure-call dispatch. The TLFS-visible primitives (intercepts, SynIC, per-VTL SLAT) have produced none.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The Pwn2Own dimension&lt;/h3&gt;
&lt;p&gt;Through Pwn2Own Berlin 2025, no public live Hyper-V guest-to-host escape has been demonstrated at Pwn2Own. The cross-vendor analogue -- and the industry&apos;s best calibration of how hard a hypervisor escape is to find when a researcher has a public dollar incentive and a deadline -- is the first-ever ESXi escape in Pwn2Own history, executed by Nguyen Hoang Thach of STAR Labs SG on Day Two (May 16, 2025) using a single integer overflow vulnerability in the hypervisor&apos;s DMA-handling path. The award was $150,000 plus 15 Master of Pwn points; STAR Labs went on to win overall Master of Pwn for the competition with $320,000 across three days [@zdi-pwn2own-day3].&lt;/p&gt;
&lt;p&gt;The technique class is a TOCTOU on a length field read twice during a DMA operation: the first read validates the length, the second read uses it; race the second read and you write past a fixed-size buffer on the host heap. The exploit class is structurally the same as the vmswitch family, just landed in a different vendor&apos;s device-emulation path.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CVE&lt;/th&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;CVSS&lt;/th&gt;
&lt;th&gt;Location&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;CVE-2021-28476&lt;/td&gt;
&lt;td&gt;A: device emulation&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;9.9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vmswitch.sys&lt;/code&gt; (root partition)&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2021-28476]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2025-21333&lt;/td&gt;
&lt;td&gt;A: device emulation&lt;/td&gt;
&lt;td&gt;2025&lt;/td&gt;
&lt;td&gt;7.8&lt;/td&gt;
&lt;td&gt;NT Kernel Integration VSP (root partition)&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2025-21333]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-21407&lt;/td&gt;
&lt;td&gt;B: hypercall path&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;8.1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hvix64.exe&lt;/code&gt; / &lt;code&gt;hvax64.exe&lt;/code&gt; (hypervisor binary)&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2024-21407]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-30092&lt;/td&gt;
&lt;td&gt;B: hypercall path&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;7.5&lt;/td&gt;
&lt;td&gt;Hyper-V hypercall validation&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2024-30092]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2024-49117&lt;/td&gt;
&lt;td&gt;B: hypercall path&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;8.8&lt;/td&gt;
&lt;td&gt;Hyper-V hypercall validation&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2024-49117]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2020-0917/0918&lt;/td&gt;
&lt;td&gt;C: VTL0-to-VTL1&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;6.8 (per MSRC)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;securekernel.exe&lt;/code&gt; (VTL1, reached via secure call)&lt;/td&gt;
&lt;td&gt;[@amar-king-bh-2020]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart LR
    subgraph CA[&quot;Class A: device emulation (root partition)&quot;]
        Vmswitch[&quot;vmswitch.sys -- CVE-2021-28476&quot;]
        Vsp[&quot;NT Kernel Integration VSP -- CVE-2025-21333&quot;]
    end
    subgraph CB[&quot;Class B: hypercall input validation (hypervisor binary)&quot;]
        UAF[&quot;CVE-2024-21407 (UAF)&quot;]
        Input[&quot;CVE-2024-30092&quot;]
        Hpcall[&quot;CVE-2024-49117&quot;]
    end
    subgraph CC[&quot;Class C: VTL0-to-VTL1 (secure call dispatch)&quot;]
        Oob[&quot;CVE-2020-0917 (OOB write)&quot;]
        Mdl[&quot;CVE-2020-0918 (SkmmUnmapMdl)&quot;]
    end
    Guest[&quot;Guest VM&quot;] --&amp;gt; CA
    Guest --&amp;gt; CB
    Vtl0[&quot;Privileged VTL0 (kernel)&quot;] --&amp;gt; CC
&lt;p&gt;This is the third insight the article is built around. The reader&apos;s prior model may have been &quot;hypervisors fail in mysterious, deep ways; the boundary is fragile in unknown places.&quot; The new model is &quot;every public Hyper-V escape since 2018 lives in one of three narrow code paths, and the TLFS-visible primitives have produced none.&quot; The narrowness of the failure space is itself a security argument. The hypervisor&apos;s micro-kernelized design has held; what has not always held are the components Microsoft chose to put &lt;em&gt;next to&lt;/em&gt; the hypervisor, in the root partition&apos;s user mode and kernel mode, by deliberate architectural choice in 2008.&lt;/p&gt;
&lt;p&gt;Six worked examples; three classes; one boundary; an unflinching public record. The boundary is alive and producing CVEs at roughly two to four per year. But every CVE so far has lived somewhere the hypervisor itself controls. The interesting question is what lives in places it does not control.&lt;/p&gt;
&lt;h2&gt;11. The Residual Attack Surface -- Beneath, Beside, and Around&lt;/h2&gt;
&lt;p&gt;The hypervisor enforces a clean boundary against everything &lt;em&gt;above&lt;/em&gt; it -- the NT kernel, user mode, even other guest VMs. It cannot, by construction, enforce anything against what lives &lt;em&gt;below&lt;/em&gt; or &lt;em&gt;beside&lt;/em&gt; it. Three structural classes of residual attack matter. We walk each.&lt;/p&gt;
&lt;h3&gt;11.1 Firmware below the hypervisor&lt;/h3&gt;
&lt;p&gt;System Management Mode (SMM), the UEFI runtime, the platform Manageability Engine (Intel ME), and the AMD Platform Security Processor (PSP) all run at higher privilege than the hypervisor for parts of boot and runtime. SMM in particular is a CPU mode that is invoked through System Management Interrupts (SMI) and has unrestricted access to all of physical memory, including the hypervisor&apos;s own pages. If the OEM-supplied SMM handler contains an exploitable bug, an SMI can run attacker code in a privilege mode strictly above the hypervisor&apos;s.&lt;/p&gt;
&lt;p&gt;The threat is not hypothetical. The Binarly research team&apos;s 2023 LogoFAIL disclosures showed entire classes of image-parser bugs in UEFI firmware reachable from a privileged OS context; BootHole (CVE-2020-10713, a buffer overflow in GRUB2&apos;s &lt;code&gt;grub.cfg&lt;/code&gt; parser) and BlackLotus (CVE-2022-21894, a UEFI Secure Boot bypass) showed that pre-boot bugs in widely-deployed bootloaders could ride past Secure Boot. None of these is a hypervisor bug; all of them are residual attack surface from the hypervisor&apos;s point of view.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s mitigation is the &lt;em&gt;dynamic&lt;/em&gt; root of trust for measurement -- System Guard Secure Launch -- which we touched on in section 8. After UEFI Secure Boot has done its static-RTM job, Intel TXT&apos;s &lt;code&gt;SENTER&lt;/code&gt; (or AMD&apos;s &lt;code&gt;SKINIT&lt;/code&gt;) executes a CPU-hardware-rooted late launch: the CPU resets to a known state, runs an Intel- or AMD-signed Authenticated Code Module (ACM), and measures the hypervisor binary into TPM PCRs 17-22 before transferring control to it. The result is that even if pre-boot firmware is compromised, the post-DRTM PCR values reflect the actual hypervisor binary; a compromised UEFI cannot silently substitute a different hypervisor without changing the attestation [@ms-system-guard-secure-launch, @ms-hardware-root-of-trust]. The residual after DRTM: OEMs that don&apos;t ship Secure Launch on their motherboards, or that ship buggy SMM handlers that can be invoked after launch.&lt;/p&gt;
&lt;h3&gt;11.2 Hardware side channels&lt;/h3&gt;
&lt;p&gt;Microarchitectural side-channel attacks cross the VTL boundary at the level of CPU implementation, not at the level of architectural specification. The 2018 Spectre and Meltdown disclosures -- followed by the L1TF, MDS, Retbleed, and CacheWarp families in the years since -- showed that speculatively-executed code on a CPU can leak microarchitectural state across privilege boundaries that the architectural ISA promises to protect.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s mitigation cadence has been in-tree and aggressive: Kernel Virtual Address Shadow (the Windows equivalent of KPTI) for Meltdown; IBRS, STIBP, and retpolines for Spectre v2; HyperClear for L1TF on Hyper-V hosts. Each Patch Tuesday since 2018 has shipped at least one microarchitectural mitigation; cumulatively the cost has been measurable but bounded.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The microarchitectural ceiling is hardware, not software. Intel TDX and AMD SEV-SNP -- the two confidential-computing architectures that move the trust root from the hypervisor to per-VM hardware encryption -- both explicitly &lt;em&gt;disclaim&lt;/em&gt; resistance to this class. If the CPU leaks across a Spectre-class side channel, no software-level isolation primitive (VTL, partition, SEAM, SEV-SNP) can fully recover the property. The mitigation is hardware that doesn&apos;t leak, and that mitigation arrives one CPU generation at a time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;11.3 IOMMU and DMA bypass&lt;/h3&gt;
&lt;p&gt;The IOMMU -- Intel VT-d, AMD-Vi -- is the hardware that gates DMA from peripheral devices to physical memory. If the IOMMU is configured correctly, a Thunderbolt-attached device cannot read or write arbitrary memory; it can only DMA to regions the OS has explicitly mapped for it. If the IOMMU is disabled, configured permissively, or has firmware bugs of its own, DMA becomes an end-run around every architectural protection above it -- including the hypervisor&apos;s.&lt;/p&gt;
&lt;p&gt;The threat is again not hypothetical. Bjorn Ruytenberg&apos;s Thunderspy disclosure in 2020 documented seven DMA-class vulnerabilities in Thunderbolt 3 firmware, demonstrating that an attacker with physical access could read or modify arbitrary memory on a powered-on system through a malicious peripheral [@thunderspy]. The Microsoft mitigation is Kernel DMA Protection (Windows 10 1803 and later): the hypervisor configures the IOMMU at boot to deny DMA from externally-attached devices outside of explicitly authorized regions, and DMA from any peripheral whose driver has not been loaded under a trusted policy is refused at the IOMMU [@ms-kernel-dma-protection]. The structural residual: pre-boot DMA, before Windows has finished configuring the IOMMU; client motherboards that still ship with VT-d or AMD-Vi disabled in BIOS; OEMs that disable Kernel DMA Protection by default.&lt;/p&gt;
&lt;h3&gt;11.4 Hypervisor downgrade and rollback&lt;/h3&gt;
&lt;p&gt;Alon Leviev&apos;s &quot;Windows Downdate&quot; at Black Hat USA 2024 disclosed a class of attack that the prior three sections do not cover: rollback of the hypervisor binary itself to a previously-vulnerable, but still validly-signed, build [@nvd-cve-2024-21302].&lt;/p&gt;
&lt;p&gt;The structural argument: UEFI Secure Boot prevents loading an &lt;em&gt;unsigned&lt;/em&gt; &lt;code&gt;hvix64.exe&lt;/code&gt;. It does &lt;em&gt;not&lt;/em&gt; prevent loading an older &lt;code&gt;hvix64.exe&lt;/code&gt; that is unsigned only in the sense of being unrevoked. If Microsoft fixes a Secure Kernel bug in build N+1 and a VTL0 attacker can convince the system to load build N at the next reboot, the patched bug is alive again. CVE-2024-21302 demonstrated exactly this rollback against both the hypervisor and the Secure Kernel through manipulation of the Windows Update servicing pipeline. The mitigation is mandatory-update servicing combined with proactive revocation list (&lt;code&gt;dbx&lt;/code&gt;) hygiene -- once an older binary&apos;s hash is in the UEFI revocation list, Secure Boot will refuse to load it -- and Microsoft completed mitigations across Windows 10 1507 through Windows Server 2019 in the July 8, 2025 update wave [@nvd-cve-2024-21302].&lt;/p&gt;

flowchart TD
    HW[&quot;Hardware (CPU, RAM, IOMMU, TPM)&quot;]
    SM[&quot;System Management Mode (Ring -2) -- residual: SMM handler bugs&quot;]
    FW[&quot;UEFI firmware -- residual: LogoFAIL, BootHole, BlackLotus&quot;]
    DR[&quot;DRTM ACM (Intel TXT / AMD SKINIT)&quot;]
    HV[&quot;Microsoft Hypervisor (hvix64 / hvax64)&quot;]
    Iommu[&quot;IOMMU (VT-d / AMD-Vi) -- residual: Thunderspy, pre-boot DMA&quot;]
    Vtl1[&quot;VTL1 (Secure Kernel + trustlets)&quot;]
    Vtl0[&quot;VTL0 (NT kernel + user mode)&quot;]
    Side[&quot;Microarchitectural side channels -- Spectre / Meltdown / MDS / Retbleed&quot;]
    Update[&quot;Windows Update servicing -- residual: hypervisor rollback (CVE-2024-21302)&quot;]
    HW --&amp;gt; SM
    SM --&amp;gt; FW
    FW --&amp;gt; DR
    DR --&amp;gt; HV
    HV --&amp;gt; Iommu
    HV --&amp;gt; Vtl1
    HV --&amp;gt; Vtl0
    Side -.-&amp;gt;|&quot;cross all boundaries&quot;| HV
    Update -.-&amp;gt;|&quot;can roll hypervisor back&quot;| HV

The hypervisor is necessary but not sufficient. The firmware-Secure-Boot-DRTM substrate beneath it, the microarchitectural ceiling above it, the IOMMU configuration beside it, and the Windows Update pipeline that decides which hypervisor build runs next are co-equal members of the same boundary. None of them is the hypervisor; all of them have to do their job for the hypervisor&apos;s guarantees to hold. The substrate is real, but the boundary is the combination of the substrate and what holds it up.
&lt;p&gt;Necessary, not sufficient. That phrase is the article&apos;s honest answer to the question &quot;how good is the substrate?&quot; The answer is that the substrate is genuine, the boundary is published, the bounty calibration is the highest in the industry, the public CVE record is alive and narrow, and the residual attack surface lives in places the hypervisor cannot by construction control. The substrate is what we have explored in detail; what holds it up is what we have just sketched. The last section turns from theory to practice.&lt;/p&gt;
&lt;h2&gt;12. Practical Guide, FAQ, and Closing&lt;/h2&gt;
&lt;p&gt;If you have read this far, the natural next question is &quot;is this on, on my machine, and how do I check?&quot; The practical answer is short.&lt;/p&gt;
&lt;h3&gt;12.1 Enabling and verifying VBS&lt;/h3&gt;
&lt;p&gt;VBS is configurable through several paths: Group Policy (&lt;code&gt;Computer Configuration &amp;gt; Administrative Templates &amp;gt; System &amp;gt; Device Guard&lt;/code&gt;), Intune, MDM CSPs (&lt;code&gt;DeviceGuard/EnableVirtualizationBasedSecurity&lt;/code&gt;, &lt;code&gt;DeviceGuard/ConfigureSystemGuardLaunch&lt;/code&gt;), the Windows Security UI, or directly via &lt;code&gt;bcdedit /set hypervisorlaunchtype Auto&lt;/code&gt;. Verification is best done with three small commands.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;msinfo32&lt;/code&gt; -&amp;gt; the Device Guard / Virtualization-based Security row. &quot;Services Configured&quot; lists what policy has requested; &quot;Services Running&quot; lists what is actually active. Kernel DMA Protection and Secure Launch each appear as their own row.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard&lt;/code&gt; -&amp;gt; &lt;code&gt;VirtualizationBasedSecurityStatus&lt;/code&gt; (0 = off, 1 = enabled but not running, 2 = running); &lt;code&gt;SecurityServicesRunning&lt;/code&gt; array (HVCI, Credential Guard, etc.); &lt;code&gt;RequiredSecurityProperties&lt;/code&gt; (the policy floor).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bcdedit /enum&lt;/code&gt; -&amp;gt; &lt;code&gt;hypervisorlaunchtype Auto&lt;/code&gt; is the default; &lt;code&gt;loadoptions DISABLE_VBS_*&lt;/code&gt; is how an administrator can opt out (you should not see these flags on a properly-configured machine).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;{`
// Given a parsed Win32_DeviceGuard object, compute whether VBS is healthy.
// The actual Win32_DeviceGuard schema is on Microsoft Learn; this is the
// decision logic an operator would write against it.
function checkVbsHealth(dg) {
  const result = { ok: false, reasons: [] };&lt;/p&gt;
&lt;p&gt;  // VBS itself
  if (dg.VirtualizationBasedSecurityStatus !== 2) {
    result.reasons.push(&apos;VBS is not running (status != 2)&apos;);
  }&lt;/p&gt;
&lt;p&gt;  // HVCI (Memory Integrity)
  if (!dg.SecurityServicesRunning.includes(2)) {
    result.reasons.push(&apos;HVCI / Memory Integrity is not running&apos;);
  }&lt;/p&gt;
&lt;p&gt;  // Credential Guard
  if (!dg.SecurityServicesRunning.includes(1)) {
    result.reasons.push(&apos;Credential Guard is not running&apos;);
  }&lt;/p&gt;
&lt;p&gt;  // Required floor properties (e.g. Secure Boot, DMA protection, SMM mitigation)
  const requiredFloor = [1, 2, 3]; // service codes per Win32_DeviceGuard
  for (const r of requiredFloor) {
    if (!dg.AvailableSecurityProperties.includes(r)) {
      result.reasons.push(&apos;Missing required security property: &apos; + r);
    }
  }&lt;/p&gt;
&lt;p&gt;  result.ok = result.reasons.length === 0;
  return result;
}&lt;/p&gt;
&lt;p&gt;const example = {
  VirtualizationBasedSecurityStatus: 2,
  SecurityServicesRunning: [1, 2, 3],
  AvailableSecurityProperties: [1, 2, 3, 4, 5],
};
console.log(JSON.stringify(checkVbsHealth(example), null, 2));
// -&amp;gt; { ok: true, reasons: [] }
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Three commands, in order: &lt;code&gt;msinfo32&lt;/code&gt; for the human-readable summary; &lt;code&gt;Get-CimInstance -ClassName Win32_DeviceGuard | Format-List *&lt;/code&gt; for the structured detail; &lt;code&gt;bcdedit /enum {current}&lt;/code&gt; to confirm &lt;code&gt;hypervisorlaunchtype Auto&lt;/code&gt; and the absence of &lt;code&gt;DISABLE_VBS_*&lt;/code&gt; load options. If all three agree that VBS, HVCI, and Credential Guard are running, you are in the configuration this article describes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;12.2 Operational pitfalls&lt;/h3&gt;
&lt;p&gt;Two operational realities are worth flagging. First, HVCI has a &lt;em&gt;&lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;driver block list&lt;/a&gt;&lt;/em&gt; and will refuse to enable Memory Integrity if any incompatible driver is installed; the usual offenders are older anti-cheat drivers, third-party virtualization clients (VMware Workstation pre-2021, VirtualBox pre-6.1), and certain disk-encryption or storage-filter drivers. Microsoft maintains a public block list; the Memory Integrity UI in Windows Security will report the specific blocking driver. Second, nested virtualization is supported for Hyper-V guests on Windows 10/11 client and Server 2016+, and is required by some development workflows (WSL2 with nested containers, certain Visual Studio device emulators). Nested virtualization changes the threat model -- the L0 hypervisor still owns the box, but the L1 guest now runs its own hypervisor with its own VTL split -- so a compromised L1 guest with VBS enabled still does not give an L1 attacker a path to the L0 host.&lt;/p&gt;
&lt;h3&gt;12.3 The substrate cross-reference&lt;/h3&gt;
&lt;p&gt;This article is the substrate of the Windows security series at paragmali.com. The siblings build on what is here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&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 in Windows&lt;/a&gt; -- the static-RTM half of the boot trust chain that hands off to the hypervisor.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;VBS Trustlets: What Actually Runs in the Secure Kernel&lt;/a&gt; -- the VTL1 internals that the hypervisor&apos;s secure-call ABI delivers requests to.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;NTLMless: The Death of NTLM in Windows&lt;/a&gt; -- the Credential Guard story from inside LSAISO.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Adminless: Administrator Protection in Windows&lt;/a&gt; -- the user-mode admin trust model that the kernel-mode VBS boundary makes possible.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paragmali.com/blog/windows-access-control-25-years-of-attacks/&quot; rel=&quot;noopener&quot;&gt;Can This Code Do This? Windows Access Control&lt;/a&gt; -- the access-control surface that VBS supplements but does not replace.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;12.4 Frequently asked questions&lt;/h3&gt;


The 10-30 percent number is folklore from the pre-SLAT era or from systems running HVCI-incompatible drivers in compatibility mode. For typical workloads on modern hardware (post-2018 CPUs with VT-x or AMD-V and SLAT), the measured overhead of VBS plus HVCI plus Credential Guard sits in the low single digits. Gaming and high-throughput I/O workloads can show larger gaps, especially on systems where the BIOS forces nested virtualization off or where IOMMU is disabled. The trade-off for that overhead is the security-boundary set described in this article.

No. VBS is a Virtual Trust Level split *inside* the root partition. There are no extra VMs. The normal Windows install is VTL0; the Secure Kernel plus its trustlets is VTL1. Both VTLs live in the same partition, share the same physical CPU, and are scheduled by the hypervisor as separate VTL contexts -- not as separate VMs. A Hyper-V guest VM, by contrast, is a child partition entirely separate from the root partition. The two architectures share a hypervisor binary but use different parts of it.

No. SYSTEM is a high VTL0 user-mode token; the hypervisor sits architecturally above all of Ring 0, which is where SYSTEM-loaded kernel drivers ultimately run. The point of the entire article is that &quot;SYSTEM owns the box&quot; is wrong on a VBS-enabled Windows install. SYSTEM is the most privileged Windows identity; the hypervisor is the most privileged *software*, and the two are not the same thing.

No. Secure Boot prevents loading an *unsigned* `hvix64.exe`. It does not prevent loading an older, signed-but-vulnerable `hvix64.exe` that has not been added to the UEFI revocation list. That gap is what CVE-2024-21302 (Windows Downdate) exploited, and the mitigation is mandatory-update servicing combined with prompt revocation-list (`dbx`) hygiene [@nvd-cve-2024-21302].

No. seL4 is formally verified at approximately ten thousand lines of code with a roughly twenty-five-person-year proof effort. The Microsoft hypervisor is unverified at an estimated one to two hundred thousand lines of code. The hypervisor&apos;s security argument is operational -- a small TCB, heavy continuous fuzzing, a standing \$5K-\$250K bounty, public servicing criteria, an unflinching public CVE record -- rather than mathematical [@sel4-whitepaper, @ms-msrc-bounty-hyperv].

Yes, in terms of binary identity, servicing criteria, and bounty eligibility. The Microsoft hypervisor that boots on a Windows 11 client laptop and the one that boots on an Azure host server are derived from the same codebase, ship with the same servicing commitments, and qualify for the same Hyper-V bounty. The threat model differs -- Azure adds multi-tenant guest-to-guest isolation, hardware confidential-VM extensions, and a different management surface -- but the substrate is shared.

&lt;h3&gt;12.5 Closing&lt;/h3&gt;
&lt;p&gt;The reason SYSTEM on a Windows 11 box cannot read LSASS, load an unsigned driver, or patch &lt;code&gt;ntoskrnl.exe&lt;/code&gt; is now fully accounted for. An &lt;code&gt;hvix64.exe&lt;/code&gt; or &lt;code&gt;hvax64.exe&lt;/code&gt; loaded by &lt;code&gt;hvloader.efi&lt;/code&gt; before &lt;code&gt;winload.exe&lt;/code&gt; ever ran. A VTL split inside the root partition, made possible by Hepkin and Kishan&apos;s 2013 patent and shipped with Windows 10 RTM in 2015. Per-VTL SLAT enforcement that the NT kernel architecturally cannot touch, because the SLAT tables live in pages the hypervisor never maps into a VTL0 view. A Microsoft-published security boundary and a $5,000-$250,000 bounty calibrating the boundary&apos;s value, both of which are unique in the industry at this writing. A public CVE record of six worked examples across three narrow classes that the boundary has had to pay out on since 2018. And a residual attack surface -- firmware below, side channels above, IOMMU bypass beside, hypervisor rollback through the update pipeline -- that the substrate cannot, by construction, eliminate.&lt;/p&gt;
&lt;p&gt;The hypervisor is what every other article in this series sits on. Now you have the substrate in hand. The Secure Kernel article reads differently when you have walked the per-VTL SLAT yourself. The Credential Guard article reads differently when you know that LSAISO is invoked through a hypercall-mediated secure call. The Secure Boot article reads differently when you know that the hypervisor&apos;s DRTM measurement re-establishes the trust root &lt;em&gt;after&lt;/em&gt; firmware. The Adminless article reads differently when you know that the privilege ceiling on Windows 11 is not Ring 0 but a hardware boundary above it.&lt;/p&gt;
&lt;p&gt;Above Ring Zero is not a metaphor. It is an instruction-set state. The Windows hypervisor lives there, owns the page tables that say what the OS can see, and is the architectural reason &quot;SYSTEM-on-Windows-11&quot; cannot do things SYSTEM used to be allowed to do.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;windows-hypervisor-security-primitive&quot; keyTerms={[
  { term: &quot;VBS&quot;, definition: &quot;Virtualization-Based Security. A Windows architecture that uses the Hyper-V hypervisor to isolate security-critical code (the Secure Kernel and trustlets) from the regular NT kernel via per-VTL SLAT.&quot; },
  { term: &quot;VTL&quot;, definition: &quot;Virtual Trust Level. A hypervisor-managed privilege level inside a single partition; each VTL has its own SLAT mapping, register state, and interrupt subsystem. Two VTLs ship today (VTL0 = Normal world, VTL1 = Secure world); the architecture admits up to sixteen.&quot; },
  { term: &quot;Hypercall&quot;, definition: &quot;A guest-to-hypervisor call issued via vmcall (Intel) or vmmcall (AMD). The hypercall ABI is documented in the TLFS; rcx carries the call code and a control word, rdx/r8 carry parameters (fast) or GPA pointers to parameter pages (slow).&quot; },
  { term: &quot;SynIC&quot;, definition: &quot;Synthetic Interrupt Controller. The hypervisor&apos;s per-virtual-processor event-delivery surface. SynIC carries VMBus traffic, secure-call signaling, and synthetic timers.&quot; },
  { term: &quot;SLAT&quot;, definition: &quot;Second-Level Address Translation. Hardware page-table support (Intel EPT, AMD NPT) that lets the hypervisor own a separate mapping from guest-physical to system-physical addresses.&quot; },
  { term: &quot;DRTM&quot;, definition: &quot;Dynamic Root of Trust for Measurement. A late-launch event (Intel TXT SENTER, AMD SKINIT) that measures the hypervisor binary into TPM PCRs after firmware initialization, re-establishing the trust root post-firmware.&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A user-mode process that runs inside VTL1&apos;s Isolated User Mode (IUM). Signed with Signature Level 12 plus the IUM EKU. Inbox trustlets include LSAISO (Credential Guard) and VMSP (vTPM host side).&quot; }
]} questions={[
  { q: &quot;Why is the same-privilege paradox an architectural ceiling rather than an implementation bug?&quot;, a: &quot;Because the defender at privilege level P shares an address space with an attacker at the same level. The attacker can locate and edit any state the defender maintains using ordinary load/store instructions. Better defenses at P do not change where the defender lives; only moving the defender to a privilege level above P does.&quot; },
  { q: &quot;What 2013 patent describes the per-VTL design that Windows 10 shipped in 2015?&quot;, a: &quot;US Patent 9,430,642 B2 by David Hepkin and Arun Kishan, priority date September 17, 2013, granted August 30, 2016. It teaches hierarchical Virtual Trust Levels with per-VTL memory access protections and per-VTL virtual-processor register state.&quot; },
  { q: &quot;Name the three classes that all post-2018 public Hyper-V CVEs fall into.&quot;, a: &quot;Class A: device emulation in the root partition (vmswitch.sys, NT Kernel Integration VSP). Class B: hypercall input-validation inside the hypervisor binary itself. Class C: VTL0-to-VTL1 secure-call dispatch into the Secure Kernel.&quot; },
  { q: &quot;Which hypervisor primitive does HVCI&apos;s W^X enforcement ride on?&quot;, a: &quot;Per-VTL SLAT. An NT-kernel attempt to mark a writable VTL0 page executable becomes a memory-access intercept routed to VTL1&apos;s code-integrity service; the hypervisor only grants the new SLAT entry if VTL1 approves.&quot; },
  { q: &quot;Why does Secure Boot not prevent hypervisor rollback?&quot;, a: &quot;Secure Boot validates signatures, not freshness. An older, validly-signed-but-vulnerable hypervisor binary that has not been added to the UEFI revocation list (dbx) will still load. Closing this gap requires proactive dbx hygiene plus mandatory-update servicing, which is what mitigated CVE-2024-21302 Windows Downdate.&quot; },
  { q: &quot;What is the structural difference between Blue Pill (offense) and VBS (defense)?&quot;, a: &quot;Architecturally there is none. Both are thin Type-1 hypervisors that interpose between firmware and OS, own the second-level page tables, and are invisible to the OS unless the OS can attest to what is underneath it. The differences are whose hypervisor it is, whether it was measured at load time, and what it does with its privilege.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows</category><category>hypervisor</category><category>hyper-v</category><category>vbs</category><category>virtualization</category><category>security</category><category>systems</category><category>tcb</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></channel></rss>