<?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: security-boundaries</title><description>Posts tagged security-boundaries.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:17 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/security-boundaries/rss.xml" rel="self" type="application/rss+xml"/><item><title>Windows Security Boundaries: The Document That Decides What Gets a CVE</title><link>https://paragmali.com/blog/windows-security-boundaries-the-document-that-decides-what-g/</link><guid isPermaLink="true">https://paragmali.com/blog/windows-security-boundaries-the-document-that-decides-what-g/</guid><description>Microsoft maintains a single public document that decides which Windows vulnerability reports receive a CVE, a Patch Tuesday bulletin, and a bounty payout. Here is how to read it.</description><pubDate>Sun, 24 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Microsoft maintains a single public document that decides which Windows vulnerability reports receive a CVE, a Patch Tuesday bulletin, and a bounty payout, and which receive &quot;by design.&quot;** The *Security Servicing Criteria for Windows* enumerates nine security **boundaries** (network, process, kernel, session, user, AppContainer, virtual machine, Virtual Trust Level, and as of 2025, the Administrator Protection elevation path) and seven security **features** (UAC, Microsoft Defender, HVCI, Driver Signing, Protected Process Light, admin-to-kernel privilege escalation, same-user post-authentication). A two-question triage rule generates every MSRC disposition, including every &quot;by design -- UAC is not a security boundary&quot; reply you have ever read. Reading the doctrine is the difference between filing a useful MSRC report and getting back one polite sentence.
&lt;h2&gt;1. A UAC Bypass Walks Into MSRC&lt;/h2&gt;
&lt;p&gt;Three weeks of reverse engineering. A clean video of &lt;code&gt;consent.exe&lt;/code&gt; being skipped via a registry-hijack technique. A report filed through &lt;code&gt;msrc.microsoft.com/report&lt;/code&gt;. Two business days later, the Microsoft Security Response Center replies in one sentence: &lt;em&gt;&quot;Thank you for the report. UAC is not a security boundary; please refer to the Microsoft Security Servicing Criteria for Windows. This issue is by design.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That sentence has been Microsoft&apos;s consistent position since June 2007 [@russinovich-vista-uac-wayback]. It is the operational anchor of every Windows vulnerability disposition made in the last nineteen years, and it routes through a single public document most researchers have never read.&lt;/p&gt;
&lt;p&gt;The document is called the &lt;em&gt;Microsoft Security Servicing Criteria for Windows&lt;/em&gt; [@msrc-criteria]. Twenty-eight paragraphs and two enumerated tables live on a single MSRC web page. Those paragraphs decide which Windows findings get a CVE number, which get a Patch Tuesday bulletin, which get a bounty payout, and which get a polite &quot;by design&quot; reply that closes the ticket without a fix. Every other operational artifact in Microsoft&apos;s security response -- the bounty schedule, the monthly bulletin calendar, the per-finding severity ratings -- is downstream of this one taxonomy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &quot;by design&quot; reply is not boilerplate. Every MSRC triage engineer who issues it is applying a specific clause of a specific document. The reply means: we read your finding, mapped it against our published classification, and the primitive you attacked is on our security-feature list rather than our security-boundary list. We may still harden the feature in a future build, but we are not going to assign a CVE or ship a Patch Tuesday bulletin for it. The classification is published. The disposition follows from the classification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The researcher&apos;s first reaction is the natural one. Three weeks of work. A working bypass. A Microsoft binary skipped. And the reply is &lt;em&gt;one sentence&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;It is right, and the rest of this article is the explanation of why. We will walk the document&apos;s history from a single June 2007 TechNet article through the November 2024 Administrator Protection announcement, decode the two-question triage rule that generates every MSRC disposition, take each of the nine boundaries and each of the seven features in turn, and finish with a checklist for filing a report that does not come back &quot;by design.&quot;&lt;/p&gt;
&lt;p&gt;To understand why the reply was operationally correct, not a cop-out, we have to walk the document&apos;s history back to its origin: a single article published in &lt;em&gt;TechNet Magazine&lt;/em&gt; in June 2007, by an author Microsoft had named a Technical Fellow just five months before.&lt;/p&gt;
&lt;h2&gt;2. The Pre-Doctrine Era&lt;/h2&gt;
&lt;p&gt;For the first fourteen years of Windows NT, there was no servicing-criteria document. There did not need to be.&lt;/p&gt;
&lt;p&gt;Windows NT 3.1 (July 1993) shipped with the architectural pieces every later boundary entry would rest on: the user-mode/kernel-mode privilege split enforced by the CPU&apos;s ring transitions, securable kernel objects mediated by the reference monitor&apos;s &lt;code&gt;SeAccessCheck&lt;/code&gt; primitive, the Security Account Manager (SAM) database with per-user Security Identifiers (SIDs), discretionary access control lists, and access tokens that travelled with every thread [@openlib-custer-nt]. The kernel boundary -- user-mode code MUST NOT execute kernel code without a syscall transition -- and the user boundary -- one user&apos;s process MUST NOT read another user&apos;s data without permission -- were born here as primitives, two decades before either would be enumerated in a vendor-disclosure document.&lt;/p&gt;
&lt;p&gt;But the architecture was not a doctrine. The boundaries sat &lt;em&gt;implicitly&lt;/em&gt; inside Helen Custer&apos;s &lt;em&gt;Inside Windows NT&lt;/em&gt; (Microsoft Press, 1992) and a handful of internal MSDN reference monographs. A researcher reporting a finding in 1998 could not look up &quot;is this a boundary?&quot; anywhere they were authorised to read.&lt;/p&gt;

A *security boundary* provides a logical separation between the code and data of security domains with different levels of trust [@msrc-criteria]. The defining requirement is that security policy dictates what can pass through the boundary -- a guarantee, not a hint. A *security feature*, by contrast, raises the difficulty of attack but carries no vendor commitment that the separation will hold. This distinction, articulated by Mark Russinovich in 2007, is the load-bearing taxonomy of the entire MSRC triage process.
&lt;p&gt;Three failures accumulated pressure during the implicit-boundary era.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Power Users group.&lt;/strong&gt; Microsoft documented the &lt;code&gt;Power Users&lt;/code&gt; group on Windows 2000 and XP as a &quot;less-privileged-than-administrator&quot; middle tier. Microsoft Knowledge Base article KB 825069 eventually conceded that members could obtain administrator rights through multiple privilege paths (the article has since been retired).The Power Users group survived through Windows Server 2003 and was finally dropped from the default Windows Vista install. The lesson stuck: a tier presented as a separation without a policy-enforced guarantee is not a separation at all. The Russinovich convenience-vs-boundary distinction inherits the lesson. A tier presented operationally as a boundary that turned out never to have been one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The wormable RCE class of 2001-2003.&lt;/strong&gt; Code Red (July 2001) and the RPC DCOM Blaster worm (August 2003) compromised millions of internet-connected Windows hosts [@caida-code-red], [@cert-vu-568148]. Microsoft shipped MS03-026 with Critical severity for the Blaster RPC interface vulnerability [@ms-bulletin-ms03-026]. Operationally, the events made one thing legible: there was no place in the kernel architecture you could point at and say &quot;this is the network boundary that held.&quot; There was a buffer overflow, an unauthenticated RPC call, and a worm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The 2002 Shatter class.&lt;/strong&gt; In August 2002, a researcher posting under the handle &quot;Foon&quot; (Chris Paget) disclosed to NTBugtraq that any process on the interactive desktop could drive any other process&apos;s windows via Win32 messages [@helpnetsecurity-shatter-2002]. That included &lt;code&gt;SYSTEM&lt;/code&gt;-level services with windows on the same desktop, turning every interactive service into a local privilege-escalation surface. Brett Moore generalised the class the following year in &lt;em&gt;Shattering By Example&lt;/em&gt;, walking message types like &lt;code&gt;WM_SETTEXT&lt;/code&gt;, &lt;code&gt;SB_SETTEXT&lt;/code&gt;, and &lt;code&gt;SB_GETTEXTLENGTH&lt;/code&gt; and turning a one-off bug into a systematic primitive [@exploit-db-21691]. Microsoft&apos;s initial response framed the problem as architectural-by-design rather than as a vulnerability. The community could not predict that response, because the boundary was nowhere written down.&lt;/p&gt;

timeline
    title Pre-doctrine era (NT 3.1 to Vista RTM)
    1993 : Windows NT 3.1 ships with SeAccessCheck and per-user SIDs
    1995 : Windows NT 3.51 and the SAM database stabilise
    1996 : Windows NT 4.0 ships with the Power Users group
    2000 : Windows 2000 introduces Active Directory
    2001 : Code Red worm compromises IIS hosts at internet scale
    2002 : Chris Paget discloses Shatter via NTBugtraq
    2002 : Bill Gates Trustworthy Computing memo reorders Microsoft priorities
    2003 : Brett Moore generalises Shatter in Shattering By Example
    2003 : RPC DCOM Blaster worm and MS03-026
    2006 : Russinovich joins Microsoft via Winternals acquisition
    2006 : Windows Vista RTM ships with UAC, MIC, UIPI, and Session 0 isolation
    2007 : Russinovich promoted to Technical Fellow
&lt;p&gt;The combined pressure forced Bill Gates&apos;s January 15, 2002 &lt;em&gt;Trustworthy Computing&lt;/em&gt; memo -- &lt;em&gt;&quot;Trustworthy Computing is the highest priority for all the work we are doing&quot;&lt;/em&gt; [@wired-twc-memo]. The memo did not itself contain a boundary taxonomy. It reorganised engineering priorities so that one could be written.&lt;/p&gt;
&lt;p&gt;By the November 2006 Vista launch, the mechanisms were in the box. Windows Vista shipped with User Account Control, the linked-token split, Mandatory Integrity Control, the User Interface Privilege Isolation (UIPI) shield, and Session 0 isolation [@ms-news-vista-launch]. By June 2007, those mechanisms had names. The document the next two decades of Windows vulnerability disclosure would route through was about to be written -- not by an MSRC document committee, but by a single Technical Fellow Microsoft had promoted to the title five months earlier.&lt;/p&gt;
&lt;h2&gt;3. Russinovich, June 2007, and the Birth of the Distinction&lt;/h2&gt;
&lt;p&gt;In the June 2007 issue of &lt;em&gt;TechNet Magazine&lt;/em&gt;, Mark Russinovich -- promoted to Technical Fellow that January, after joining Microsoft via the July 2006 Winternals acquisition -- published a single article that would dictate the disposition of every Windows vulnerability filed for the next nineteen years. The article was &lt;em&gt;Inside Windows Vista User Account Control&lt;/em&gt; [@russinovich-vista-uac-wayback]. Its load-bearing section, &lt;em&gt;Elevations and Security Boundaries&lt;/em&gt;, ran two paragraphs.&lt;/p&gt;

It&apos;s important to be aware that UAC elevations are conveniences and not security boundaries. A security boundary requires that security policy dictates what can pass through the boundary. User accounts are an example of a security boundary in Windows because one user can&apos;t access the data belonging to another user without having that user&apos;s permission. -- Mark Russinovich, *Inside Windows Vista User Account Control*, TechNet Magazine, June 2007
&lt;p&gt;The article was first published on TechNet on May 23, 2007 and ran in the June issue of the magazine [@russinovich-vista-uac-announce]. That sentence is the doctrinal origin point. Three architectural ideas appear in it: boundaries exist, they are different from features, and UAC sits on the feature side.&lt;/p&gt;
&lt;p&gt;Russinovich then walked the structural reason. The Vista UAC split-token model shares a great deal between the standard-user token and the elevated-administrator token [@russinovich-vista-uac-wayback]: the same SID, the same &lt;code&gt;%USERPROFILE%&lt;/code&gt; directory, the same &lt;code&gt;HKEY_CURRENT_USER&lt;/code&gt; registry hive, the same logon session, and the same DOS device object directory. Those shared resources are the reason the elevation path cannot be a &lt;em&gt;guaranteed&lt;/em&gt; separation. An attacker running at standard integrity on the same desktop can interact with the elevated process&apos;s window station, its named objects, and its user-writable files. The convenience is real -- prompting before a privileged operation is a high-friction barrier against accidental elevation. The guarantee is not.&lt;/p&gt;

flowchart TD
    User[Interactive user logs on]
    User --&amp;gt; Linked[Linked-token logon]
    Linked --&amp;gt; Standard[Standard-user token]
    Linked --&amp;gt; Elevated[Elevated administrator token]
    subgraph Shared[Shared resources between the two tokens]
        SID[Same user SID]
        Profile[Same USERPROFILE]
        HKCU[Same HKCU hive]
        Session[Same logon session]
        Desktop[Same interactive desktop]
    end
    Standard -.-&amp;gt; Shared
    Elevated -.-&amp;gt; Shared
    Shared --&amp;gt; Verdict[No guaranteed separation = feature, not boundary]
&lt;p&gt;The article identifies the &lt;em&gt;real&lt;/em&gt; boundaries Windows enforces -- the user boundary (cross-user access requires explicit permission), the kernel boundary (the syscall gate), and the process boundary (one process cannot read another&apos;s memory without &lt;code&gt;PROCESS_VM_READ&lt;/code&gt; access) -- as the lines policy &lt;em&gt;does&lt;/em&gt; enforce. UAC sits among the features that make those boundaries cheaper to defend, not among the boundaries themselves.&lt;/p&gt;

The widely-circulated press narrative is that Microsoft *initially* called UAC a security boundary and *retracted* that classification in 2009 after the Zheng and Rivera research. This framing is false. Russinovich&apos;s June 2007 article already said verbatim that UAC elevations are &quot;conveniences and not security boundaries.&quot; The position was on the record from Vista&apos;s first six months, two years before any 2009 Windows 7 beta disclosure. What Microsoft changed in 2009 was *implementation* -- the UAC slider began running at High integrity, UAC-settings changes began prompting -- not the classification. The Russinovich Windows 7 follow-up restated the original position word for word [@ms-learn-russinovich-win7].
&lt;p&gt;The historical record matters because so much downstream doctrine rests on it. In late January 2009, Long Zheng and Rafael Rivera demonstrated a Windows 7 beta UAC auto-elevation flaw via &lt;code&gt;rundll32.exe&lt;/code&gt;: Microsoft-signed binaries inside &lt;code&gt;%SystemRoot%&lt;/code&gt; auto-elevated when invoked from a process holding the user&apos;s administrator token, and &lt;code&gt;rundll32.exe&lt;/code&gt; accepted arbitrary DLL paths [@crn-uac-flaw-2009].The original &lt;code&gt;istartedsomething.com&lt;/code&gt; post and the Ars Technica contemporary coverage have since been reorganised away by both sites; the CRN contemporary report (cited here) preserves the disclosure timeline, the &lt;code&gt;rundll32.exe&lt;/code&gt; mechanism, and the Microsoft response. The historical claim is uncontested. What is contested is the framing of Microsoft&apos;s response, which primary sources show was implementation hardening, not a change in classification. Microsoft&apos;s &lt;em&gt;initial&lt;/em&gt; reply (&quot;by design; UAC is not a security boundary&quot;) was operationally consistent with the June 2007 article. The &lt;em&gt;engineering&lt;/em&gt; response that followed -- UAC slider promoted to High integrity, UAC-settings changes prompting -- was implementation hardening, not reclassification. The doctrinal position did not move. Russinovich&apos;s July 2009 follow-up, &lt;em&gt;Inside Windows 7 User Account Control&lt;/em&gt;, restated the convenience-vs-boundary argument with the same architectural reasoning [@ms-learn-russinovich-win7].&lt;/p&gt;
&lt;p&gt;Russinovich&apos;s June 2007 article gave the community three ideas: boundaries exist; they are different from features; UAC sits on the feature side. The next step was to publish the table. That took roughly five years.&lt;/p&gt;
&lt;h2&gt;4. The Document Accumulates&lt;/h2&gt;
&lt;p&gt;Between 2007 and 2026, the boundary table grew by accretion. One new entry per Windows generation. The shape of the doctrine changed three times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation 1 -- scattered prose (2007 to roughly 2010).&lt;/strong&gt; Russinovich&apos;s June 2007 article, plus the July 2009 &lt;em&gt;Inside Windows 7 User Account Control&lt;/em&gt; restatement, articulated the convenience-vs-boundary doctrine without a public enumeration. A reader of the two articles could correctly predict the disposition of a UAC bypass, and could correctly predict that user-to-user data access was a CVE-eligible boundary violation. They could not, from those articles alone, predict the disposition of a network-stack RCE, an AppContainer escape, or a guest-to-host virtual-machine break. The doctrine was consistent but it was not yet a document.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation 2 -- the enumerated MSRC page (roughly 2010 to 2015).&lt;/strong&gt; The &lt;code&gt;microsoft.com/en-us/msrc/windows-security-servicing-criteria&lt;/code&gt; page appears in something close to its current form. It states the two-question triage rule. It includes the verbatim definition of a security boundary. It enumerates a list of boundaries -- process, kernel, network, session, user, AppContainer, virtual machine, web browser -- and a parallel list of security features. The doctrine moves from a single magazine article to a vendor commitment with a URL [@msrc-criteria].The first-publication date of the page is folk knowledge. Wayback Machine snapshots survive from 2017 onward at the current URL slug. No Microsoft announcement post pins the exact date the page first appeared, so the &quot;roughly 2010&quot; figure is a community estimate rather than a documented birthday.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation 3 -- VTL added (2015 to 2017).&lt;/strong&gt; Windows 10 1507 (RTM July 29, 2015) shipped Virtualization-Based Security, the Secure Kernel, Isolated User Mode (IUM), and the first canonical Trustlet -- LsaIso, the Credential Guard isolated LSA process. The boundary table grew a row whose enforcement primitive is the hypervisor itself: VTL0 (the normal kernel) cannot read or modify VTL1 (the Secure Kernel and IUM) without going through documented hypercalls [@ms-learn-vbs-ci]. The strongest local boundary on the system is now classified, not orphaned.&lt;/p&gt;

A *Trustlet* is a process that runs inside Isolated User Mode (IUM) -- the user-mode portion of VTL1 -- protected by the hypervisor from the normal-kernel VTL0 [@ms-learn-vbs-ci]. The canonical example is LsaIso, the Isolated LSA process that holds the credential material Credential Guard protects. Even a kernel-mode attacker in VTL0 cannot read the memory of a Trustlet running in VTL1; the hypervisor&apos;s second-level address translation tables do not map VTL1 pages into VTL0. Cross-VTL communication routes through Virtual Secure Mode hypercalls (`HvCallVtlCall` and `HvCallVtlReturn`), which are the only documented channel.
&lt;p&gt;&lt;strong&gt;Generation 4 -- stabilised reference (2018 to 2024).&lt;/strong&gt; No new rows. The boundary list is treated as a stable reference that MSRC, researchers, and the community all cite. Three flagship community projects encode the doctrine in their names and structure during this period: hfiref0x&apos;s UACMe (more than 80 catalogued UAC bypasses, none of which receive CVE numbers) [@uacme]; Gabriel Landau&apos;s &lt;em&gt;ItsNotASecurityBoundary&lt;/em&gt; GitHub repository, whose name is an explicit homage to MSRC&apos;s admin-to-kernel policy [@landau-itsnotasb-gh]; and Alon Leviev&apos;s &lt;a href=&quot;https://paragmali.com/blog/windows-downdate-when-the-update-itself-is-the-attack/&quot; rel=&quot;noopener&quot;&gt;Windows Downdate&lt;/a&gt;, presented at Black Hat USA 2024 [@leviev-downdate-orig]. The community-side institutional memory now exists outside MSRC, augmented by Matt Miller&apos;s BlueHat IL keynotes (notably the 2019 &lt;em&gt;Trends, challenges, and shifts in software vulnerability mitigation&lt;/em&gt; talk) that carried the boundary-and-mitigations story to the security-conference audience in parallel with the MSRC page [@miller-bluehat-il-2019].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generation 5 -- Administrator Protection (2024 to 2026).&lt;/strong&gt; On November 19, 2024, David Weston announced &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Administrator Protection&lt;/a&gt; at Microsoft Ignite, framing it as part of the Windows Resiliency Initiative [@weston-ignite-2024]. The Microsoft Learn page carries the verbatim doctrinal statement: &lt;em&gt;&quot;Administrator protection introduces a new security boundary with support to fix any reported security bugs&quot;&lt;/em&gt; [@ms-learn-admin-protection]. This is the first new boundary entry added to the servicing-criteria table in nearly a decade.&lt;/p&gt;

The *System Managed Administrator Account* is the elevation primitive at the heart of Administrator Protection [@ms-learn-admin-protection]. Each interactive user with administrator privileges has a hidden, system-generated, profile-separated SMAA companion account provisioned in the SAM database. Elevations route through Windows Hello consent and run against the SMAA token, which has a *different* SID, a *different* profile directory, and a *different* logon session from the user&apos;s standard-user token. The token is destroyed when the elevated process ends. The shared-resources structural reason UAC could not be a boundary no longer applies, because the SMAA token does not share those resources with the user&apos;s standard token.

timeline
    title Five generations of the boundary doctrine
    section Generation 1 - Scattered prose (2007 to 2010)
        2007 : Russinovich publishes the convenience-vs-boundary distinction
        2009 : Long Zheng and Rafael Rivera force UAC implementation hardening
        2009 : Russinovich Windows 7 follow-up restates the doctrine
    section Generation 2 - Enumerated page (2010 to 2015)
        2010 : MSRC servicing-criteria page goes live with two-question rule
        2014 : hfiref0x publishes UACMe v1.0
        2014 : CVE-2014-4113 Win32k EoP becomes canonical kernel-boundary case
    section Generation 3 - VTL added (2015 to 2017)
        2015 : Windows 10 1507 ships VBS, Secure Kernel, Credential Guard
        2016 : Edge AppContainer sandbox cements the browser boundary entry
        2017 : EternalBlue and MS17-010 anchor the network-boundary case study
    section Generation 4 - Stabilised reference (2018 to 2024)
        2023 : Landau PPLFault names PPL as not a security boundary
        2024 : Landau ItsNotASecurityBoundary homages MSRC policy in repo name
        2024 : Leviev Windows Downdate at Black Hat USA 2024
    section Generation 5 - Administrator Protection (2024 to 2026)
        2024 : Ignite keynote announces Administrator Protection as new boundary
        2025 : Developer-blog detail post lands
        2025 : October non-security update KB5067036 rolls out and is reverted
        2026 : Forshaw publishes nine pre-GA bypasses via Project Zero
&lt;p&gt;The December 1, 2025 rollout revert of the October 2025 non-security update KB5067036 is an application-compatibility decision, not a doctrinal one [@ms-learn-admin-protection]. The Microsoft Learn page now reads that the feature will roll out &quot;at a later date.&quot; The boundary classification stands; the rollout schedule slipped.&lt;/p&gt;
&lt;p&gt;Five generations later, the boundary table has nine entries. The next section walks the parallel evolution that nobody outside MSRC reads first -- the not-a-boundary table -- because that is the table that decides what does &lt;em&gt;not&lt;/em&gt; get a CVE.&lt;/p&gt;
&lt;h2&gt;5. The Not-a-Boundary Table Also Accumulates&lt;/h2&gt;
&lt;p&gt;For every boundary Microsoft has added to the servicing-criteria table, there is a primitive that did not make the list. The not-a-boundary table tells a parallel story: primitives that attackers repeatedly tried to make into boundaries, and that Microsoft repeatedly classified as features. Seven entries, each tied to a load-bearing research artifact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User Account Control (since June 2007).&lt;/strong&gt; The original not-a-boundary entry; see Section 8.1 for the full treatment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Driver Signing / Code Integrity / KMCS (since the Vista x64 kernel-mode driver signing requirement).&lt;/strong&gt; Local administrator can, by design, load drivers; see Section 8.2. The &quot;bring your own vulnerable driver&quot; (BYOVD) catalog and the &lt;a href=&quot;https://www.loldrivers.io/&quot; rel=&quot;noopener&quot;&gt;LOLDrivers project&lt;/a&gt; are the institutional memory [@loldrivers].&lt;/p&gt;

*BYOVD* is the attack pattern in which a privileged user installs a legitimately-signed driver that happens to contain an exploitable vulnerability, then exploits the driver to obtain arbitrary kernel-mode code execution. Because Driver Signing is on the security-feature side of the doctrine, a BYOVD chain that exploits a signed driver does not, on its own, receive a CVE attributed to Microsoft -- the driver vendor may receive one, but Microsoft does not classify the loadability of the driver as a boundary crossing. The Lazarus Group&apos;s use of expired-but-signed drivers and the broader [LOLDrivers catalog](https://www.loldrivers.io/) are the operational embodiment of this classification [@loldrivers].
&lt;p&gt;&lt;strong&gt;Microsoft Defender / Antimalware.&lt;/strong&gt; A heuristic detection layer cannot, by construction, be a boundary. Defender bypasses earn CVEs only when they also cross another boundary (see Section 8.3 for the Tavis Ormandy 2014 to 2017 network-boundary pattern; the flagship CVE-2017-0290 &lt;em&gt;crazy bad&lt;/em&gt; MsMpEng RCE is the canonical example [@ms-advisory-4022344]).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HVCI / Memory Integrity.&lt;/strong&gt; A feature enforced &lt;em&gt;at&lt;/em&gt; the VTL boundary, not itself a boundary; see Section 8.4.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Protected Process Light (PPL).&lt;/strong&gt; Introduced in Windows 8.1 to protect anti-malware services and other specially-signed processes from administrator tampering [@ms-learn-am-ppl]. Gabriel Landau&apos;s PPLFault research preserves the verbatim MSRC position that PPL is not a security boundary; see Section 8.5 for the full Landau quotation [@landau-pplfault].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Administrator-to-kernel privilege escalation.&lt;/strong&gt; Local administrator can, by design, load drivers; see Section 8.6. Gabriel Landau named his False File Immutability research repository &lt;em&gt;ItsNotASecurityBoundary&lt;/em&gt; as an explicit homage to MSRC&apos;s policy [@landau-itsnotasb-gh]; Alon Leviev&apos;s October 2024 Downdate follow-up contains the most recent verbatim Microsoft quotation of this position (see Section 8.6) [@leviev-downdate-update].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Same-user post-authentication.&lt;/strong&gt; Once a process has executed under a user&apos;s session, it inherits that user&apos;s trust; per-process isolation within the same user is not a declared boundary. James Forshaw&apos;s June 3, 2024 &lt;em&gt;Working your way Around an ACL&lt;/em&gt; post is the doctrinal anchor (see Section 8.7 for the verbatim formulation) [@forshaw-tyranid-acl].&lt;/p&gt;
&lt;p&gt;Here are the two tables side by side.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The boundary table (nine entries)&lt;/th&gt;
&lt;th&gt;What enforces it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;NDIS/TCP-IP/SMB/RPC stack; remote callers are the lowest trust tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel&lt;/td&gt;
&lt;td&gt;SYSCALL/SYSRET transition, syscall service table, Driver Verifier, HVCI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeAccessCheck&lt;/code&gt; on &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;, &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, &lt;code&gt;NtDuplicateObject&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session&lt;/td&gt;
&lt;td&gt;Session 0 vs Session 1+; per-session &lt;code&gt;BaseNamedObjects&lt;/code&gt; namespace isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User&lt;/td&gt;
&lt;td&gt;Per-user SIDs in SAM, file-system DACL inheritance, per-user &lt;code&gt;HKCU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppContainer&lt;/td&gt;
&lt;td&gt;LowBox token + capability SID list + DENY-by-default ACLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Virtual machine (guest-to-host)&lt;/td&gt;
&lt;td&gt;Hyper-V root partition, VMBus, synthetic device model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VTL (VTL0 to VTL1)&lt;/td&gt;
&lt;td&gt;Hypervisor-enforced SLAT (Intel EPT / AMD NPT); VSL hypercalls as the only cross-VTL channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Administrator Protection elevation path (2025)&lt;/td&gt;
&lt;td&gt;SMAA with separate SID, profile, logon session; Windows Hello consent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The not-a-boundary table (seven entries)&lt;/th&gt;
&lt;th&gt;Why it is a feature, not a boundary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;UAC&lt;/td&gt;
&lt;td&gt;Split token shares SID, profile, session, namespace; no policy guarantee&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Driver Signing / Code Integrity / KMCS&lt;/td&gt;
&lt;td&gt;Administrators can install drivers by design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Defender / Antimalware&lt;/td&gt;
&lt;td&gt;Heuristic detection cannot guarantee detection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HVCI / Memory Integrity&lt;/td&gt;
&lt;td&gt;A feature enforced &lt;em&gt;at&lt;/em&gt; the VTL boundary, not itself a boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protected Process Light (PPL)&lt;/td&gt;
&lt;td&gt;Hardened against admin tampering, not policy-guaranteed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Administrator-to-kernel privilege escalation&lt;/td&gt;
&lt;td&gt;Admin loads drivers; drivers run in kernel; structural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same-user post-authentication&lt;/td&gt;
&lt;td&gt;One user, one trust scope; per-process isolation not declared&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The not-a-boundary table is the doctrine &lt;em&gt;learning&lt;/em&gt;. Each new entry is a primitive an attacker class repeatedly tried to treat as a boundary, and Microsoft explicitly classified as a feature so the operational question -- &lt;em&gt;does this report receive a CVE?&lt;/em&gt; -- has a stable answer.&lt;/p&gt;
&lt;p&gt;Two tables. Sixteen total entries. One operational question per report. But how does Microsoft actually apply this -- and why is the application &lt;em&gt;correct&lt;/em&gt;, not a cop-out?&lt;/p&gt;
&lt;h2&gt;6. The Two-Question Triage Rule&lt;/h2&gt;
&lt;p&gt;Here is the load-bearing engineering decision of the entire document: the classification question is &lt;em&gt;decoupled&lt;/em&gt; from the severity question. Microsoft does not ask &quot;is this report important enough to fix&quot; as a single judgment call. It asks two separate questions, and both have to be answered yes.&lt;/p&gt;
&lt;p&gt;The MSRC servicing-criteria page states the rule verbatim:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;The criteria used by Microsoft when evaluating whether to provide a security update or guidance for a reported vulnerability involves answering two key questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Does the vulnerability violate the goal or intent of a security boundary or a security feature?&lt;/li&gt;
&lt;li&gt;Does the severity of the vulnerability meet the bar for servicing?&quot; [@msrc-criteria]&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The second question is parameterised by a separate document, the &lt;em&gt;Microsoft Vulnerability Severity Classification for Windows&lt;/em&gt;, often called the &lt;em&gt;Windows Bug Bar&lt;/em&gt; [@msrc-bugbar]. The Bug Bar defines four severity levels -- Critical, Important, Moderate, Low -- with worked examples for each vulnerability type (remote code execution, elevation of privilege, information disclosure, denial of service, spoofing, tampering). It also pivots between server and client severity. A bug that earns Critical on a server can earn Important on a client, and the disposition can change accordingly.&lt;/p&gt;
&lt;p&gt;The first question answers the &lt;em&gt;eligible-by-doctrine&lt;/em&gt; half. A boundary crossing is in scope. A feature defeat is &lt;em&gt;also&lt;/em&gt; in scope -- Microsoft does service security features when the severity bar is met, but the path is different. The second question answers &lt;em&gt;severity-meets-bar&lt;/em&gt;. Critical and Important on the Bug Bar route to a security update via Patch Tuesday (or out-of-band when the impact warrants it). Moderate and Low route to &quot;consider for the next version or release of Windows.&quot;&lt;/p&gt;
&lt;p&gt;The doctrine has an explicit relief valve.&lt;/p&gt;

If the answer to both questions is yes, then Microsoft&apos;s intent is to address the vulnerability through a security update and/or guidance ... If the answer to either question is no, then by default the vulnerability will be considered for the next version or release of Windows but will not be addressed through a security update or guidance, though exceptions may be made. -- Microsoft Security Servicing Criteria for Windows [@msrc-criteria]
&lt;p&gt;Notice the work the &lt;em&gt;and&lt;/em&gt; is doing. Two independent gates, both required. A feature defeat with Critical impact (for example, a Defender bypass that enables ransomware deployment at scale) &lt;em&gt;can&lt;/em&gt; still ship as a Patch Tuesday item -- but it does so via the second question, with the explicit exception clause as the framing. A boundary crossing with Low severity (a process-isolation primitive bypass that requires preconditions no realistic attacker would arrange) might &lt;em&gt;not&lt;/em&gt; ship as a bulletin.&lt;/p&gt;

flowchart TD
    Report[&quot;Vulnerability report arrives at MSRC&quot;]
    Q1{&quot;Q1: Does it violate a boundary or feature?&quot;}
    Q2{&quot;Q2: Does severity meet the bar (Critical or Important)?&quot;}
    Excp{&quot;Exception applies?&quot;}
    Service[&quot;Service via security update / Patch Tuesday&quot;]
    Defer[&quot;By design / consider for next release&quot;]
    Report --&amp;gt; Q1
    Q1 -- &quot;No&quot; --&amp;gt; Excp
    Q1 -- &quot;Yes&quot; --&amp;gt; Q2
    Q2 -- &quot;Yes&quot; --&amp;gt; Service
    Q2 -- &quot;No&quot; --&amp;gt; Excp
    Excp -- &quot;Yes&quot; --&amp;gt; Service
    Excp -- &quot;No&quot; --&amp;gt; Defer
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Classification and severity are decoupled. The &lt;em&gt;and&lt;/em&gt; of the two questions is the doctrine. Every &quot;by design&quot; reply the community has ever received is generated by this exact rule, applied with the published boundary list, the published feature list, the published severity bar, and the published exception clause.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The rule, restated as runnable pseudocode, looks like this. Try the three example inputs to see the doctrine in action.&lt;/p&gt;
&lt;p&gt;{`
// The MSRC servicing-criteria triage, in pseudocode.
const BOUNDARIES = new Set([
  &quot;network&quot;, &quot;kernel&quot;, &quot;process&quot;, &quot;session&quot;, &quot;user&quot;,
  &quot;appcontainer&quot;, &quot;vm&quot;, &quot;vtl&quot;, &quot;administrator-protection&quot;,
]);
const FEATURES = new Set([
  &quot;uac&quot;, &quot;defender&quot;, &quot;hvci&quot;, &quot;driver-signing&quot;,
  &quot;ppl&quot;, &quot;admin-to-kernel&quot;, &quot;same-user&quot;,
]);&lt;/p&gt;
&lt;p&gt;function disposition(report) {
  const { primitive, severity, exception } = report;
  const isBoundary = BOUNDARIES.has(primitive);
  const isFeature  = FEATURES.has(primitive);
  const violatedSomething = isBoundary || isFeature;
  const meetsBar = (severity === &quot;Critical&quot; || severity === &quot;Important&quot;);
  if (violatedSomething &amp;amp;&amp;amp; meetsBar) return &quot;Service via security update&quot;;
  if (exception)                     return &quot;Service via security update (exception)&quot;;
  return &quot;By design / consider for next version&quot;;
}&lt;/p&gt;
&lt;p&gt;// Example 1: a fresh UAC bypass (consent.exe registry hijack)
console.log(&quot;UAC bypass    -&amp;gt;&quot;,
  disposition({ primitive: &quot;uac&quot;, severity: &quot;Important&quot; }));&lt;/p&gt;
&lt;p&gt;// Example 2: a pre-auth SMB RCE like CVE-2017-0144 EternalBlue
console.log(&quot;SMB pre-auth  -&amp;gt;&quot;,
  disposition({ primitive: &quot;network&quot;, severity: &quot;Critical&quot; }));&lt;/p&gt;
&lt;p&gt;// Example 3: a PPLFault-class bypass loading unsigned code into a PPL
console.log(&quot;PPLFault      -&amp;gt;&quot;,
  disposition({ primitive: &quot;ppl&quot;, severity: &quot;Important&quot; }));
`}&lt;/p&gt;
&lt;p&gt;Run it. The UAC bypass returns &quot;Service via security update&quot; only because UAC is on the &lt;em&gt;feature&lt;/em&gt; table -- so the first question is yes (a feature defeat) and the second question is yes (Important severity) -- and &lt;em&gt;both&lt;/em&gt; questions matter. If you change the severity to Moderate the disposition flips to &quot;by design / consider for next version.&quot; If you change the primitive to one that is not on either table, the disposition again becomes &quot;by design&quot; unless the exception clause fires.&lt;/p&gt;
&lt;p&gt;That is the entire MSRC triage rule. Nine boundary entries, seven feature entries, one severity scheme, one exception clause. Every &quot;by design&quot; reply the community has ever received is generated by this exact rule.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A single-question rule would collapse the doctrine. &quot;Is this report important enough to fix&quot; without a published classification turns every disposition into MSRC engineers&apos; personal judgment. &quot;Is this a boundary crossing&quot; without a severity gate would force Microsoft to ship a Patch Tuesday bulletin for every low-impact boundary-adjacent finding, including the ones with no realistic attack path. Decoupling lets Microsoft commit to a published taxonomy on the first question while retaining engineering judgment on the second, with the exception clause as the explicit relief valve in either direction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With the rule in hand, the next three sections walk the parameters of the rule -- the nine boundary entries, the seven feature entries, and the bounty schedule that mechanically follows both -- at one consistent pedagogical depth per entry.&lt;/p&gt;
&lt;h2&gt;7. The Nine Boundaries, Walked&lt;/h2&gt;
&lt;p&gt;One subsection per boundary. Each follows the same template: the architectural primitive that enforces the boundary, the canonical CVE-eligible violation pattern, and one verified historical case study.&lt;/p&gt;
&lt;h3&gt;7.1 Network boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; The NDIS / TCP-IP / SMB / RPC / HTTP server stacks treat remote callers as the lowest trust tier. Any code that processes attacker-influenced bytes off the wire before authenticating the caller sits at this boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; Pre-authentication remote code execution. A remote attacker reaches &lt;code&gt;SYSTEM&lt;/code&gt; (or any local code execution) without first satisfying an authentication primitive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; EternalBlue, CVE-2017-0144, MS17-010. The SMBv1 server in Windows Vista SP2 through Windows 10 1607 accepted crafted packets that triggered a memory-corruption primitive in the kernel-mode driver, yielding pre-authentication remote code execution [@nvd-2017-0144]. NSA-developed; Shadow Brokers-leaked; weaponised within weeks by WannaCry and NotPetya. Critical severity, mandatory patch, the canonical network-boundary case in the entire taxonomy. SMBGhost (CVE-2020-0796) [@nvd-2020-0796] and PrintNightmare (CVE-2021-34527) [@nvd-2021-34527] are the supporting cases. PrintNightmare is particularly instructive because it crosses &lt;em&gt;two&lt;/em&gt; boundaries simultaneously -- remote code execution via a malicious shared printer driver (network) &lt;em&gt;and&lt;/em&gt; local privilege escalation via the same primitive on the spooler service (kernel).&lt;/p&gt;
&lt;h3&gt;7.2 Kernel boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; The user-mode-to-kernel-mode transition is enforced by the CPU&apos;s privilege rings and the SYSCALL/SYSRET instruction pair. The syscall service table is the only legal way to enter the kernel. Driver Verifier and HVCI run on top of this transition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; User-mode code achieves kernel-mode code execution without using the legitimate syscall interface, typically by exploiting a memory-safety bug in a kernel driver that the user-mode caller can reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; CVE-2014-4113, the Win32k.sys &lt;code&gt;tagWND&lt;/code&gt; elevation-of-privilege bug, exploited in the wild in October 2014.The Win32k subsystem is a recurring source of kernel-boundary findings because it processes window-manager state from user mode in kernel context, an architectural choice that predates the boundary doctrine. MS14-058 / KB3000061 was the Patch Tuesday fix on October 14, 2014 [@ms-bulletin-ms14-058]. The bug allowed a local user to run arbitrary code in kernel mode by crafting calls to the kernel-mode portion of the Win32 subsystem [@nvd-2014-4113]. Important severity; canonical kernel-boundary case; the kind of finding the doctrine was built to service cleanly.&lt;/p&gt;

*`SeAccessCheck`* is the Windows kernel&apos;s reference-monitor function that decides whether a thread holding a specific access token may perform a requested access against a securable object. It takes the object&apos;s security descriptor, the requesting token, and the desired access mask; it returns granted access or `STATUS_ACCESS_DENIED`. Every cross-process memory access, every securable kernel-object open, and every registry-key access ultimately routes through this function. It is the architectural enforcement point for both the process boundary and the user boundary.
&lt;h3&gt;7.3 Process boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; &lt;code&gt;SeAccessCheck&lt;/code&gt; mediates &lt;code&gt;PROCESS_VM_READ&lt;/code&gt;, &lt;code&gt;PROCESS_VM_WRITE&lt;/code&gt;, &lt;code&gt;PROCESS_DUP_HANDLE&lt;/code&gt;, and the access mask passed to &lt;code&gt;NtOpenProcess&lt;/code&gt; [@ms-learn-process-access-rights]. A process cannot read another process&apos;s memory without holding a token that grants the requested access against the target&apos;s security descriptor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; One process reads or writes another process&apos;s address space without having been granted permission.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; Thread injection canon: &lt;code&gt;CreateRemoteThread&lt;/code&gt;, &lt;code&gt;SetWindowsHookEx&lt;/code&gt;, &lt;code&gt;NtMapViewOfSection&lt;/code&gt;. Each violation routes through a documented OS primitive that Microsoft has hardened repeatedly. The hardening culminated in the &lt;a href=&quot;https://paragmali.com/blog/protected-process-light-when-the-administrator-isnt-enough/&quot; rel=&quot;noopener&quot;&gt;Protected Process Light&lt;/a&gt; (PPL) signer-hierarchy enforcement introduced in Windows 8.1, which lets specially-signed processes refuse code injection even from administrator processes [@ms-learn-am-ppl]. PPL itself is on the feature side of the doctrine -- &lt;em&gt;the&lt;/em&gt; canonical example of how the process boundary and PPL interact is the AM-PPL extension that anti-malware vendors use to protect their services from administrator-level interference, which Landau&apos;s research has explored at length [@landau-pplfault].The access-mask argument to &lt;code&gt;NtOpenProcess&lt;/code&gt; is the load-bearing enforcement point. A thread that opens a target process with &lt;code&gt;PROCESS_VM_READ&lt;/code&gt; and then calls &lt;code&gt;ReadProcessMemory&lt;/code&gt; is exercising an &lt;em&gt;audited&lt;/em&gt; boundary crossing; a thread that obtains the target&apos;s handle through a more circuitous route (handle duplication, named-object games) still routes through &lt;code&gt;SeAccessCheck&lt;/code&gt; somewhere. The taxonomy is what gives the audit something to anchor against.&lt;/p&gt;
&lt;h3&gt;7.4 Session boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; Session 0 (system services) is isolated from interactive user sessions (Session 1, Session 2, and so on). Each session has its own &lt;code&gt;\Sessions\&amp;lt;id&amp;gt;\BaseNamedObjects&lt;/code&gt; namespace, its own window station, and its own desktop [@ms-learn-kernel-object-namespaces]. Services that previously ran in the interactive session of the first logged-in user now run in Session 0 with no GUI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; A low-privilege interactive process sends window messages to a &lt;code&gt;SYSTEM&lt;/code&gt;-level service on the same desktop, driving the service&apos;s UI into executing attacker-controlled code paths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; The August 2002 Shatter class, generalised by Brett Moore in &lt;em&gt;Shattering By Example&lt;/em&gt; (2003) [@exploit-db-21691]. Microsoft&apos;s architectural response shipped with Windows Vista: Session 0 isolation. Services were moved to Session 0 with no interactive desktop; user applications run in Session 1 and higher. The Microsoft Learn &lt;em&gt;Interactive Services&lt;/em&gt; page records the engineering decision verbatim: &lt;em&gt;&quot;Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code&quot;&lt;/em&gt; [@ms-learn-interactive-services].&lt;/p&gt;
&lt;h3&gt;7.5 User boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; Per-user SIDs in the SAM database (or the domain database for joined hosts), file-system DACL inheritance, per-user &lt;code&gt;HKCU&lt;/code&gt; registry hives, the user profile directory, and the access token that travels with every thread [@ms-learn-access-tokens]. A process running as one user cannot access objects owned by another user unless the DACL explicitly permits it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; One user&apos;s process reads another user&apos;s data without permission. Classic targets: &lt;code&gt;NTUSER.DAT&lt;/code&gt; of another logged-on user, the other user&apos;s &lt;code&gt;%USERPROFILE%&lt;/code&gt;, the other user&apos;s tokens via &lt;code&gt;NtOpenProcess&lt;/code&gt; or &lt;code&gt;NtOpenProcessToken&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; The user boundary is the &lt;em&gt;example&lt;/em&gt; Russinovich uses in his June 2007 article when contrasting boundaries with conveniences [@russinovich-vista-uac-wayback]. User-to-user separation is the canonical &quot;yes, this is a boundary&quot; case in the entire taxonomy; the closest &lt;em&gt;same-user&lt;/em&gt; counter-example -- Forshaw&apos;s June 2024 Recall ACL post -- explicitly notes that &lt;em&gt;user-to-user&lt;/em&gt; would be a boundary, but &lt;em&gt;same-user&lt;/em&gt; per-process isolation is not [@forshaw-tyranid-acl]. The boundary granularity matters: the same primitive class can be a boundary at one granularity and a non-boundary at a finer granularity.&lt;/p&gt;

This is the cleanest illustration of how granularity drives classification. *User to user* is a boundary -- Alice&apos;s process cannot read Bob&apos;s data without explicit permission. *Same user, process to process* is not a boundary -- Alice&apos;s text editor, Alice&apos;s browser, and Alice&apos;s media player all run with Alice&apos;s identity and any one of them can read the others&apos; resources. PPL adds a feature-class barrier within the same user, but Microsoft has explicitly classified PPL as not a boundary [@landau-pplfault]. The taxonomy is consistent: the same primitive (the access token) can guarantee separation across user identities and *not* guarantee separation between two processes that share an identity.
&lt;h3&gt;7.6 AppContainer / sandbox boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; A &lt;a href=&quot;https://paragmali.com/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/&quot; rel=&quot;noopener&quot;&gt;LowBox token&lt;/a&gt; with a capability SID list; default-DENY ACLs against any object that has not explicitly granted the relevant capability; restricted access to the file system, the registry, named objects, and the network stack. AppContainer is built on top of the Mandatory Integrity Control mechanism but is strictly more restrictive than a Low IL token.&lt;/p&gt;

*MIC* is the Windows mechanism that assigns each securable object and each access token an integrity level: Untrusted, Low, Medium (the default for standard users), High (the default for administrators), and System. The access-check rules state that a lower-integrity subject cannot write to a higher-integrity object, regardless of DACL permissions. Introduced in Vista alongside UIPI, MIC underpins both the AppContainer boundary and the UAC feature.
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; A LowBox or AppContainer process escapes its capability list to perform operations the container was supposed to deny.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; Edge sandbox escape canon, from the Anniversary Update (Windows 10 1607, August 2016) forward. AppContainer as a mechanism predates 1607 (it shipped in Windows 8 alongside the Modern UI app model, where it was originally named &lt;em&gt;LowBox&lt;/em&gt;) [@ms-learn-appcontainer-legacy], but the Edge sandbox is the flagship demonstration that AppContainer can serve as a browser-grade sandbox boundary. Edge sandbox escapes route through MSRC as boundary violations and earn the Microsoft Edge Bounty Program payouts [@msrc-bounty-edge].&lt;/p&gt;
&lt;h3&gt;7.7 Virtual machine (guest-to-host) boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; Hyper-V&apos;s root partition versus L1 guest partitions, the &lt;a href=&quot;https://paragmali.com/blog/hyper-v-enlightenments-vmbus-and-the-synthetic-device-model/&quot; rel=&quot;noopener&quot;&gt;VMBus&lt;/a&gt; inter-partition channel, the synthetic device model, the virtualization-service-provider (VSP) and virtualization-service-client (VSC) split. A guest VM communicates with the host only via VMBus, and only through the synthetic devices the host exposes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; A guest VM achieves code execution on the host (or in a sibling guest).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; CVE-2024-21407, a use-after-free in a Hyper-V root-partition component reachable from a guest VM (the MSRC advisory does not name the component), shipped as a Critical-severity Patch Tuesday item on March 12, 2024 [@nvd-2024-21407]. The guest-to-host class pays the highest bounty in the Microsoft Bounty Programs portfolio.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Microsoft Hyper-V Bounty Program pays $5,000 to $250,000 USD for guest-to-host escape vulnerabilities [@msrc-bounty-hyperv]. That is the highest single-finding payout in the Microsoft bounty catalogue [@msrc-bounty-root], and it maps directly to the VM boundary on the servicing-criteria table. The bounty schedule is one of the cleanest market-side confirmations available that the boundary list drives every other operational artifact: the boundary that protects the most consequential trust separation (cloud tenant from cloud tenant on shared hypervisor hardware) also pays the most.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;7.8 VTL (VTL0 to VTL1) boundary&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; Hypervisor-enforced second-level address translation (SLAT, implemented as Intel EPT or AMD NPT) separates the address spaces of VTL0 (the normal kernel and user mode) and VTL1 (the Secure Kernel and Isolated User Mode). The hypervisor mediates every cross-VTL access. The only documented cross-VTL channel is the Virtual Secure Mode hypercall pair (&lt;code&gt;HvCallVtlCall&lt;/code&gt; and &lt;code&gt;HvCallVtlReturn&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; A VTL0 attacker observes or modifies VTL1 memory or Trustlet state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; &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; / Isolated LSA is the canonical VTL1 success story. The LSA Trustlet (LsaIso) holds the credential material Credential Guard protects; even an &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt;-class attacker in VTL0 cannot read those credentials because the relevant pages are not mapped into the VTL0 kernel&apos;s address space at all [@ms-learn-vbs-ci]. The doctrine has a row that says so, and the bounty schedule pays Critical-class amounts under the Windows Insider Preview Bounty Program for VTL violations.&lt;/p&gt;

*Virtual Trust Levels* are the hypervisor-enforced trust tiers Hyper-V introduces inside a single guest partition [@ms-learn-vbs-ci]. VTL0 is the &quot;normal&quot; Windows world: the regular kernel, regular drivers, and regular user-mode processes. VTL1 is the secure world: the Secure Kernel and Isolated User Mode (IUM), where Trustlets like LsaIso run. The hypervisor&apos;s SLAT tables enforce the separation: VTL0 page-table entries that would let the normal kernel read VTL1 memory simply fail the SLAT check at hardware-page-fault granularity. The only cross-VTL channel is the VSL hypercall pair. The VTL boundary is the strongest local boundary on Windows.
&lt;h3&gt;7.9 Administrator Protection elevation path (2025 addition)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Primitive.&lt;/strong&gt; The System Managed Administrator Account (SMAA) sits in the SAM database with its own SID, profile, and home directory. The &lt;code&gt;appinfo.dll&lt;/code&gt; consent service authorises SMAA-scoped elevation via Windows Hello. When a user requests an elevation, &lt;code&gt;appinfo.dll&lt;/code&gt; walks the Windows Hello flow, the SMAA token is created in a fresh logon session, the elevated process runs, and the token is destroyed when the process exits [@ms-learn-admin-protection].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Violation.&lt;/strong&gt; A standard-user process obtains the SMAA&apos;s elevated token without Windows Hello consent, typically by exploiting a primitive in the elevation path that lets the attacker substitute their own controlled object for one the SMAA elevation flow expects to create.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case study.&lt;/strong&gt; James Forshaw&apos;s January 2026 nine pre-GA Administrator Protection bypass series, disclosed via the Project Zero issue tracker [@pz-tracker-432313668]. The canonical illustration is the &quot;lazy DOS device directory hijack&quot; (Project Zero issue 432313668): DOS device object directories are created on demand for each logon session rather than at session creation time, and an attacker can race the SMAA elevation flow to create the directory first, with attacker-controlled permissions. Microsoft fixed all nine pre-GA -- not &quot;by design&quot;-replied. The boundary classification is operationally enforced.&lt;/p&gt;

flowchart TB
    subgraph Network[&quot;Network boundary&quot;]
        Remote[&quot;Remote / unauthenticated attacker&quot;]
    end
    subgraph Hypervisor[&quot;Hyper-V root partition&quot;]
        subgraph Guest[&quot;L1 guest VM&quot;]
            subgraph VTL0[&quot;VTL0 (normal kernel)&quot;]
                Kernel[&quot;Kernel mode&quot;]
                subgraph Session1[&quot;Session 1+ interactive&quot;]
                    subgraph User[&quot;Per-user identity&quot;]
                        ProcA[&quot;Process A&quot;]
                        ProcB[&quot;Process B&quot;]
                        subgraph AppC[&quot;AppContainer / LowBox&quot;]
                            Sandbox[&quot;Sandboxed renderer&quot;]
                        end
                    end
                end
                subgraph Session0[&quot;Session 0 services&quot;]
                    Svc[&quot;SYSTEM services&quot;]
                end
                subgraph AP[&quot;Administrator Protection elevation path&quot;]
                    SMAA[&quot;SMAA token&quot;]
                end
            end
            subgraph VTL1[&quot;VTL1 (Secure Kernel + IUM)&quot;]
                Trustlet[&quot;LsaIso Trustlet&quot;]
            end
        end
    end
    Remote -.-&amp;gt;|&quot;Network boundary&quot;| Kernel
    ProcA -.-&amp;gt;|&quot;Process boundary&quot;| ProcB
    Session1 -.-&amp;gt;|&quot;Session boundary&quot;| Session0
    Sandbox -.-&amp;gt;|&quot;AppContainer boundary&quot;| ProcA
    Kernel -.-&amp;gt;|&quot;VTL boundary&quot;| Trustlet
    ProcA -.-&amp;gt;|&quot;Administrator Protection boundary&quot;| SMAA
&lt;p&gt;Nine boundaries. Every one of them backed by a real architectural primitive, every one of them carrying a documented violation history. But the doctrine is only half a table. The other half is the table of primitives Microsoft has &lt;em&gt;explicitly&lt;/em&gt; chosen not to commit to.&lt;/p&gt;
&lt;h2&gt;8. What Is Not a Boundary&lt;/h2&gt;
&lt;p&gt;For every primitive on the boundary list, there is a primitive Microsoft has named in the same document and chosen &lt;em&gt;not&lt;/em&gt; to commit to. The seven entries, with the structural reason for each classification.&lt;/p&gt;
&lt;h3&gt;8.1 UAC&lt;/h3&gt;
&lt;p&gt;Russinovich&apos;s June 2007 sentence is the doctrinal source: &lt;em&gt;&quot;UAC elevations are conveniences and not security boundaries&quot;&lt;/em&gt; [@russinovich-vista-uac-wayback]. The structural reason is the shared-resources model -- same SID, same profile, same logon session, same DOS device object directory between the standard-user and elevated tokens. UACMe is the operational catalogue: more than 80 documented auto-elevation methods, zero CVEs [@uacme]. The reply to a UAC bypass report is &quot;by design, please refer to the servicing criteria,&quot; and that reply is operationally correct.&lt;/p&gt;
&lt;h3&gt;8.2 Driver Signing / Code Integrity / KMCS&lt;/h3&gt;
&lt;p&gt;Local administrator can, by design, install drivers. Once a driver is installed, it runs in kernel mode. Classifying admin-to-kernel as a boundary would require redesigning the Administrators group itself. The downstream operational consequence is the &lt;a href=&quot;https://paragmali.com/blog/windows-kernel-code-integrity-2006-2026/&quot; rel=&quot;noopener&quot;&gt;BYOVD attack family&lt;/a&gt;: an administrator installs a legitimately-signed driver with an exploitable vulnerability and uses the driver to obtain arbitrary kernel-mode code execution. Microsoft maintains the &lt;em&gt;Vulnerable Driver Blocklist&lt;/em&gt; as feature hardening, and the Windows Defender Application Control (WDAC) infrastructure as a tighter enforcement option, but those are features layered over a primitive Microsoft has not classified as a boundary [@leviev-downdate-update].&lt;/p&gt;
&lt;h3&gt;8.3 Microsoft Defender / Antimalware&lt;/h3&gt;
&lt;p&gt;A heuristic detection layer cannot, by construction, be a boundary. Antivirus operates by recognising patterns -- signature, behaviour, reputation -- and an adversary tuning a payload against those patterns can always find a path that the detector does not recognise.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A boundary requires that &quot;security policy dictates what can pass through.&quot; Heuristic detection cannot meet that requirement. There is no policy oracle that can decide, in finite time with finite memory, whether an arbitrary binary will exhibit malicious behaviour. The decision problem is undecidable in the general case (Rice&apos;s theorem); in practice antivirus is a probabilistic filter, not a guarantee. Microsoft&apos;s classification of Defender as a feature acknowledges this constraint. Defender will be improved, hardened, and updated -- but the doctrine does not promise that it will &lt;em&gt;catch&lt;/em&gt; any specific malware. Bypassing Defender is expected and continuous, and a Defender-bypass report on its own does not earn a CVE.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tavis Ormandy&apos;s 2014 to 2017 Defender disclosures earned CVEs not because they bypassed Defender&apos;s detection but because they crossed &lt;em&gt;other&lt;/em&gt; boundaries [@ms-advisory-4022344]. The bugs were memory-corruption primitives in the Defender parsing engine reachable from attacker-controlled inputs the engine fetched from email or web traffic. The flagship example is CVE-2017-0290, the &lt;em&gt;crazy bad&lt;/em&gt; MsMpEng RCE Microsoft addressed with out-of-band Security Advisory 4022344 on May 8, 2017 [@ms-advisory-4022344]. The network boundary crossing is what earned the CVE.This is the operational lesson for anyone reporting a Defender finding: lead with the boundary, not the feature. If your bypass is a clever signature evasion, expect a &quot;by design&quot; reply. If your bypass is a parsing-engine memory-corruption primitive that fires from attacker-controlled input arriving over the network, that is a network-boundary crossing and you have a CVE-eligible report.&lt;/p&gt;
&lt;h3&gt;8.4 HVCI / Memory Integrity&lt;/h3&gt;
&lt;p&gt;The doctrinally subtle one. &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; is the kernel-mode code integrity check that lives &lt;em&gt;inside&lt;/em&gt; VTL1, running under the protection of the hypervisor. The VTL boundary is what protects HVCI from attacker tampering. HVCI itself is a &lt;em&gt;feature&lt;/em&gt; enforced &lt;em&gt;at&lt;/em&gt; the VTL boundary, not a boundary in its own right.&lt;/p&gt;
&lt;p&gt;The operational consequence: an HVCI bypass that does not also cross VTL0 to VTL1 is a feature defeat. Critical-severity HVCI bypasses may still ship as security updates through the exception clause -- but the primary disposition path is feature-hardening rather than boundary-servicing. Microsoft&apos;s &lt;em&gt;Virtualization-based protection of code integrity&lt;/em&gt; page documents the architecture in detail and is the canonical reference [@ms-learn-vbs-ci].&lt;/p&gt;
&lt;h3&gt;8.5 Protected Process Light (PPL)&lt;/h3&gt;
&lt;p&gt;Introduced in Windows 8.1 to protect anti-malware services and other specially-signed processes from administrator tampering [@ms-learn-am-ppl]. PPL uses code integrity to refuse unsigned code injection into protected processes, and refuses termination requests even from administrators.&lt;/p&gt;
&lt;p&gt;Gabriel Landau&apos;s PPLFault chain demonstrated loading unsigned code into a PPL process by racing the kernel&apos;s signature check against attacker-controlled storage during catalog load -- the False File Immutability primitive [@landau-pplfault], [@landau-ffi-elastic]. Microsoft&apos;s response was the Canary build 25941 mitigation on September 1, 2023 -- feature hardening that ships out-of-cycle when the impact warrants it, &lt;em&gt;not&lt;/em&gt; boundary-class servicing. Landau&apos;s article preserves the verbatim MSRC position.&lt;/p&gt;

The PPL mechanism was introduced in Windows 8.1, enabling specially-signed programs to run in such a way that they are protected from tampering and termination, even by administrative processes ... Microsoft does not consider PPL to be a security boundary, meaning they won&apos;t prioritize security patches for code-execution vulnerabilities discovered therein, but they have historically addressed some such vulnerabilities on a less-urgent basis. -- Gabriel Landau, Elastic Security Labs, September 2023 [@landau-pplfault]
&lt;h3&gt;8.6 Administrator-to-kernel privilege escalation&lt;/h3&gt;
&lt;p&gt;The structural impossibility argument applies cleanly here. By Saltzer-Schroeder&apos;s &lt;em&gt;complete mediation&lt;/em&gt; principle [@saltzer-schroeder-mit], a boundary requires that every access through it be mediated by policy. Administrators are policy-authorised to load drivers; drivers run in kernel mode; therefore admin-to-kernel is the &lt;em&gt;expected&lt;/em&gt; operation, not a policy violation. Reclassifying this as a boundary would mean redesigning the Administrators group itself.&lt;/p&gt;
&lt;p&gt;The Landau &lt;em&gt;ItsNotASecurityBoundary&lt;/em&gt; GitHub repository name is an explicit homage to this Microsoft policy [@landau-itsnotasb-gh]. The repository&apos;s research extends False File Immutability into kernel space: the Windows Code Integrity subsystem (&lt;code&gt;ci.dll&lt;/code&gt;) is itself susceptible to FFI, letting an attacker who controls a catalog file on attacker-controlled storage race the CI signature check and then load unsigned drivers. Microsoft fixed the specific FFI primitive but did not move the admin-to-kernel classification.&lt;/p&gt;
&lt;p&gt;Alon Leviev&apos;s Windows Downdate is the recent flagship demonstration. Microsoft assigned CVE-2024-21302 to the chain because it crossed the VTL boundary; the underlying Windows Update takeover -- the admin-to-kernel piece -- remained unpatched [@leviev-downdate-update]. The classification stood. Specific chains earn CVEs when they cross another boundary; the primitive itself does not become a boundary by accumulation of exploitation evidence.&lt;/p&gt;

While 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, SafeBreach Labs, October 26, 2024 [@leviev-downdate-update]
&lt;h3&gt;8.7 Same-user post-authentication&lt;/h3&gt;
&lt;p&gt;The most recent addition to the feature table, articulated by James Forshaw in &lt;em&gt;Working your way Around an ACL&lt;/em&gt; (June 3, 2024). Once a process has executed under a user&apos;s session, it inherits the user&apos;s trust. Per-process isolation within the same user is not a declared boundary. Forshaw&apos;s verbatim formulation: &lt;em&gt;&quot;any privilege escalation (or non-security boundary &lt;em&gt;cough&lt;/em&gt;) is sufficient to leak the information&quot;&lt;/em&gt; [@forshaw-tyranid-acl].&lt;/p&gt;
&lt;p&gt;The operational stakes here are higher than they look. AI-mediated features like Windows 11 Recall continuously record sensitive user state into a same-user-readable database. If same-user is not a boundary, every non-PPL local process under the same user identity can read that database. The &quot;ACLed to SYSTEM&quot; mitigation that protects the Recall storage is operationally weak under the doctrine, because &lt;em&gt;any&lt;/em&gt; same-user privilege escalation -- including the entire UACMe catalogue, all of the same-user-post-authentication footguns, and every UI-Access trick -- is a sufficient predicate.&lt;/p&gt;

flowchart TD
    Report[&quot;Vulnerability report arrives&quot;]
    Cls{&quot;Classify primitive&quot;}
    BdyQ2{&quot;Boundary path: severity Critical or Important?&quot;}
    FtrQ2{&quot;Feature path: severity Critical or Important?&quot;}
    Excp{&quot;Exception applies?&quot;}
    SvcBdy[&quot;Boundary servicing: Patch Tuesday CVE&quot;]
    SvcFtr[&quot;Feature servicing: Patch Tuesday CVE (Q2 yes path)&quot;]
    SvcExc[&quot;Exception servicing: feature hardening, possible bulletin&quot;]
    Defer[&quot;By design / consider for next version&quot;]
    Report --&amp;gt; Cls
    Cls -- &quot;Boundary&quot; --&amp;gt; BdyQ2
    Cls -- &quot;Feature&quot; --&amp;gt; FtrQ2
    BdyQ2 -- &quot;Yes&quot; --&amp;gt; SvcBdy
    BdyQ2 -- &quot;No&quot; --&amp;gt; Excp
    FtrQ2 -- &quot;Yes&quot; --&amp;gt; SvcFtr
    FtrQ2 -- &quot;No&quot; --&amp;gt; Excp
    Excp -- &quot;Yes&quot; --&amp;gt; SvcExc
    Excp -- &quot;No&quot; --&amp;gt; Defer
&lt;p&gt;The central insight: the not-a-boundary table is &lt;em&gt;not&lt;/em&gt; a list of bugs Microsoft has not gotten around to fixing. It is a list of primitives Microsoft has &lt;em&gt;deliberately&lt;/em&gt; chosen not to commit to, because guaranteeing those primitives as boundaries would require either reorganising the architecture (admin-to-kernel) or operating against an inherent impossibility (heuristic detection cannot guarantee detection).&lt;/p&gt;
&lt;p&gt;Nine boundaries that Microsoft commits to. Seven features Microsoft hardens but does not commit to. One remaining structural artifact ties the two together: the bounty schedule.&lt;/p&gt;
&lt;h2&gt;9. The Bounty Schedule Mirrors the Boundary List&lt;/h2&gt;
&lt;p&gt;If you wanted a market-side confirmation that the boundary list is the operational anchor, you would look at the bounty schedule. The two documents are mechanically linked.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bounty program&lt;/th&gt;
&lt;th&gt;Payout range&lt;/th&gt;
&lt;th&gt;Primary boundary (or boundaries)&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;Microsoft Hyper-V Bounty Program&lt;/td&gt;
&lt;td&gt;$5,000 to $250,000 USD&lt;/td&gt;
&lt;td&gt;Virtual machine (guest-to-host)&lt;/td&gt;
&lt;td&gt;[@msrc-bounty-hyperv]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Insider Preview Bounty Program&lt;/td&gt;
&lt;td&gt;$500 to $100,000 USD&lt;/td&gt;
&lt;td&gt;Kernel, network, sandbox, VBS / VTL&lt;/td&gt;
&lt;td&gt;[@msrc-bounty-wip]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Edge Bounty Program&lt;/td&gt;
&lt;td&gt;$250 to $30,000 USD&lt;/td&gt;
&lt;td&gt;AppContainer / sandbox, network&lt;/td&gt;
&lt;td&gt;[@msrc-bounty-edge]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Bounty Programs (landing)&lt;/td&gt;
&lt;td&gt;Varies by program&lt;/td&gt;
&lt;td&gt;Identity, Cloud, M365, Azure (cloud-side boundaries)&lt;/td&gt;
&lt;td&gt;[@msrc-bounty-root]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standalone UAC bypass bounty&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;(UAC is on the feature list, no bounty)&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Hyper-V is the highest payout.&lt;/strong&gt; Up to $250,000 USD for a guest-to-host escape, which is the largest single-finding payout in the Microsoft bounty catalogue [@msrc-bounty-hyperv]. The program&apos;s verbatim definition of an eligible submission is a remote-code-execution vulnerability that lets an L1 guest virtual machine compromise the hypervisor, escape from the guest to the host, or escape to another L1 guest. That maps directly to the VM boundary on the servicing-criteria table. The market signal is unambiguous: the boundary whose violation matters the most pays the most.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows Insider Preview is the kernel / network / VBS catch-all.&lt;/strong&gt; Up to $100,000 USD for vulnerabilities found on the latest Canary Channel build, with the eligibility requirement that the vulnerability &quot;must be Critical or Important severity as defined in the Microsoft Vulnerability Severity Classification for Windows&quot; [@msrc-bounty-wip]. That severity requirement is the &lt;em&gt;Question 2&lt;/em&gt; gate from the two-question rule, written directly into the bounty&apos;s eligibility clause. The bounty program inherits Question 2 mechanically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Edge is the sandbox program.&lt;/strong&gt; Up to $30,000 USD for Edge-unique vulnerabilities (not reproducing on the equivalent Google Chrome channel) in the Dev, Beta, or Stable channels [@msrc-bounty-edge]. The &quot;unique to Edge&quot; requirement reflects that Chromium engine bugs upstream are Google Chrome&apos;s bounty scope; the Microsoft Edge program covers the Edge-specific shell, AppContainer integration, and Windows integration code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The absence of a UAC bounty.&lt;/strong&gt; There is no standalone UAC bypass bounty program. Not because Microsoft does not care about UAC bypasses, but because UAC is not on the boundary list -- the market signal follows the doctrine.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The bounty schedule is the most reliable cross-check available for the boundary list. Reading the bounty page is a reasonable proxy for reading the boundary list, because Microsoft only pays for findings that violate primitives the company has committed to defending. The absence of a UAC bounty, the presence of a $250,000 Hyper-V tier, and the Critical-or-Important severity gate baked into the Windows Insider Preview bounty are all consequences of the servicing-criteria classification. The classification drives the payout. The payout reveals the classification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The mapping is &lt;em&gt;dominantly&lt;/em&gt; tight, not &lt;em&gt;strictly&lt;/em&gt; tight. The exception clause from the servicing criteria applies here too: a sufficiently impactful feature defeat may receive an out-of-band bounty under the broader Microsoft Bounty Programs umbrella [@msrc-bounty-root]. But the structural mapping is consistent enough that the bounty page is a fair proxy for the classification.&lt;/p&gt;
&lt;p&gt;You have now read the doctrine in full. Two tables, one rule, one bounty overlay. The next question is the one the doctrine itself cannot answer: where are the gaps?&lt;/p&gt;
&lt;h2&gt;10. What the Doctrine Cannot Decide&lt;/h2&gt;
&lt;p&gt;The doctrine is the most enumerated vulnerability-classification policy any major OS vendor has published. It still has gray zones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resourcing versus security.&lt;/strong&gt; Microsoft&apos;s admin-to-kernel position is at least partly a &lt;em&gt;resourcing&lt;/em&gt; decision: finite engineering capacity to harden the admin elevation path. The structural impossibility argument (admin loads drivers; drivers run in kernel) is genuine, but it does not by itself force the classification -- a sufficiently invasive architectural change (sealed-system mode; VTL Enclaves hosting the entire kernel) could in principle move the line. What &quot;guaranteed by Windows&quot; means in a model that admits BYOVD, Windows Downdate, and False File Immutability is a question reasonable researchers can disagree on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Severity-meets-bar as the second filter.&lt;/strong&gt; Two findings that cross the same boundary can receive different fates depending on Question 2. The Bug Bar [@msrc-bugbar] documents the &lt;em&gt;types&lt;/em&gt; of severity (RCE, EoP, info disclosure, DoS, spoofing, tampering) and the &lt;em&gt;pivots&lt;/em&gt; (server vs client; default-on vs default-off; user interaction required vs not), but the thresholds within each type are not exhaustively published. A researcher who knows the boundary list still cannot, from the document alone, predict severity to single-step accuracy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &quot;exceptions may be made&quot; clause.&lt;/strong&gt; The doctrine itself admits exceptions exist. PPLFault shipped a feature-hardening mitigation in Canary build 25941 [@landau-pplfault] even though PPL is a feature; CVE-2024-21302 received a Patch Tuesday bulletin even though the underlying admin-to-kernel primitive remained on the feature side [@leviev-downdate-update]. Researchers cannot fully predict the MSRC reply from the document alone; the exception clause is structural relief, not an edge case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boundary classification of paths, not just components.&lt;/strong&gt; Administrator Protection is the elevation &lt;em&gt;path&lt;/em&gt;, not the account [@ms-learn-admin-protection]. Admin-to-kernel via driver load is still not a boundary even when the elevation path is. The two coexist: a researcher who finds a way for a standard-user process to obtain an SMAA elevated token without consent has a CVE-eligible boundary crossing; a researcher who finds a way for an &lt;em&gt;administrator&lt;/em&gt; process to install a vulnerable driver and pivot to kernel has a feature defeat.&lt;/p&gt;

Saltzer and Schroeder&apos;s 1975 *The Protection of Information in Computer Systems* [@saltzer-schroeder-mit] articulates the *open design* principle: the security design should be public, &quot;the mechanisms should not depend on the ignorance of potential attackers.&quot; A published classification doctrine like Microsoft&apos;s satisfies open design. Their *complete mediation* principle is the other constraint at work: a boundary requires that every access through it be mediated by policy. The Microsoft doctrine lives precisely in the gap between *enumerable* (an upper bound: a published doctrine must list the boundaries it commits to) and *complete* (a lower bound: no doctrine can list every primitive that will ever matter). The &quot;exceptions may be made&quot; clause is the doctrine&apos;s explicit acknowledgment of the gap.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The doctrine does not promise that every reported finding will be serviced. It does not promise that severity thresholds are publicly enumerated to single-step accuracy. It does not promise that the boundary list will not grow or contract. It does not promise that two reports against the same primitive at the same severity will receive identical disposition. What it promises is that the &lt;em&gt;classification half&lt;/em&gt; of the triage will follow the published list, and that the &lt;em&gt;exception clause&lt;/em&gt; exists as the explicit relief valve when the published list does not fit. The promise is procedural, not absolute. That procedural promise is what makes the doctrine more legible than any comparable vendor policy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft&apos;s doctrine has gray zones -- but it has more enumerated certainty than any comparable doctrine. How does it compare to Apple&apos;s, Chromium&apos;s, Mozilla&apos;s, and the Linux kernel&apos;s?&lt;/p&gt;
&lt;h2&gt;11. How Other Vendors Classify the Same Primitives&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s document is one of five major published doctrines. Each draws the line differently.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;Taxonomic structure&lt;/th&gt;
&lt;th&gt;Primary URL&lt;/th&gt;
&lt;th&gt;Example divergence from Microsoft&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;Enumerated boundary + feature tables; two-question rule&lt;/td&gt;
&lt;td&gt;[@msrc-criteria]&lt;/td&gt;
&lt;td&gt;The Microsoft baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apple (macOS / iOS)&lt;/td&gt;
&lt;td&gt;Architectural-by-section; sealed system + SIP&lt;/td&gt;
&lt;td&gt;[@apple-platform-security]&lt;/td&gt;
&lt;td&gt;SIP classifies admin-to-OS-modification as a boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chromium&lt;/td&gt;
&lt;td&gt;Design-time &lt;em&gt;Rule of 2&lt;/em&gt;; severity guidelines for triage&lt;/td&gt;
&lt;td&gt;[@chromium-rule-of-2]&lt;/td&gt;
&lt;td&gt;Design-time pre-commitment, not post-hoc classification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mozilla&lt;/td&gt;
&lt;td&gt;sec-rating (sec-critical / sec-high / sec-moderate / sec-low)&lt;/td&gt;
&lt;td&gt;[@mozilla-client-bounty]&lt;/td&gt;
&lt;td&gt;Severity-only, no primitive enumeration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;Per-subsystem implicit classification&lt;/td&gt;
&lt;td&gt;[@linux-security-bugs]&lt;/td&gt;
&lt;td&gt;No central table; maintainer-driven&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Apple&apos;s Platform Security Guide.&lt;/strong&gt; A sealed-system / Signed System Volume model with stricter user/kernel separation. macOS System Integrity Protection (SIP) restricts the root user account and limits the actions root may perform on protected parts of the OS [@apple-sip-ht204899]. Some admin-to-system-modification paths that Windows classifies as features (Driver Signing, Code Integrity, admin-to-kernel) are classified by SIP as boundaries the OS protects against modification, &lt;em&gt;including&lt;/em&gt; by the local administrator. The Apple guide is less enumerated than Microsoft&apos;s -- it organises by section rather than by table -- but it commits to architectural separations that the open-driver-loading Windows model cannot match [@apple-platform-security].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chromium&apos;s Rule of 2 plus Severity Guidelines.&lt;/strong&gt; A &lt;em&gt;design-time&lt;/em&gt; pre-commitment, fundamentally different from Microsoft&apos;s post-hoc triage. The Rule of 2 states: &lt;em&gt;&quot;When you write code to parse, evaluate, or otherwise handle untrustworthy inputs from the Internet ... Pick no more than 2 of: untrustworthy inputs; unsafe implementation language; and high privilege&quot;&lt;/em&gt; [@chromium-rule-of-2]. Code that violates the rule must be sandboxed before it ships. Site isolation (each origin in its own renderer process) is the operational boundary equivalent. The Severity Guidelines parameterise triage with a Critical (S0) / High / Medium / Low scheme [@chromium-severity-guidelines].The Chromium Rule of 2 and Microsoft&apos;s servicing criteria are not substitutes -- they live at different layers. The Rule of 2 is an &lt;em&gt;engineering&lt;/em&gt; rule that forecloses entire vulnerability classes at design time. The Microsoft doctrine is a &lt;em&gt;triage&lt;/em&gt; rule that classifies findings at disclosure time. A Chromium project can adopt both, and Microsoft Edge does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mozilla&apos;s Client Bug Bounty Program.&lt;/strong&gt; A severity-only rating: sec-critical, sec-high, sec-moderate, sec-low. The bounty page states verbatim: &lt;em&gt;&quot;Typically, the security rating given by the Bounty Committee for a bug must be rated a &apos;sec-high&apos; or &apos;sec-critical&apos; in order for it to be eligible for a bounty&quot;&lt;/em&gt; [@mozilla-client-bounty]. There is no published boundary enumeration. The Bounty Committee&apos;s judgment is the deciding factor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Linux kernel security-bugs process.&lt;/strong&gt; Per-subsystem, not per-boundary. The verbatim policy: &lt;em&gt;&quot;By definition if an issue cannot be reproduced, it is not exploitable, thus it is not a security bug&quot;&lt;/em&gt; [@linux-security-bugs]. CVE assignment runs through the kernel&apos;s CVE Numbering Authority since 2024. There is no Linux equivalent of the MSRC servicing-criteria document; classification is implicit in the maintainer&apos;s response.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s document is the most enumerated, most operationally legible vulnerability-classification doctrine published by any major OS vendor. That legibility is itself a vendor commitment, and is what makes &quot;by design&quot; a predictable answer rather than an arbitrary one. All five doctrines agree that boundaries exist. They disagree on which primitives count, how to enumerate them, and how to communicate the result. Microsoft has chosen the most-enumerated point in that gap. The next question is whether the enumeration will keep growing.&lt;/p&gt;
&lt;h2&gt;12. The 2026 Frontier&lt;/h2&gt;
&lt;p&gt;The boundary list grew by accretion for twenty years. Four pressures are pushing the next additions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cloud-side boundaries.&lt;/strong&gt; Conditional Access policy enforcement (Microsoft Entra), the Primary Refresh Token (PRT), and the Microsoft 365 service boundary that Copilot operates within. These are not currently in the Windows servicing criteria -- they are governed by separate MSRC documents and per-product bounty programs [@msrc-bounty-root]. Modern Windows attack chains routinely involve both client-side (Windows) and cloud-side (Entra / Azure) primitives. A finding that crosses a &lt;em&gt;cloud-side&lt;/em&gt; boundary may or may not also cross a &lt;em&gt;client-side&lt;/em&gt; boundary, and the Windows document does not yet arbitrate.&lt;/p&gt;
&lt;p&gt;The open question is whether the Windows servicing criteria document will expand to cover cloud-side primitives, or whether a parallel &lt;em&gt;Microsoft Identity Security Servicing Criteria&lt;/em&gt; document will appear. The bounty pages function as a &lt;em&gt;derived&lt;/em&gt; boundary list today -- reading them tells a researcher which cloud-side primitives Microsoft commits to servicing -- but the unified document does not yet exist.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agentic / AI-mediated privilege expansion.&lt;/strong&gt; Copilot in Windows and Copilot for Microsoft 365 can take actions on behalf of a user. Prompt injection from untrusted content can cause Copilot to perform actions the user did not intend. Is that a boundary crossing?&lt;/p&gt;

A prompt-injected Copilot action operates *within* the user&apos;s identity and the user&apos;s authorisations. By the same-user-post-authentication classification, that should be a feature defeat, not a boundary crossing. But the *intent* the user expressed (summarise my email; do not exfiltrate it) is defeated by the injected prompt. The doctrine was designed to classify primitives in terms of policy-enforced separations, not in terms of user-intent-vs-attacker-intent. The MITRE ATT&amp;amp;CK framework has begun to enumerate prompt-injection-class techniques [@mitre-attack]; the Microsoft document has not yet. Whichever way Microsoft decides -- a new boundary entry, a new feature entry, or a deferral -- will be the most consequential doctrinal move since the 2025 Administrator Protection addition.
&lt;p&gt;&lt;strong&gt;Administrator Protection rollout resumption.&lt;/strong&gt; The December 2025 revert was an application-compatibility decision; the boundary classification stands [@ms-learn-admin-protection]. What would have to be true for the rollout to resume: Win32 application compatibility validated across the long tail, Visual Studio elevation flows verified, the WebView2 installer regression resolved [@ms-blogs-admin-protection-dev]. What stays the same when it does: Forshaw&apos;s nine pre-GA bypasses all fixed; the elevation path still on the boundary side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Same-user as a possible new boundary.&lt;/strong&gt; The Recall disclosure and the broader same-user post-authentication class push on this question. The community position, articulated by Forshaw, is that same-user should not be expected to be a boundary [@forshaw-tyranid-acl]. Microsoft&apos;s response has been &lt;em&gt;feature hardening&lt;/em&gt; (Personal Data Encryption, VTL Enclave use) rather than reclassification.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If VTL Enclaves and Personal Data Encryption become a per-user attestable substrate -- a per-user equivalent of VTL1 -- then &lt;em&gt;same-user&lt;/em&gt; could become a boundary in the same way &lt;em&gt;user-to-user&lt;/em&gt; already is. The structural ingredient that VTL1 added to the user boundary (hypervisor-mediated separation that even SYSTEM cannot cross) would be added to a per-process scope within a user&apos;s identity. This is a research-track conjecture, not a Microsoft commitment; no public Microsoft statement has confirmed the direction. But the &lt;em&gt;shape&lt;/em&gt; of how same-user could become a boundary is now legible, in a way it was not before Administrator Protection demonstrated that re-using an existing boundary (user-to-user) for a new primitive (the SMAA elevation path) is a viable engineering pattern.&lt;/p&gt;
&lt;/blockquote&gt;

flowchart LR
    subgraph Existing[&quot;Existing boundaries (current doctrine)&quot;]
        Net[&quot;Network&quot;]
        Krn[&quot;Kernel&quot;]
        Prc[&quot;Process&quot;]
        Sess[&quot;Session&quot;]
        Usr[&quot;User&quot;]
        AC[&quot;AppContainer&quot;]
        VM[&quot;Virtual machine&quot;]
        VTL[&quot;VTL0 to VTL1&quot;]
        AP[&quot;Administrator Protection&quot;]
    end
    subgraph Ingredients[&quot;Structural ingredients pushing the frontier&quot;]
        PRT[&quot;Primary Refresh Token&quot;]
        CA[&quot;Conditional Access policy&quot;]
        PI[&quot;Prompt injection primitives&quot;]
        PDE[&quot;Personal Data Encryption&quot;]
        Enc[&quot;VTL Enclaves&quot;]
    end
    subgraph Candidate[&quot;Candidate future boundaries&quot;]
        Cloud[&quot;Cloud-side: PRT / Conditional Access&quot;]
        AI[&quot;AI-mediated action expansion&quot;]
        SU[&quot;Same-user per-process&quot;]
    end
    Usr --&amp;gt; PRT
    Usr --&amp;gt; CA
    PRT --&amp;gt; Cloud
    CA --&amp;gt; Cloud
    PI --&amp;gt; AI
    Sess --&amp;gt; PI
    PDE --&amp;gt; SU
    Enc --&amp;gt; SU
    VTL --&amp;gt; Enc
&lt;p&gt;None of these candidates is on the table yet. All four are being pushed by primitives -- the Primary Refresh Token, prompt injection, Administrator Protection, the Recall directory ACL -- that have already shipped. The next decade&apos;s boundary list is being negotiated now, in real research posts and MSRC replies. The question is how &lt;em&gt;you&lt;/em&gt; file a report into that negotiation.&lt;/p&gt;
&lt;h2&gt;13. How to File a Useful MSRC Report&lt;/h2&gt;
&lt;p&gt;Everything in this article has been theory until this section. Here is how the doctrine becomes a checklist you can apply to your own findings before the submit button.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the servicing-criteria document first&lt;/strong&gt; [@msrc-criteria]. Map your finding to a boundary entry. If it does not map, expect a feature-defeat reply. If it maps cleanly, you know in advance that the disposition path goes through Question 2.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lead the MSRC submission with the boundary claim in the first sentence.&lt;/strong&gt; &lt;em&gt;&quot;This issue violates the [process | kernel | session | network | user | AppContainer | VM | VTL | Administrator Protection] boundary because &lt;code&gt;&amp;lt;reason&amp;gt;&lt;/code&gt;.&quot;&lt;/em&gt; The triage engineer reading your report should never have to infer which boundary you are claiming. Name it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Include the severity-meets-bar argument in the second paragraph.&lt;/strong&gt; Critical / Important / Moderate / Low per the Bug Bar [@msrc-bugbar]. Cite the specific bug-type cell (RCE, EoP, info disclosure, DoS, spoofing, tampering) and the pivot (server vs client; default-on vs default-off; user interaction required vs not). Worked examples beat assertions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If the finding crosses a feature &lt;em&gt;and&lt;/em&gt; a boundary, lead with the boundary.&lt;/strong&gt; The feature defeat is supporting evidence, not the primary claim. A Defender bypass that also crosses the network boundary is a network-boundary report with a Defender defeat as supporting detail, not the other way around.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expect the reply to be operationally predictable.&lt;/strong&gt; If the finding is on the feature side and severity is not Critical, the reply will be &quot;by design / consider for next version.&quot; Plan publication accordingly. A 90-day Project Zero clock that lines up with a probable &quot;by design&quot; reply is not a failed disclosure -- it is a successful one, because the reply was predicted in advance [@project-zero-9030].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For bounty-eligible classes, read the program-scope page carefully.&lt;/strong&gt; Hyper-V ($5K - $250K) [@msrc-bounty-hyperv], Windows Insider Preview ($500 - $100K) [@msrc-bounty-wip], Edge ($250 - $30K) [@msrc-bounty-edge], plus the Identity / Cloud / M365 / Azure programs [@msrc-bounty-root]. The boundary-payout mapping is dominantly tight; the program-scope page tells you whether the bounty fires.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If the reply surprises you, the &quot;exceptions may be made&quot; clause is the framing&lt;/strong&gt; [@msrc-criteria]. A feature defeat that &lt;em&gt;does&lt;/em&gt; receive a bulletin does not contradict the doctrine; it invokes the exception. A boundary crossing that &lt;em&gt;does not&lt;/em&gt; receive a bulletin invokes the exception in the other direction (severity below bar). Either way, the doctrine is not broken; the exception clause is doing its job.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Before you spend three weeks reverse-engineering a primitive, spend three minutes reading the relevant Microsoft Bounty Program scope page. The page tells you, in plain language, whether Microsoft considers the primitive class you are attacking to be bounty-eligible. If the bounty program does not list your primitive class -- if there is no UAC-bypass bounty, no Defender-bypass-by-detection-evasion bounty, no PPL-bypass bounty -- the boundary classification has already told you the operational answer. You can still publish the research; you just know the disposition in advance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Subject: Boundary violation -- Hyper-V guest-to-host escape via
         root-partition heap UAF (Critical, RCE, default-on)

Section 1 -- Boundary claim
  This issue violates the Hyper-V virtual machine (guest-to-host)
  security boundary as enumerated in the Microsoft Security Servicing
  Criteria for Windows. The attack flow: a malicious L1 guest VM
  triggers a use-after-free in a Hyper-V root-partition component
  reachable via VMBus; the freed allocation is reclaimed with
  attacker-controlled data via a follow-up VMBus message; the
  resulting type confusion yields remote code execution in the host
  root-partition context with SYSTEM privileges.

Section 2 -- Severity argument
  Per the Microsoft Vulnerability Severity Classification for Windows
  bug bar, this is Critical severity:
    - Vulnerability type: Remote Code Execution
    - Server severity: Critical (server pivot: Hyper-V host is by
      definition a server role)
    - Client severity: Critical (client pivot: same primitive on
      client Hyper-V used by Windows Sandbox / WSL2)
    - Default-on: Yes (the affected root-partition component ships
      and runs by default on all Hyper-V hosts)
    - User interaction required: No
    - Attack complexity: Low

Section 3 -- Reproduction
  - Attached: minimal L1 guest exploit binary (Linux x86_64),
    deterministic on Windows Server 2025 Hyper-V build 26100.4061.
  - Attached: WinDbg crash dump showing the UAF and the controlled
    write primitive.
  - Attached: video of the SYSTEM shell on the host opened by an
    unprivileged user in the guest.

Section 4 -- Bounty eligibility
  Microsoft Hyper-V Bounty Program scope: L1 Guest Escape -- RCE on
  the host from the guest. Requested payout tier per program scope
  page.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the checklist. The doctrine is internalised. You can predict the disposition of any Windows finding from the boundary list, the severity scheme, and the exception clause. The only thing left is the closing -- the return to the researcher we opened with.&lt;/p&gt;
&lt;h2&gt;14. Frequently Asked Questions and Closing&lt;/h2&gt;
&lt;p&gt;Return to the researcher we opened with. Their &quot;UAC bypass&quot; was filed against a primitive that was never on the boundary list, and the MSRC reply was operationally correct, not a cop-out. The doctrine the reply invoked is the one this article has just walked.&lt;/p&gt;

No. UAC was never officially classified as a boundary. Mark Russinovich&apos;s June 2007 *Inside Windows Vista User Account Control* article stated verbatim that *&quot;UAC elevations are conveniences and not security boundaries&quot;* -- two years before the January 2009 Long Zheng and Rafael Rivera Windows 7 beta UAC auto-elevation disclosure [@russinovich-vista-uac-wayback]. What Microsoft changed in 2009 was the *implementation* (UAC slider promoted to High integrity; UAC-settings changes prompting), not the *classification*. Russinovich&apos;s July 2009 follow-up article restated the original position [@ms-learn-russinovich-win7].

No. &quot;By design&quot; means the doctrine explicitly chose not to service this primitive class as a boundary violation. Microsoft may still harden the feature in a future Windows release, ship out-of-band Canary build mitigations (as with PPLFault build 25941) [@landau-pplfault], or assign CVEs to specific exploitation chains that cross *other* boundaries (as with Windows Downdate&apos;s CVE-2024-21302) [@leviev-downdate-update]. The finding is interesting research. It simply does not receive a CVE under the published doctrine.

Probably not, but the Administrator Protection elevation *path* is now a boundary [@ms-learn-admin-protection], and the Landau / Leviev disclosures keep pressure on the unmoved part of the classification. The structural impossibility argument (admin loads drivers; drivers run in kernel) makes a doctrinal reclassification unlikely without a deeper architectural change. The most plausible architectural change would be the extension of VTL Enclaves and VBS Trustlets to host security-critical kernel components, such that *admin-to-VTL1* becomes the boundary even as *admin-to-VTL0-kernel* stays a feature [@ms-learn-vbs-ci].

No. Defender bypasses that do not also cross another boundary typically do not receive bulletins. Tavis Ormandy&apos;s 2014 to 2017 Defender disclosures earned CVEs because the bugs were memory-corruption primitives reachable from attacker-controlled inputs over the network -- they crossed the network boundary, not because the Defender bypass itself was a boundary crossing. The CVE-2017-0290 *crazy bad* MsMpEng RCE, addressed by Microsoft Security Advisory 4022344 (May 8, 2017), is the flagship instance [@ms-advisory-4022344]. A clever signature-evasion technique alone earns &quot;by design.&quot;

No. It has grown by accretion: Session 0 isolation (Vista, 2007); AppContainer / Edge sandbox (Windows 8 / 1607, 2012 to 2016); VBS / VTL (Windows 10 1507, 2015); Administrator Protection elevation path (2025) [@ms-learn-admin-protection]. The list is expected to keep growing. Candidate future entries include cloud-side primitives (Conditional Access, Primary Refresh Token) and possibly an AI-mediated action-expansion entry.

Not on its own. BYOVD only earns a Microsoft CVE if a second primitive (network, user, AppContainer) is also crossed, or if the *driver vendor* receives the CVE. The Microsoft *Vulnerable Driver Blocklist* is feature hardening that ships in Windows updates, but the loadability of a properly-signed driver by an administrator is not a boundary crossing under the doctrine [@leviev-downdate-update].

No. AM-PPL is a *feature*. The Microsoft Learn page documents PPL as a hardening mechanism for anti-malware services [@ms-learn-am-ppl], and Gabriel Landau&apos;s *Inside Microsoft&apos;s Plan to Kill PPLFault* preserves the verbatim MSRC position: *&quot;Microsoft does not consider PPL to be a security boundary&quot;* [@landau-pplfault]. Microsoft will still ship PPLFault-class mitigations as feature hardening (build 25941 was the canary), but PPL-bypass reports that do not also cross another boundary do not earn standard Patch Tuesday bulletins.
&lt;h3&gt;Closing&lt;/h3&gt;
&lt;p&gt;The Administrator Protection addition is the most interesting recent move because it &lt;em&gt;closes&lt;/em&gt; the elevation-path gap that the entire UAC era could not close. Microsoft added the SMAA elevation path to the boundary table while leaving the admin-to-kernel primitive on the feature side. The result is a two-tier classification: UAC bypasses still do not get CVEs, but Administrator Protection bypasses do -- and Forshaw&apos;s nine pre-GA disclosures, all of which Microsoft &lt;em&gt;fixed&lt;/em&gt; (not &quot;by design&quot;-replied) are the public-record evidence that the new classification is operationally enforced [@pz-tracker-432313668]. The 2026 frontier is cloud-side and AI-mediated. The boundary list is still growing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The doctrine of what is a boundary is the silent gatekeeper of MSRC triage. Reading it is the difference between filing a useful report and getting back &quot;by design -- UAC is not a security boundary.&quot; Every Windows security engineer should be able to recite the boundary list from memory. After this article, you can.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;windows-security-boundaries-the-document-that-decides-what-gets-a-cve&quot; keyTerms={[
  { term: &quot;Security boundary&quot;, definition: &quot;A logical separation between security domains with different levels of trust, with security policy dictating what can pass through. Boundary crossings receive CVEs under the MSRC servicing criteria when severity meets the bar.&quot; },
  { term: &quot;Security feature&quot;, definition: &quot;A mechanism that raises the difficulty of attack but does not carry a vendor guarantee that policy holds. Feature defeats may still ship as security updates via the exception clause, but they are not boundary crossings.&quot; },
  { term: &quot;Two-question rule&quot;, definition: &quot;(1) Does the vulnerability violate the goal or intent of a security boundary or a security feature? (2) Does the severity meet the bar for servicing? Both yes = service via security update. Either no = by design / next version, with exceptions.&quot; },
  { term: &quot;System Managed Administrator Account (SMAA)&quot;, definition: &quot;The Administrator Protection elevation primitive: a hidden, profile-separated user account with its own SID, profile, and logon session, used to host elevated-administrator tokens authorised via Windows Hello.&quot; },
  { term: &quot;Trustlet&quot;, definition: &quot;A process running in VTL1 (Isolated User Mode), protected by the hypervisor from VTL0 (the normal kernel). LsaIso, the Isolated LSA Trustlet that holds Credential Guard credentials, is the canonical example.&quot; },
  { term: &quot;BYOVD&quot;, definition: &quot;Bring Your Own Vulnerable Driver: an administrator installs a legitimately-signed driver containing an exploitable vulnerability and uses the driver to obtain arbitrary kernel-mode code execution. Not a Microsoft boundary crossing because admin loads drivers by design.&quot; },
  { term: &quot;Protected Process Light (PPL)&quot;, definition: &quot;A signer-hierarchy mechanism introduced in Windows 8.1 that lets specially-signed processes refuse code injection and termination even from administrators. Microsoft explicitly classifies PPL as not a security boundary.&quot; },
  { term: &quot;Mandatory Integrity Control (MIC)&quot;, definition: &quot;Each securable object and access token carries an integrity level: Untrusted / Low / Medium / High / System. Lower-integrity subjects cannot write to higher-integrity objects regardless of DACL permissions.&quot; }
]} flashcards={[
  { front: &quot;Is UAC a security boundary?&quot;, back: &quot;No. UAC has been classified as a security feature, not a boundary, since Russinovich&apos;s June 2007 TechNet article. UACMe has documented more than 80 auto-elevation bypasses and zero CVEs.&quot; },
  { front: &quot;Is admin-to-kernel a security boundary?&quot;, back: &quot;No. Administrators can load drivers by design; drivers run in kernel mode. The Landau ItsNotASecurityBoundary repo name is an explicit homage to this MSRC policy.&quot; },
  { front: &quot;Is the Administrator Protection elevation path a security boundary?&quot;, back: &quot;Yes, as of 2025. The SMAA token has a separate SID, separate profile, and separate logon session from the user&apos;s standard-user token; the user boundary applies.&quot; },
  { front: &quot;Is HVCI a security boundary?&quot;, back: &quot;No. HVCI is a feature enforced inside VTL1. The VTL boundary is on the boundary list; HVCI is a feature that lives at that boundary.&quot; },
  { front: &quot;Is PPL a security boundary?&quot;, back: &quot;No. Microsoft has stated verbatim that &apos;Microsoft does not consider PPL to be a security boundary.&apos; AM-PPL is a feature that protects anti-malware services.&quot; },
  { front: &quot;Is bypassing Defender a CVE?&quot;, back: &quot;Only if the bypass also crosses another boundary. Defender-itself bypasses are feature defeats; Tavis Ormandy&apos;s 2014 to 2017 CVEs crossed the network boundary.&quot; },
  { front: &quot;Is same-user post-authentication a security boundary?&quot;, back: &quot;No. Once a process executes under a user&apos;s session, it inherits the user&apos;s trust. Forshaw&apos;s June 2024 Recall ACL post is the doctrinal anchor.&quot; },
  { front: &quot;Is guest-to-host on Hyper-V a security boundary?&quot;, back: &quot;Yes. It pays $5,000 to $250,000 USD under the Microsoft Hyper-V Bounty Program -- the highest single-finding payout in the Microsoft bounty catalogue.&quot; }
]} questions={[
  { q: &quot;Why is decoupling Question 1 (classification) from Question 2 (severity) the load-bearing engineering decision of the entire doctrine?&quot;, a: &quot;Because a single-question rule would collapse the doctrine into opaque MSRC judgment. Decoupling lets Microsoft commit to a published taxonomy on the classification half while retaining engineering judgment on severity, with the explicit exception clause as the relief valve in either direction.&quot; },
  { q: &quot;Explain why HVCI is on the feature list even though VTL is on the boundary list.&quot;, a: &quot;HVCI is a feature enforced inside VTL1, under the protection of the hypervisor. The VTL boundary protects HVCI from VTL0 attackers, but HVCI itself does not enforce a separation between security domains. The boundary is the VTL line; HVCI is one of the features that runs at that boundary.&quot; },
  { q: &quot;How did Administrator Protection close a gap that the entire UAC era could not?&quot;, a: &quot;By creating a new elevation primitive (the SMAA token) with a separate SID, separate profile, and separate logon session, so that the existing user boundary applies. The Russinovich-2007 shared-resources structural argument that disqualified UAC from boundary status no longer applies because the SMAA token does not share those resources with the standard-user token.&quot; },
  { q: &quot;Why does the absence of a UAC-bypass bounty matter for understanding the doctrine?&quot;, a: &quot;Because the bounty schedule mirrors the boundary list mechanically. Microsoft only pays standalone bounties for findings that violate primitives the company commits to defending. The absence of a UAC bounty is structural, not oversight: there is no boundary to violate, so there is nothing to pay for.&quot; },
  { q: &quot;Predict the MSRC disposition of a Defender bypass that allows malware to evade signature detection but does not introduce any other primitive. Justify your prediction.&quot;, a: &quot;By design / consider for next version. Defender is on the feature list (heuristic detection cannot guarantee detection); a signature-evasion technique is a feature defeat with no boundary crossing; the severity gate is satisfied only by Critical / Important impact, and a pure detection evasion typically does not meet the bar. The exception clause could fire for an unusually impactful detection-evasion technique, but the default disposition is by design.&quot; }
]} /&amp;gt;&lt;/p&gt;
&lt;p&gt;The boundary list. From memory. Now.&lt;/p&gt;
</content:encoded><category>windows-security</category><category>msrc</category><category>vulnerability-disclosure</category><category>security-boundaries</category><category>cve</category><category>patch-tuesday</category><category>uac</category><category>administrator-protection</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></channel></rss>