<?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: privilege-escalation</title><description>Posts tagged privilege-escalation.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:06 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/privilege-escalation/rss.xml" rel="self" type="application/rss+xml"/><item><title>A Mitigation That Became a Primitive: The Story of SeImpersonatePrivilege</title><link>https://paragmali.com/blog/a-mitigation-that-became-a-primitive-the-story-of-seimperson/</link><guid isPermaLink="true">https://paragmali.com/blog/a-mitigation-that-became-a-primitive-the-story-of-seimperson/</guid><description>How a 2003 backward-compatibility privilege became the most-abused Windows service primitive, and why every Microsoft closure path breaks something shipped.</description><pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate><content:encoded>
Any Windows process running as `IIS APPPOOL\...`, `MSSQLSERVER`, or any other LOCAL SERVICE or NETWORK SERVICE-derived account holds one privilege -- `SeImpersonatePrivilege` -- that is sufficient, given any token-source primitive, to become `NT AUTHORITY\SYSTEM`. The privilege was introduced in Windows Server 2003 as a *mitigation*, so that lower-privileged service accounts could keep impersonating their RPC clients after Microsoft moved services off `SYSTEM`. Eighteen years of named-exploit lineage -- Token Kidnapping (2008), HotPotato (2016), RottenPotato, JuicyPotato, PrintSpoofer, GodPotato, LocalPotato, SilverPotato -- all ride on the same three-piece system: the privilege, the `ImpersonateNamedPipeClient` API, and Microsoft&apos;s documented decision to treat Windows Service Hardening as a *safety* boundary rather than a *security* boundary. This article explains why every closure path Microsoft has shipped narrows the surface without closing it, and why the primitive is structurally undefeated in 2026.
&lt;h2&gt;1. The One Line in &lt;code&gt;whoami /priv&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Open a shell inside any IIS application pool worker, any SQL Server service-step process, or any Exchange worker on a fully patched Windows 11 24H2 or Server 2025 box in 2026, and type &lt;code&gt;whoami /priv&lt;/code&gt;. One line will read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SeImpersonatePrivilege  Impersonate a client after authentication  Enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That single line is sufficient, given the right coercion primitive, to become &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt; in under a second. Microsoft has known this on the record since April 2009 [@msrc-blog-2009-04-token-kidnapping]. The privilege has not moved.&lt;/p&gt;

A Windows user right that lets a process call any of the kernel&apos;s token-substitution APIs on a token it has received from another principal. The right is enumerated as the constant `SE_IMPERSONATE_NAME` [@ms-learn-privilege-constants]. It is assigned by default to `LOCAL SERVICE`, `NETWORK SERVICE`, the local Administrators group, and every Windows service that runs under one of those accounts [@ms-learn-impersonate-policy].

Two well-known Windows accounts introduced in Windows Server 2003 / XP SP2 as a hardening alternative to running services under `NT AUTHORITY\SYSTEM`. The Microsoft Learn account documentation lists each account&apos;s default privilege set; in both cases `SE_IMPERSONATE_NAME` appears with the marker `(enabled)` [@ms-learn-localservice; @ms-learn-networkservice].
&lt;p&gt;The Microsoft Learn pages list this assignment as a default. &quot;Enabled&quot; is a token-state distinction with operational weight. Most privileges in a service-account token are &lt;em&gt;present but disabled&lt;/em&gt;: the process can call &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt; to turn them on, but until that happens the kernel treats the privilege as absent during access checks. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; on a NETWORK SERVICE token is shipped &lt;em&gt;enabled&lt;/em&gt;. The process can call &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; immediately, on first instruction.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; There is a real semantic difference between a privilege that is present-but-disabled and a privilege that is enabled. The kernel checks the &lt;em&gt;enabled&lt;/em&gt; bit during access decisions. A NETWORK SERVICE process does not need to elevate the privilege before using it; the token already has it in the active state. This is the reason a freshly spawned IIS worker is one well-aimed coercion away from SYSTEM, with no preparatory steps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Andrea Pierini, the researcher who has spent more time with this primitive than anyone outside Microsoft, put the operational fact in eleven words: &quot;if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM&quot; [@labro-2020-printspoofer-post]. Clement Labro, quoting him, added the qualifier: &quot;a deliberately provocative shortcut obviously, but it&apos;s not far from the truth.&quot; The aphorism gets repeated in every PrintSpoofer-era writeup for a reason.&lt;/p&gt;
&lt;p&gt;Here is the article&apos;s load-bearing claim, stated up front and re-argued through every section that follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Microsoft gave every NETWORK SERVICE a privilege that, in the wrong hands, is equivalent to SYSTEM. They knew. They could not change it without breaking the service model. Roughly eighteen years after Cerrudo first put that fact on the record -- and ten years after HotPotato made it pushbutton -- they still have not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The figure &quot;roughly eighteen years&quot; anchors to Cesar Cerrudo&apos;s March 2008 disclosure at Hack In The Box Dubai [@cerrudo-2008-pdf]. The privilege itself shipped earlier, in Server 2003 / XP SP2 (2003-2004), and the operational-pushbutton anchor is Stephen Breen&apos;s HotPotato (January 16, 2016) [@breen-2016-hot-potato]. Three different dates, three different anchors for &quot;how long has this been true.&quot; The article uses the Cerrudo date because that is when the fact entered the offensive-research public record.&lt;/p&gt;
&lt;p&gt;From here, this article traces the privilege from a 2003 backward-compatibility concession to a 2024 Troopers articulation by Pierini and Cocomazzi, and explains why every closure path Microsoft has shipped narrows the surface without closing it.&lt;/p&gt;
&lt;p&gt;{`
// On a Windows service account, this is the line that matters:
const tokenPrivileges = [
  { name: &apos;SeAssignPrimaryTokenPrivilege&apos;, state: &apos;Disabled&apos; },
  { name: &apos;SeIncreaseQuotaPrivilege&apos;,      state: &apos;Disabled&apos; },
  { name: &apos;SeAuditPrivilege&apos;,              state: &apos;Disabled&apos; },
  { name: &apos;SeChangeNotifyPrivilege&apos;,       state: &apos;Enabled&apos;  },
  { name: &apos;SeImpersonatePrivilege&apos;,        state: &apos;Enabled&apos;  },  // &amp;lt;-- the gate
  { name: &apos;SeCreateGlobalPrivilege&apos;,       state: &apos;Enabled&apos;  },
];&lt;/p&gt;
&lt;p&gt;const gateOpen = tokenPrivileges.some(
  p =&amp;gt; p.name === &apos;SeImpersonatePrivilege&apos; &amp;amp;&amp;amp; p.state === &apos;Enabled&apos;
);
console.log(gateOpen ? &apos;Gate is open. Token-source primitive is the only missing piece.&apos; : &apos;Gate is closed.&apos;);
`}&lt;/p&gt;
&lt;p&gt;If one line in &lt;code&gt;whoami /priv&lt;/code&gt; is sufficient to become SYSTEM, why does Microsoft ship that line as the default for every IIS application pool, every SQL Server service step, and every Exchange worker process on every shipping Windows release? The answer is not a mistake. It is a decision -- and to understand it we need to go back to a Tymshare FORTRAN compiler in the late 1970s, around 1977 by Hardy&apos;s own &quot;about eleven years ago&quot; dating from his 1988 paper.&lt;/p&gt;
&lt;h2&gt;2. Hardy&apos;s Deputy and the 2003 Service-Hardening Pivot&lt;/h2&gt;
&lt;p&gt;In the late 1970s, around 1977, a Tymshare engineer named Norm Hardy watched a FORTRAN compiler with &quot;home files license&quot; overwrite the system billing file &lt;code&gt;(SYSX)BILL&lt;/code&gt; because some user had passed that path as the compiler&apos;s debug-output target. The compiler had two authorities -- its own (to read system libraries) and the caller&apos;s (to write the caller&apos;s files) -- and no way to keep them separate when serving a request. The compiler was, in Hardy&apos;s later phrasing, &lt;em&gt;confused&lt;/em&gt; about which authority to use [@hardy-1988].&lt;/p&gt;

A program that holds authority on behalf of two or more principals at once and has no architectural way to keep those authorities separate when acting on a request. Hardy&apos;s 1988 paper [@hardy-1988] argues that any identity-and-ACL system in which a server holds more authority than its clients and acts on client requests has a confused-deputy attack surface by construction. The only complete defence, Hardy argues, is capability-based access control.
&lt;p&gt;Hardy&apos;s argument generalises: as long as authority flows ambiently with identity rather than being passed explicitly with each request, a server cannot reliably tell whose authority a given request should run under. This is not a bug class. It is a structural property of the access-matrix model Lampson formalised in 1971 [@lampson-1971]. Windows is an instance of that model. A NETWORK SERVICE process holding &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is &lt;em&gt;Hardy&apos;s deputy&lt;/em&gt;: it carries two authorities at once (its own modest service identity and whatever caller just connected to its named pipe), and Windows has no in-architecture way to keep them apart.&lt;/p&gt;

Capability systems -- EROS, Coyotos, seL4 -- bind authority to operations rather than to running identities. A capability is an unforgeable token that names both an object and the rights you have on it; you cannot exercise authority you were not handed. In a capability system, Hardy&apos;s compiler would have been handed a capability only for the file the caller actually wanted opened, and the bill-overwrite would have been mechanically prevented. Windows shipped the alternative design in 1993 -- identity-and-ACL with kernel tokens carrying ambient authority -- and the rest of this article is, in a precise sense, the story of what that design costs eighteen years on. Section 8 returns to this thread.
&lt;h3&gt;2.1 The kernel object Cutler&apos;s team shipped in 1993&lt;/h3&gt;
&lt;p&gt;Dave Cutler&apos;s NT 3.1 team chose the identity-and-ACL model and built a kernel object to carry it. The &lt;em&gt;access token&lt;/em&gt; is what an NT thread or process holds; it enumerates the user SID, the group SIDs, and the privileges currently associated with the running code. Every access check the kernel performs reduces to &quot;does this token, evaluated against this object&apos;s ACL, grant the requested rights?&quot; The standard reference is &lt;em&gt;Windows Internals&lt;/em&gt;, Part 1, chapter on security [@ms-learn-windows-internals].&lt;/p&gt;

A kernel object the Windows security subsystem creates at logon (and clones on demand). It carries the user SID, group SIDs, privileges, integrity level, and impersonation level for a running thread or process. Tokens come in two flavours: *primary* (attached to a process at creation) and *impersonation* (attached to a thread to make it temporarily act as another identity).
&lt;p&gt;NT 3.1 also shipped two structural distinctions that the rest of this article depends on. First, &lt;em&gt;primary&lt;/em&gt; versus &lt;em&gt;impersonation&lt;/em&gt; tokens -- a primary token is what a process is born with; an impersonation token is what a thread can wear temporarily to act on behalf of someone else. Second, the four &lt;em&gt;impersonation levels&lt;/em&gt; (Anonymous, Identification, Impersonation, Delegation), each granting progressively more authority to act under the borrowed identity. Both distinctions exist because servers need to act on client requests under the client&apos;s authority -- and both distinctions are the surface every Potato variant operates on.&lt;/p&gt;
&lt;p&gt;The Tymshare anecdote that Hardy uses in the 1988 paper -- the FORTRAN compiler that overwrote &lt;code&gt;(SYSX)BILL&lt;/code&gt; -- is worth recounting in full because it is structurally identical to the Windows scenario. A user invoked the compiler with the billing information file as the debug-output target. The compiler had write access to system files (it was a &quot;home files license&quot; service). The compiler dutifully opened the user-supplied path under its own authority and wrote debug output to it, destroying the bill. The compiler was not malicious; it had no way to ask the OS to scope its write to &quot;only files the caller could write.&quot; Hardy&apos;s own dating in the paper is &quot;about eleven years ago&quot; from 1988 -- so the events sit in the late 1970s, not the early ones.&lt;/p&gt;
&lt;h3&gt;2.2 Why the privilege exists: the 2003 service-hardening pivot&lt;/h3&gt;
&lt;p&gt;Through the 1990s, Windows services almost universally ran under &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt;. The convenience was operational: SYSTEM is the local-machine principal and holds every right the kernel knows about, so a service running as SYSTEM never needed an explicit privilege grant. The cost became visible in 2001-2003 as the first generation of service-borne worms hit production: Code Red and Nimda (2001) walked IIS; SQL Slammer and MSBlast (2003) walked SQL Server and the DCOM RPC endpoint [@wikipedia-timeline-worms]. Every successful remote code execution against a service became a SYSTEM compromise of the host, because the service &lt;em&gt;was&lt;/em&gt; SYSTEM.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response was a structural retreat. Two new well-known accounts shipped in Windows Server 2003 (and reached desktop with XP SP2 in 2004): &lt;code&gt;NT AUTHORITY\LOCAL SERVICE&lt;/code&gt; (no network credentials) and &lt;code&gt;NT AUTHORITY\NETWORK SERVICE&lt;/code&gt; (machine-account credentials when authenticating off-box). The two account documentation pages enumerate the default privileges the SCM assigns when a service is configured to run under either account [@ms-learn-localservice; @ms-learn-networkservice]. Most of the SYSTEM-only privileges -- &lt;code&gt;SeTcbPrivilege&lt;/code&gt;, &lt;code&gt;SeLoadDriverPrivilege&lt;/code&gt;, &lt;code&gt;SeRestorePrivilege&lt;/code&gt; -- are absent from the enumerated default sets [@ms-learn-localservice; @ms-learn-networkservice]. The intent was clear: a worm-popped IIS worker should land as a low-privileged process, not as SYSTEM.&lt;/p&gt;
&lt;p&gt;But the new accounts could not lose &lt;em&gt;every&lt;/em&gt; SYSTEM authority. Pre-2003 services routinely impersonated their clients to make access checks against per-user resources -- IIS reading a user&apos;s home directory under the user&apos;s identity, SQL Server enforcing per-login row security, the SMB server returning per-user file lists. That entire pattern depended on the service being able to call &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; (or &lt;code&gt;RpcImpersonateClient&lt;/code&gt;, or one of the LSA-side APIs) and then act under the caller&apos;s token. If LOCAL SERVICE and NETWORK SERVICE could not impersonate, the entire RPC server population would break.&lt;/p&gt;
&lt;p&gt;So Microsoft introduced &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; -- a new named user right gating the impersonation APIs -- and assigned it by default to LOCAL SERVICE, NETWORK SERVICE, the local Administrators group, and (via the SCM&apos;s auto-grant logic) every service configured to run under one of those accounts [@ms-learn-impersonate-policy]. The policy-setting page is explicit about the intent: &quot;If this user right is required for this type of impersonation, an unauthorized user cannot cause a client to connect (for example, by remote procedure call (RPC) or named pipes) to a service that they have created to impersonate that client&quot; [@ms-learn-impersonate-policy].&lt;/p&gt;
&lt;p&gt;The privilege, in other words, was created &lt;em&gt;as a mitigation&lt;/em&gt;. Its purpose was to keep impersonation working for legitimate service-account RPC servers while denying it to ordinary user processes. That decision -- to gate impersonation on an explicit named right rather than to forbid impersonation outright -- is the architectural pivot the rest of this article re-examines from every angle.&lt;/p&gt;

flowchart TD
    Client[&quot;Low-privileged caller&quot;] -- &quot;Connects to attacker pipe&quot; --&amp;gt; NS[&quot;NETWORK SERVICE process&quot;]
    NS -- &quot;Holds its own modest authority&quot; --&amp;gt; A1[&quot;Authority 1, service identity&quot;]
    NS -- &quot;Holds SeImpersonatePrivilege&quot; --&amp;gt; A2[&quot;Authority 2, any token it receives&quot;]
    SYSPROC[&quot;Privileged caller, SYSTEM&quot;] -- &quot;Coerced to authenticate to the pipe&quot; --&amp;gt; NS
    NS -- &quot;Impersonate caller token, then act&quot; --&amp;gt; Action[&quot;Action runs under SYSTEM&quot;]
&lt;p&gt;Microsoft did not introduce &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; to enable an exploit. They introduced it as a backward-compatibility concession. So why did the privilege become the dominant lineage of service-to-SYSTEM elevation for nearly two decades? The answer starts with the API surface.&lt;/p&gt;
&lt;h2&gt;3. The Token API Surface&lt;/h2&gt;
&lt;p&gt;There is no single &quot;impersonate&quot; API on Windows. There are four substitution APIs that put a token on a thread or a new process, and one coercion API that supplies the token in the first place. The Potato family lives at the intersection of all five.&lt;/p&gt;
&lt;h3&gt;3.1 Primary versus impersonation tokens&lt;/h3&gt;
&lt;p&gt;The kernel distinguishes &lt;code&gt;TOKEN_PRIMARY&lt;/code&gt; from &lt;code&gt;TOKEN_IMPERSONATION&lt;/code&gt;. A primary token is what a process is created with; an impersonation token can be attached only to a thread. The distinction matters operationally because only an impersonation token at level &lt;code&gt;SecurityImpersonation&lt;/code&gt; or &lt;code&gt;SecurityDelegation&lt;/code&gt; lets you take real action under the borrowed identity. An &lt;code&gt;Identification&lt;/code&gt;-level token can be checked against ACLs but cannot be used to open kernel objects under the new identity, and an &lt;code&gt;Anonymous&lt;/code&gt;-level token is useless for almost everything [@ms-learn-windows-internals; @ms-learn-impersonateloggedonuser].&lt;/p&gt;

A *primary token* is created at logon and attached to a process for its lifetime; the kernel uses it for every access check the process makes by default. An *impersonation token* is attached to an individual thread by `SetThreadToken` (or by an impersonation API that calls it internally) and overrides the primary token for that thread only. The kernel reserves the right to demote impersonation tokens to `Identification` level in cross-machine RPC scenarios where delegation has not been explicitly negotiated.

A four-value enum -- `SecurityAnonymous`, `SecurityIdentification`, `SecurityImpersonation`, `SecurityDelegation` -- carried on every impersonation token. It limits what the impersonating thread can do under the borrowed identity. `SecurityImpersonation` is the level a service can act under for local access checks; `SecurityDelegation` extends that to off-box authentication and is the level the LocalPotato class occasionally reaches.
&lt;p&gt;The Potato lineage navigates these four levels with care. &lt;code&gt;Identification&lt;/code&gt; is harmless because it cannot spawn a process under the borrowed identity; &lt;code&gt;Impersonation&lt;/code&gt; is the level a service can act under for any local kernel object; &lt;code&gt;Delegation&lt;/code&gt; is what cross-host variants such as SilverPotato sometimes need.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;SecurityIdentification&lt;/code&gt; versus &lt;code&gt;SecurityImpersonation&lt;/code&gt; distinction is the gate that makes many naive coercion attempts fail. If the attacker controls only an RPC interface that performs an &lt;code&gt;ImpersonateClient&lt;/code&gt; call without the right SQOS (Security Quality of Service) negotiation, the resulting token may land at &lt;code&gt;SecurityIdentification&lt;/code&gt; -- usable for &lt;code&gt;AccessCheck&lt;/code&gt;, useless for &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt;. Each Potato variant either chooses a coercion primitive that arrives at &lt;code&gt;SecurityImpersonation&lt;/code&gt; or upgrades the token via a subsequent &lt;code&gt;DuplicateTokenEx&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;3.2 The substitution primitives&lt;/h3&gt;
&lt;p&gt;Four APIs move tokens around the system. None of them produces a token from nothing; all of them assume the caller already has a handle to one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SetThreadToken&lt;/code&gt; -- attach an impersonation token to a thread [@ms-learn-setthreadtoken]. The thread now runs under the borrowed identity for every subsequent access check.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ImpersonateLoggedOnUser&lt;/code&gt; -- the thread-level convenience wrapper [@ms-learn-impersonateloggedonuser]. Same effect as &lt;code&gt;SetThreadToken&lt;/code&gt;, with simpler arguments.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DuplicateTokenEx&lt;/code&gt; -- create a new token from an existing one, with adjustable type (primary vs impersonation) and level (the four-value enum above) [@ms-learn-duplicatetokenex]. The Potato lineage uses this to convert an impersonation token into a primary one before launching a process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; -- spawn a new process under an arbitrary primary token [@ms-learn-createprocesswithtokenw]. The Microsoft Learn documentation is explicit about the gate: &quot;The process that calls &lt;strong&gt;CreateProcessWithTokenW&lt;/strong&gt; must have the &lt;code&gt;SE_IMPERSONATE_NAME&lt;/code&gt; privilege.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last sentence is the keystone. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is not just &quot;the right to impersonate.&quot; It is the right to convert an impersonated identity into a fresh process that owns the desktop, the registry, the file system, and every other kernel object the borrowed identity has authority over. Without the privilege, the attacker has a thread temporarily wearing SYSTEM&apos;s hat; with it, the attacker has &lt;code&gt;cmd.exe&lt;/code&gt; running as SYSTEM until the system reboots.&lt;/p&gt;
&lt;h3&gt;3.3 The coercion primitive&lt;/h3&gt;
&lt;p&gt;The three substitution primitives are inert without a token to substitute. The dominant token source on Windows is the named-pipe server primitive &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;, shipped since Windows XP / Server 2003 [@ms-learn-impersonatenamedpipeclient]. Any process that owns a named pipe can call this API after a client connects; the impersonating thread then wears the caller&apos;s token at whatever impersonation level the caller&apos;s SQOS negotiated.&lt;/p&gt;

A Win32 API that copies the connected client&apos;s access token onto the calling thread, after which the thread acts under the client&apos;s identity until `RevertToSelf` is called. The API has shipped since Windows XP / Server 2003 [@ms-learn-impersonatenamedpipeclient]. It is the load-bearing token source for every Potato variant from HotPotato through GodPotato. Calling the API at higher than `SecurityIdentification` requires `SeImpersonatePrivilege` on the caller.
&lt;p&gt;This is the four-step chain every Potato operator runs, as enumerated in Forshaw&apos;s 2021 Project Zero retrospective on the lineage [@forshaw-2021-10-relaying-dcom-pz]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;CreateNamedPipe(&quot;\\.\pipe\&amp;lt;attacker_name&amp;gt;&quot;)&lt;/code&gt; -- a service-account process opens a pipe it controls.&lt;/li&gt;
&lt;li&gt;Induce some privileged Windows component to authenticate to that pipe.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; -- the impersonating thread now wears the caller&apos;s token.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DuplicateTokenEx&lt;/code&gt; to primary; &lt;code&gt;CreateProcessWithTokenW(cmd.exe)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

sequenceDiagram
    participant Atk as Attacker, service account
    participant Pipe as Named pipe attacker controls
    participant Sys as Privileged caller, SYSTEM-context
    Atk-&amp;gt;&amp;gt;Pipe: CreateNamedPipe and listen
    Atk-&amp;gt;&amp;gt;Sys: Trigger coercion primitive
    Sys-&amp;gt;&amp;gt;Pipe: Authenticate to the pipe
    Atk-&amp;gt;&amp;gt;Pipe: ImpersonateNamedPipeClient
    Atk-&amp;gt;&amp;gt;Atk: DuplicateTokenEx, impersonation to primary
    Atk-&amp;gt;&amp;gt;Atk: CreateProcessWithTokenW cmd.exe
    Note over Atk: cmd.exe now running as SYSTEM
&lt;p&gt;Step three depends on step two. Step two is the open question every generation of Potato has answered differently -- and that Microsoft has patched, one token source at a time, for nearly two decades.&lt;/p&gt;
&lt;p&gt;{`
// Pseudocode showing the four-step Potato chain.
// Privilege checks shown as comments where the kernel enforces them.&lt;/p&gt;
&lt;p&gt;function impersonationChain(coercionTrigger) {
  const pipe = createNamedPipe(&quot;\\.\pipe\demo&quot;);            // no privilege required
  coercionTrigger(pipe);                                          // induce SYSTEM to connect
  pipe.waitForConnect();&lt;/p&gt;
&lt;p&gt;  // kernel allows SecurityImpersonation only if caller has SeImpersonatePrivilege:
  const callerToken = pipe.impersonateNamedPipeClient();&lt;/p&gt;
&lt;p&gt;  const primary = duplicateTokenEx(callerToken, &quot;primary&quot;,
                                   &quot;SecurityImpersonation&quot;);      // no privilege required&lt;/p&gt;
&lt;p&gt;  // kernel gate: requires SE_IMPERSONATE_NAME on the calling process:
  return createProcessWithTokenW(primary, &quot;cmd.exe&quot;);
}
`}&lt;/p&gt;
&lt;h3&gt;3.4 The privilege next to it&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; is gated on &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;. Its sibling &lt;code&gt;CreateProcessAsUser&lt;/code&gt; is gated on a &lt;em&gt;different&lt;/em&gt; pair of privileges -- &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt; (constant name &lt;code&gt;SE_ASSIGNPRIMARYTOKEN_NAME&lt;/code&gt;) when the supplied token is not assignable by the caller, plus &lt;code&gt;SeIncreaseQuotaPrivilege&lt;/code&gt; (&lt;code&gt;SE_INCREASE_QUOTA_NAME&lt;/code&gt;) in all cases. Both are enumerated separately in the privilege-constants table [@ms-learn-privilege-constants]. On a NETWORK SERVICE or LOCAL SERVICE token, &lt;code&gt;SE_ASSIGNPRIMARYTOKEN_NAME&lt;/code&gt; and &lt;code&gt;SE_INCREASE_QUOTA_NAME&lt;/code&gt; are both &lt;em&gt;present but disabled&lt;/em&gt; [@ms-learn-localservice; @ms-learn-networkservice]: a service-account process must call &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt; to enable them before &lt;code&gt;CreateProcessAsUser&lt;/code&gt; will succeed, whereas &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is shipped &lt;em&gt;enabled&lt;/em&gt; and &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; works on the first instruction. Pierini&apos;s aphorism quoted in section 1 names both privileges because either one independently makes the same chain runnable -- but on a vanilla NETWORK SERVICE token, only &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is enabled, and the rest of this article treats it as the privilege that matters in practice.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Privilege required&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none for &lt;code&gt;SecurityIdentification&lt;/code&gt; or &lt;code&gt;SecurityAnonymous&lt;/code&gt;; for higher levels, either &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;, or the token was created with explicit credentials via &lt;code&gt;LogonUser&lt;/code&gt;/&lt;code&gt;LsaLogonUser&lt;/code&gt; from within the caller&apos;s logon session, or the authenticated identity is the same as the caller (see [@ms-learn-impersonatenamedpipeclient])&lt;/td&gt;
&lt;td&gt;connected pipe handle&lt;/td&gt;
&lt;td&gt;impersonation token on thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ImpersonateLoggedOnUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none (caller must already hold the token)&lt;/td&gt;
&lt;td&gt;token handle&lt;/td&gt;
&lt;td&gt;impersonation token on thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SetThreadToken&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;depends on token level&lt;/td&gt;
&lt;td&gt;token handle&lt;/td&gt;
&lt;td&gt;impersonation token on thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DuplicateTokenEx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;source token&lt;/td&gt;
&lt;td&gt;new token, type/level adjustable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CreateProcessWithTokenW&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;primary token + command line&lt;/td&gt;
&lt;td&gt;new process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CreateProcessAsUser&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;primary token + command line&lt;/td&gt;
&lt;td&gt;new process&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

flowchart LR
    Process[&quot;Process, holds primary token&quot;]
    Thread[&quot;Thread, optional impersonation token&quot;]
    NewProc[&quot;New process, spawned with chosen primary token&quot;]
    Process -- &quot;OpenProcessToken, read&quot; --&amp;gt; TH[&quot;Token handle&quot;]
    TH -- &quot;SetThreadToken or ImpersonateLoggedOnUser&quot; --&amp;gt; Thread
    Thread -- &quot;GetThreadToken&quot; --&amp;gt; TH
    TH -- &quot;DuplicateTokenEx, impersonation to primary&quot; --&amp;gt; PT[&quot;Primary token handle&quot;]
    PT -- &quot;CreateProcessWithTokenW, gated on SeImpersonatePrivilege&quot; --&amp;gt; NewProc
    Pipe[&quot;Connected named pipe&quot;] -- &quot;ImpersonateNamedPipeClient, gated on SeImpersonatePrivilege beyond SecurityIdentification&quot; --&amp;gt; Thread
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The five-API surface decomposes cleanly into two halves. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is the kernel-side &lt;em&gt;gate&lt;/em&gt; that decides whether a process can substitute an arbitrary primary token into a new process. &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; is the user-mode &lt;em&gt;source&lt;/em&gt; that provides the token in the first place. Closing one half closes the surface. Closing neither half is the choice Microsoft has shipped for twenty years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So how do you get a SYSTEM-context Windows process to authenticate to a pipe you control? Cesar Cerrudo asked that question in 2008 -- and his answer was just the first of five.&lt;/p&gt;
&lt;h2&gt;4. Five Generations of Token Sources, One Constant Privilege&lt;/h2&gt;
&lt;p&gt;Cesar Cerrudo had the privilege figured out in March 2008. So why did it take until January 2016 for HotPotato to make the chain pushbutton, until July 2018 for JuicyPotato to industrialise it, and until December 2022 for GodPotato to bypass the most aggressive DCOM hardening Microsoft has shipped? Because every generation answered the same question -- &lt;em&gt;where do the tokens come from?&lt;/em&gt; -- differently, and Microsoft patched each token source one at a time.&lt;/p&gt;
&lt;p&gt;This section is &lt;em&gt;generation-level&lt;/em&gt;. The variant-by-variant chronology of every named Potato lives in the &lt;a href=&quot;https://paragmali.com/blog/system-in-ten-seconds-how-the-potato-family-survived-every-m/&quot; rel=&quot;noopener&quot;&gt;sibling Potato Family article&lt;/a&gt; (2026-05-31); here, variants appear only as evidence for claims about the primitive.&lt;/p&gt;
&lt;h3&gt;4.1 Generation 1, direct token theft (2008-2010)&lt;/h3&gt;
&lt;p&gt;Cerrudo&apos;s HITB Dubai 2008 paper, &lt;em&gt;Token Kidnapping&lt;/em&gt;, named the privilege and named the technique [@cerrudo-2008-pdf]. The chain ran inside an MSSQL or IIS process and looked like this: enumerate processes the service account could open; find a thread that was already impersonating a higher-privileged token (typically leaked by some service-startup path); &lt;code&gt;DuplicateTokenEx&lt;/code&gt; that token; &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; to spawn &lt;code&gt;cmd.exe&lt;/code&gt; under the new identity. Two years later, at DEF CON 18, Cerrudo presented &lt;em&gt;Token Kidnapping&apos;s Revenge&lt;/em&gt; with fresh examples and a community-canonical title for the technique [@cerrudo-2010-defcon].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response was MS09-012 in April 2009 (community-known as the &lt;em&gt;Chimichurri&lt;/em&gt; fix, after Cesar Cerrudo&apos;s PoC of the same name shipped by Argeniss alongside the disclosure [@webarchive-argeniss-chimichurri; @forshaw-2020-01-empirical-wsh]). The MSRC blog post announcing the bulletin is unusually clear about what it closed and what it deliberately did not:&lt;/p&gt;

An attacker can escalate their privileges on a system if they can control the SeImpersonatePrivilege token. An attacker would need to be executing code in the context of a Windows service to use this exploit. -- MSRC blog, April 14, 2009 [@msrc-blog-2009-04-token-kidnapping]
&lt;p&gt;The MSRC text continues: &quot;the first update addresses service isolation, while the second addresses processes running as service accounts&quot; [@msrc-blog-2009-04-token-kidnapping]. &lt;em&gt;Service isolation&lt;/em&gt;, not the privilege itself. The bulletin closed the specific handle-leak surface Cerrudo had used -- it did not revoke &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; from NETWORK SERVICE, did not modify &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt;, did not modify &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;. The MSRC acknowledged on the record that the privilege was sufficient for the escalation and elected to fix the &lt;em&gt;symptom&lt;/em&gt; (the leak surface), not the &lt;em&gt;gate&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is the supersession pattern that every subsequent generation follows: Microsoft patches the current token source; the next generation finds a new one within months.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Chimichurri&lt;/em&gt; (sometimes &lt;code&gt;Chimichurri.exe&lt;/code&gt;) is not a Microsoft codename. It is the name Cesar Cerrudo gave to the PoC exploit Argeniss released alongside the MS09-012 bulletin, hosted at the time at &lt;code&gt;argeniss.com/research/Chimichurri_CesarCerrudo.zip&lt;/code&gt; and preserved in the Internet Archive [@webarchive-argeniss-chimichurri]. Microsoft&apos;s own naming for the bulletin is simply MS09-012 / KB959454. Offensive-research convention has used &quot;Chimichurri&quot; as shorthand for the Cerrudo PoC ever since -- never for a Microsoft internal codename. Forshaw&apos;s January 2020 service-hardening retrospective references the same Cerrudo / Argeniss lineage [@forshaw-2020-01-empirical-wsh].&lt;/p&gt;
&lt;p&gt;Cerrudo presented the 2008 paper under his Argeniss affiliation and the 2010 DEF CON talk under IOActive [@cerrudo-2008-pdf; @cerrudo-2010-defcon]. The affiliation change occasionally trips up archival cross-referencing -- the work is the same lineage.&lt;/p&gt;
&lt;h3&gt;4.2 Generation 2, local NTLM cross-protocol reflection (2014-2016)&lt;/h3&gt;
&lt;p&gt;In December 2014, James Forshaw filed Project Zero Issue 222 -- a WebDAV-to-SMB local NTLM reflection that turned the Windows authentication redirector into a self-service token source. Stephen Breen&apos;s &lt;em&gt;HotPotato&lt;/em&gt; (January 16, 2016) used a related local-NTLM-relay primitive to deliver the first end-to-end service-account-to-SYSTEM chain that did not depend on finding a leaked token handle [@breen-2016-hot-potato]. Breen credits the genealogy openly: &quot;If this sounds vaguely familiar, it&apos;s because a similar technique was disclosed by the guys at Google Project Zero . . . In fact, some of our code was shamelessly borrowed from their PoC and expanded upon&quot; [@breen-2016-hot-potato].&lt;/p&gt;
&lt;p&gt;The conceptual leap is the one every subsequent generation depends on. Cerrudo&apos;s G1 had to &lt;em&gt;find&lt;/em&gt; a high-privileged token leaked into the local process tree; Breen&apos;s G2 &lt;em&gt;makes the system hand you one&lt;/em&gt; by coercing it to authenticate. The system itself becomes the token source. Forshaw articulated this generalisation explicitly in the 2021 Project Zero retrospective on the entire lineage [@forshaw-2021-10-relaying-dcom-pz].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response was MS16-075 (the SMB-side fix) and a handful of WPAD-hardening rollups. The chain became fragile and stopped being pushbutton -- but, again, none of these changes touched &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;4.3 Generation 3, local DCOM activation (2016-2018)&lt;/h3&gt;
&lt;p&gt;Within months of HotPotato, the community converged on a more reliable coercion primitive: a forged DCOM &lt;code&gt;OBJREF&lt;/code&gt; marshalled with an attacker-chosen OXID resolver. The trick induces a SYSTEM-context COM server to authenticate to a named pipe the attacker controls. Forshaw had reported the underlying primitive at Project Zero in 2015 as Issue 325, fixed as CVE-2015-2370 [@nvd-cve-2015-2370], but as his 2021 retrospective notes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;The technique to locally relay authentication for DCOM was something I originally reported back in 2015 (issue 325). This issue was fixed as CVE-2015-2370, however the underlying authentication relay using DCOM remained. This was repurposed and expanded upon by various others for local and remote privilege escalation in the RottenPotato series of exploits, the latest in that line being RemotePotato which is currently unpatched as of October 2021.&quot; [@forshaw-2021-10-relaying-dcom-pz]&lt;/p&gt;
&lt;/blockquote&gt;

The DCOM service that maps an OXID (Object Exporter Identifier) to the RPC binding string a client uses to call methods on a marshalled COM object. The &quot;Rotten&quot; and &quot;Juicy&quot; Potato families forge `OBJREF` marshalled blobs in which the OXID resolver field points back at an attacker-controlled endpoint, causing the SYSTEM-context RPCSS to authenticate to the attacker&apos;s pipe when it tries to resolve the OXID.
&lt;p&gt;RottenPotato (September 26, 2016) demonstrated the chain [@foxglove-2016-09-rotten-potato]; JuicyPotato (July 2018) industrialised it with a configurable CLSID table and reliable pipe handling. The canonical mirror for the JuicyPotato repository is the &lt;code&gt;ohpe/juicy-potato&lt;/code&gt; GitHub project [@ohpe-juicy-potato-repo]. Crucially, the load-bearing API was still &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; -- the DCOM trick is just the &lt;em&gt;vehicle&lt;/em&gt; that delivers a SYSTEM-context authentication to the attacker&apos;s pipe.&lt;/p&gt;
&lt;h3&gt;4.4 Generation 4, coercion APIs beyond DCOM (2020-2024)&lt;/h3&gt;
&lt;p&gt;Clement Labro (itm4n) shipped PrintSpoofer on April 28, 2020 [@labro-2020-printspoofer-post; @itm4n-printspoofer-repo]. The coercion primitive was MS-RPRN&apos;s &lt;code&gt;RpcRemoteFindFirstPrinterChangeNotificationEx&lt;/code&gt; -- an RPC method on the Print Spooler that takes an attacker-supplied UNC-like notification target and authenticates to it under the Spooler&apos;s SYSTEM identity. PrintSpoofer needed neither DCOM nor any leaked handle; the coercion primitive lived inside a always-running Windows service.&lt;/p&gt;
&lt;p&gt;PrintSpoofer generalised. Researchers quickly mapped a family of Windows RPC interfaces with the same shape -- an RPC method that takes an attacker-supplied path and resolves it server-side under a privileged identity. MS-EFSR (the Encrypting File System remote protocol) gave EfsPotato and SharpEfsPotato -- the canonical fork is &lt;code&gt;bugch3ck/SharpEfsPotato&lt;/code&gt; [@bugch3ck-sharpefspotato-repo], not the &lt;code&gt;ly4k&lt;/code&gt; mirror. MS-FSRVP, MS-DFSNM, and a long tail followed. CoercedPotato&apos;s &lt;code&gt;--interface {ms-rprn, ms-efsr}&lt;/code&gt; switch operationalises the enumeration in a single tool [@prepouce-coercedpotato-repo]; the project&apos;s MS-EFSR catalogue alone lists fourteen entry points (indices 0-13, with two marked NOT WORKING).&lt;/p&gt;
&lt;p&gt;The pattern is clear at this point: the privilege is the constant; the coercion primitive is interchangeable. Microsoft has shipped per-CVE patches for individual coercion APIs (the &lt;a href=&quot;https://paragmali.com/blog/three-years-of-printnightmare-how-the-oldest-windows-service/&quot; rel=&quot;noopener&quot;&gt;PrintNightmare cluster&lt;/a&gt; around MS-RPRN, anchored by CVE-2021-34527 [@nvd-cve-2021-34527]; targeted MS-EFSR fixes), but no commitment to enumerate or class-close the surface.&lt;/p&gt;
&lt;h3&gt;4.5 Generation 5, into RPCSS itself (2022-2024)&lt;/h3&gt;
&lt;p&gt;In December 2022, the researcher who goes by BeichenDream published GodPotato, with a README that names the structural defect plainly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Based on the history of Potato privilege escalation for 6 years, from the beginning of RottenPotato to the end of JuicyPotatoNG, I discovered a new technology by researching DCOM, which enables privilege escalation in Windows 2012 - Windows 2022, now as long as you have &lt;code&gt;ImpersonatePrivilege&lt;/code&gt; permission. Then you are &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt; . . . There are some defects in rpcss when dealing with oxid, and rpcss is a service that must be opened by the system.&quot; [@beichendream-godpotato-readme]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;GodPotato survives every phase of CVE-2021-26414 (the three-phase DCOM hardening, rolled out 2021-06-08, 2022-06-14, 2023-03-14) [@nvd-cve-2021-26414] because the defect is in RPCSS&apos;s OXID &lt;em&gt;handling&lt;/em&gt;, not in DCOM &lt;em&gt;activation&lt;/em&gt;. The other structural half of the defect is documented by Forshaw in April 2020: &quot;When LSASS creates a Token for a new Logon session it stores that Token for later retrieval . . . in this case it does matter as it means that the negotiated Token on the server, which is the same machine, will actually be the session&apos;s Token, not the caller&apos;s Token&quot; [@forshaw-2020-04-sharing-logon-session]. Together those two structural properties keep GodPotato functional across the README&apos;s tested matrix -- Server 2012 through Server 2022, Windows 8 through Windows 11 -- and no public Microsoft patch has been issued for the underlying defect through mid-2026 [@beichendream-godpotato-readme].&lt;/p&gt;
&lt;p&gt;LocalPotato (February 2023) is the parallel branch: Antonio Cocomazzi and Andrea Pierini discovered that the NTLM Type-2 &quot;Reserved&quot; field could be used to swap context handles during local authentication, escalating from an &lt;em&gt;unprivileged&lt;/em&gt; user -- the first variant in the lineage that does not require &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; to start [@cocomazzi-pierini-2023-localpotato-post]. Microsoft fixed it as CVE-2023-21746 [@nvd-cve-2023-21746], but the conceptual proof remains: the local NTLM stack itself is an attacker-controllable token source.&lt;/p&gt;
&lt;p&gt;SilverPotato (April 24, 2024) extended the family across hosts [@pierini-2024-silverpotato-post]. Members of the Distributed COM Users or Performance Log Users groups trigger remote activation of the &lt;code&gt;sppui&lt;/code&gt; DCOM application (CLSID &lt;code&gt;{F87B28F1-DA9A-4F35-8EC0-800EFCF26B83}&lt;/code&gt;) on a target server. The coerced Domain Admin authentication is then chained through SMB relay to the &lt;a href=&quot;https://paragmali.com/blog/certified-pre-owned-ad-cs-and-active-directorys-second-trust/&quot; rel=&quot;noopener&quot;&gt;ADCS host&lt;/a&gt;, SAM dump, &lt;a href=&quot;https://paragmali.com/blog/pass-the-hash-to-pass-the-prt-twenty-nine-years-of-windows-c/&quot; rel=&quot;noopener&quot;&gt;Pass-the-Hash&lt;/a&gt;, CA private key extraction, and ForgeCert to mint a Domain Admin certificate. Microsoft fixed SilverPotato as CVE-2024-38061 in the July 2024 Patch Tuesday [@nvd-cve-2024-38061]; the original researcher&apos;s credit was subsequently removed after a second-reporter overlap and an MSRC severity re-grading from &lt;em&gt;moderate&lt;/em&gt; to &lt;em&gt;important&lt;/em&gt; [@pierini-2024-silverpotato-post]. The structural primitive the chain exploits -- DCOM cross-session activation gated on Distributed COM Users / Performance Log Users group membership chained into a cross-host NTLM relay -- remains a per-CVE rather than a class-level close.&lt;/p&gt;
&lt;p&gt;FakePotato (CVE-2024-38100, July 2024 KB5040434) closed the ShellWindows DCOM activation path that Pierini disclosed; the patch shipped about a month &lt;em&gt;before&lt;/em&gt; the public disclosure [@nvd-cve-2024-38100; @pierini-2024-fakepotato-post].&lt;/p&gt;

James Forshaw&apos;s writing is, by some margin, the single most-cited body on the impersonation primitive in the offensive-research community. Four single-author primaries underpin most of this article: *The Art of Becoming TrustedInstaller* (2017-08) on Service-SID derivation [@forshaw-2017-08-trustedinstaller]; *Empirically Assessing Windows Service Hardening* (2020-01), the canonical empirical assessment of what the WSH stack actually closes and what it does not [@forshaw-2020-01-empirical-wsh]; *Sharing a Logon Session a Little Too Much* (2020-04), which documents the LSASS cached-token defect that GodPotato later weaponised [@forshaw-2020-04-sharing-logon-session]; and *Windows Exploitation Tricks: Relaying DCOM Authentication* (2021-10), the Project Zero retrospective that names the genealogy from Issue 325 to RemotePotato [@forshaw-2021-10-relaying-dcom-pz]. Forshaw&apos;s 2020-01 opening sentence is the line every defender quotes back: &quot;In the past few years there&apos;s been numerous exploits for service to system privilege escalation. Primarily they revolve around the fact that system services typically have impersonation privilege&quot; [@forshaw-2020-01-empirical-wsh].

flowchart TD
    G1[&quot;G1, 2008-2010, Cerrudo Token Kidnapping, leaked impersonation handles&quot;]
    G2[&quot;G2, 2014-2016, HotPotato, local NTLM WPAD reflection&quot;]
    G3[&quot;G3, 2016-2018, RottenPotato, JuicyPotato, DCOM OXID activation&quot;]
    G4[&quot;G4, 2020-2024, PrintSpoofer, CoercedPotato, non-DCOM RPC coercion&quot;]
    G5[&quot;G5, 2022-2024, GodPotato, LocalPotato, SilverPotato, RPCSS OXID and NTLM-loopback defects&quot;]
    Constant[&quot;SeImpersonatePrivilege plus ImpersonateNamedPipeClient, unchanged 2003 through 2026&quot;]
    G1 -- &quot;MS09-012, Cerrudo Chimichurri PoC&quot; --&amp;gt; G2
    G2 -- &quot;MS16-075 plus WPAD hardening&quot; --&amp;gt; G3
    G3 -- &quot;Win10 1809 OXID hardening, then CVE-2021-26414 three phases&quot; --&amp;gt; G4
    G4 -- &quot;Per-CVE coercion-API patches, PrintNightmare cluster&quot; --&amp;gt; G5
    G5 -- &quot;GodPotato unpatched, SilverPotato patched CVE-2024-38061, LocalPotato patched CVE-2023-21746, FakePotato patched CVE-2024-38100&quot; --&amp;gt; Open[&quot;Mid-2026 state, still functional via GodPotato and the coercion-API long tail&quot;]
    G1 --- Constant
    G2 --- Constant
    G3 --- Constant
    G4 --- Constant
    G5 --- Constant
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Generation&lt;/th&gt;
&lt;th&gt;Years&lt;/th&gt;
&lt;th&gt;Token source&lt;/th&gt;
&lt;th&gt;Microsoft response&lt;/th&gt;
&lt;th&gt;Still works in 2026?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;G1 Direct Token Theft (Cerrudo)&lt;/td&gt;
&lt;td&gt;2008-2010&lt;/td&gt;
&lt;td&gt;Leaked impersonation handles&lt;/td&gt;
&lt;td&gt;MS09-012 (Cerrudo &lt;em&gt;Chimichurri&lt;/em&gt; PoC)&lt;/td&gt;
&lt;td&gt;No (handle leaks closed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G2 Local NTLM Reflection (HotPotato)&lt;/td&gt;
&lt;td&gt;2014-2016&lt;/td&gt;
&lt;td&gt;WPAD + HTTP-to-SMB reflection&lt;/td&gt;
&lt;td&gt;MS16-075 + WPAD hardening&lt;/td&gt;
&lt;td&gt;No (chain too fragile)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G3 DCOM Activation (Rotten/Juicy)&lt;/td&gt;
&lt;td&gt;2016-2018&lt;/td&gt;
&lt;td&gt;Coerced DCOM auth to attacker pipe&lt;/td&gt;
&lt;td&gt;Win10 1809 OXID + CVE-2021-26414&lt;/td&gt;
&lt;td&gt;Partial (some LTSC pins)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G4 Non-DCOM RPC Coercion (PrintSpoofer/Coerced)&lt;/td&gt;
&lt;td&gt;2020-2024&lt;/td&gt;
&lt;td&gt;MS-RPRN / MS-EFSR / MS-FSRVP coercion&lt;/td&gt;
&lt;td&gt;Per-CVE patches&lt;/td&gt;
&lt;td&gt;Yes (long tail)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G5 RPCSS OXID + NTLM-Loopback (GodPotato/Local/Silver)&lt;/td&gt;
&lt;td&gt;2022-2024&lt;/td&gt;
&lt;td&gt;RPCSS handling defect + cross-host NTLM relay&lt;/td&gt;
&lt;td&gt;None for GodPotato; CVE-2023-21746 for LocalPotato; CVE-2024-38061 for SilverPotato (July 2024)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt; (GodPotato unaddressed)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

Microsoft&apos;s umbrella term for the post-2003 stack of mitigations around the service-account population: Service SIDs, restricted tokens, write-restricted tokens, integrity levels for services, the SCM&apos;s per-service required-privileges list, and the LPAC variants for select Windows components. The hardening is real, but as section 7 establishes, Microsoft has elected not to treat WSH as a *security* boundary.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Eighteen years. Five generations. One privilege. The variable is the token source; the constant is the gate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each generation tells a story of an MSRC bulletin that closed a specific token source and a researcher who found a new one within months. But every generation also leaves the same three components in place: the privilege, the named-pipe coercion API, and Microsoft&apos;s choice not to close the family at its root. What if those three components, taken together, form a closed system?&lt;/p&gt;
&lt;h2&gt;5. The Three-Piece Theorem&lt;/h2&gt;
&lt;p&gt;The Potato lineage is not a collection of bugs. It is the consequence of a single architectural identity:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; + &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; + the MSRC servicing-criteria carve-out = service-account-to-SYSTEM.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each summand is individually documented. Each is individually shipped by Microsoft. Each is individually justified by a real engineering or product requirement. &lt;em&gt;Together they form a closed system that no point fix can break, because removing any one of them breaks a documented Windows behaviour shipped applications depend on.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the article&apos;s main contribution: re-frame the eighteen-year named-exploit lineage as the consequence of a documented three-piece architectural decision rather than as a series of bugs.&lt;/p&gt;
&lt;h3&gt;Component 1: the privilege&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is enumerated in the privilege-constants table as &lt;code&gt;SE_IMPERSONATE_NAME&lt;/code&gt; [@ms-learn-privilege-constants] and is the subject of a dedicated security-policy page that lists default assignments [@ms-learn-impersonate-policy]. The LOCAL SERVICE and NETWORK SERVICE account documentation each enumerate it as &lt;code&gt;(enabled)&lt;/code&gt; in the default privilege set [@ms-learn-localservice; @ms-learn-networkservice].&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost of removal:&lt;/em&gt; every shipping RPC server that impersonates clients breaks; §7.1 walks through the production-Windows surface this affects in detail.&lt;/p&gt;
&lt;h3&gt;Component 2: the coercion API&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; has shipped since Windows XP / Server 2003 [@ms-learn-impersonatenamedpipeclient]. It is the standard mechanism by which a Win32 RPC server picks up the identity of a connecting client to make per-user access checks. Deprecating it is not a question of swapping one API for another -- the Microsoft-recommended impersonation APIs (&lt;code&gt;RpcImpersonateClient&lt;/code&gt;, the LSA-side variants) ultimately compose into the same kernel-side token-substitution call.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost of removal:&lt;/em&gt; the named-pipe RPC server population that pre-dates the modern impersonation APIs breaks; §7.3 details the SMB-redirector, Print-Spooler, EFS-RPC, and broader Win32 ABI migration cost.&lt;/p&gt;
&lt;h3&gt;Component 3: the carve-out&lt;/h3&gt;

Microsoft&apos;s public policy document defining what counts as a security boundary, a security feature, and a defence-in-depth feature for servicing purposes. The two-question test is direct: &quot;Does the vulnerability violate the goal or intent of a security boundary or a security feature? Does the severity of the vulnerability meet the bar for servicing?&quot; If either answer is no, &quot;the vulnerability will be considered for the next version or release of Windows but will not be addressed through a security update or guidance&quot; [@msrc-windows-security-servicing-criteria].
&lt;p&gt;The &lt;a href=&quot;https://paragmali.com/blog/windows-security-boundaries-the-document-that-decides-what-g/&quot; rel=&quot;noopener&quot;&gt;MSRC Windows Security Servicing Criteria&lt;/a&gt; document [@msrc-windows-security-servicing-criteria] is the policy-level anchor. The operational articulation came at Troopers 24 from Pierini and Cocomazzi, who named the doctrine in three sentences anchored on the WSH-as-safety-not-security distinction [@pierini-cocomazzi-troopers24-talk]. §7 opens with the full quote and walks through its implications; for the three-piece theorem here, what matters is that the carve-out is &lt;em&gt;documented&lt;/em&gt; and &lt;em&gt;Microsoft-position-as-stated&lt;/em&gt;, not inferred from per-CVE behaviour.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost of removal:&lt;/em&gt; Microsoft commits to the per-CVE cadence becoming a structural-close cadence -- servicing every coercion API in the long tail, every NTLM-loopback edge case, every cross-session token confusion, on the same SLAs as kernel RCEs. The MSRC has explicitly declined to take on that workload [@msrc-windows-security-servicing-criteria].&lt;/p&gt;

&quot;if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM&quot; -- Andrea Pierini; &quot;a deliberately provocative shortcut obviously, but it&apos;s not far from the truth&quot; -- Clement Labro&apos;s gloss on the same line [@labro-2020-printspoofer-post]

flowchart TB
    Priv[&quot;SeImpersonatePrivilege, default-assigned to LOCAL SERVICE and NETWORK SERVICE.  Removing this breaks every service that impersonates clients.&quot;]
    API[&quot;ImpersonateNamedPipeClient, shipped since XP/Server 2003.  Removing this breaks every named-pipe RPC server.&quot;]
    Doctrine[&quot;MSRC servicing criteria: WSH is a safety boundary, not a security boundary.  Changing this commits Microsoft to a structural-close servicing cadence.&quot;]
    Center[&quot;Service-account to SYSTEM&quot;]
    Priv --&amp;gt; Center
    API --&amp;gt; Center
    Doctrine --&amp;gt; Center
&lt;p&gt;The original focus paragraph that seeded this article mentioned &quot;RBAC for services&quot; as one of Microsoft&apos;s mitigations. The Stage 0a focus-premise audit found this phrase to be non-standard Windows terminology and explicitly retracted it; Microsoft has never shipped a Windows-side RBAC architecture for services. Azure RBAC and Microsoft Entra RBAC are cloud-side authorisation systems and do not gate the local &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; at all. Section 6.6 returns to this retraction in full.&lt;/p&gt;
&lt;p&gt;If the primitive is a closed three-piece system, what has Microsoft actually shipped in the eighteen years since Cerrudo? Five containment mitigations -- each of which narrows the surface around the primitive without closing it.&lt;/p&gt;
&lt;h2&gt;6. Five Mitigations and the Surface None of Them Closes&lt;/h2&gt;
&lt;p&gt;Microsoft has not been idle. Over nineteen years of service hardening they have shipped Service SIDs, restricted tokens, the Less-Privileged AppContainer model, group Managed Service Accounts, and the three-phase DCOM hardening of CVE-2021-26414. Each closes a real surface. None of them closes the primitive. The pattern is too consistent to be accidental.&lt;/p&gt;
&lt;h3&gt;6.1 Service SID isolation (Vista, 2007)&lt;/h3&gt;
&lt;p&gt;Vista shipped per-service SIDs of the form &lt;code&gt;NT SERVICE\&amp;lt;name&amp;gt;&lt;/code&gt; -- a SID generated on the fly from the service&apos;s name and attached to the service-process token. Forshaw&apos;s &lt;em&gt;The Art of Becoming TrustedInstaller&lt;/em&gt; is the canonical reference for the derivation: &quot;The SID itself is generated on the fly as the SHA1 hash of the uppercase version of the service name&quot; [@forshaw-2017-08-trustedinstaller]. Service SIDs are also documented as part of the SCM service-security model [@ms-learn-service-security].&lt;/p&gt;

A SID of the form `NT SERVICE\` derived as the SHA1 hash of the uppercased service name. Service SIDs let an ACL grant access to a specific service without granting access to every service running under the same account. When `SERVICE_SID_TYPE_UNRESTRICTED` is configured, the Service SID is added to the service-process token as a regular group SID.
&lt;p&gt;&lt;em&gt;Closes:&lt;/em&gt; lateral movement between services sharing an account. A NETWORK SERVICE process for service A cannot, by Service SID alone, open files ACL&apos;d to NETWORK SERVICE for service B.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does NOT close:&lt;/em&gt; vertical movement to SYSTEM via NETWORK SERVICE. Forshaw&apos;s April 2020 &lt;em&gt;Sharing a Logon Session a Little Too Much&lt;/em&gt; documents the LSASS cached-token defect that underpins GodPotato: even with Service SIDs in place, the local logon session that LSASS retrieves for a same-machine authentication is the &lt;em&gt;session&apos;s&lt;/em&gt; token, not the &lt;em&gt;caller&apos;s&lt;/em&gt; token, which is exactly the structural property GodPotato weaponises [@forshaw-2020-04-sharing-logon-session].&lt;/p&gt;
&lt;h3&gt;6.2 Restricted and write-restricted service tokens (Vista 2007, backport via MS09-012)&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SERVICE_SID_TYPE_RESTRICTED&lt;/code&gt; and &lt;code&gt;WRITE_RESTRICTED&lt;/code&gt; are SCM configuration values that wrap the service-process token in a restricting-SID set; the kernel performs every access check twice (once against the regular group SIDs, once against the restricting set) and grants only the intersection. Forshaw&apos;s January 2020 empirical assessment is the canonical study of what these settings actually accomplish: &quot;In the past few years there&apos;s been numerous exploits for service to system privilege escalation. Primarily they revolve around the fact that system services typically have impersonation privilege&quot; [@forshaw-2020-01-empirical-wsh].&lt;/p&gt;

A token marked with a *restricting SID* set in addition to its regular group SIDs. The kernel grants access only when both sets satisfy the ACL. Configured per-service via `SERVICE_SID_TYPE_RESTRICTED` (or `WRITE_RESTRICTED`, which restricts only write access). The intent is to prevent a compromised service from touching arbitrary objects outside an explicit allow-list of restricting SIDs.
&lt;p&gt;&lt;em&gt;Closes:&lt;/em&gt; the compromised service&apos;s ability to write to (or read, depending on configuration) arbitrary objects outside its restricting-SID set.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does NOT close:&lt;/em&gt; &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is not revoked. A restricted token can still call &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; and &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt;. The privilege gate is orthogonal to the restricting-SID gate.&lt;/p&gt;
&lt;h3&gt;6.3 LPAC (Less-Privileged AppContainer) for select services (Windows 10+)&lt;/h3&gt;
&lt;p&gt;Some Microsoft components opt into the AppContainer model with the Less-Privileged variant: the Edge browser broker, certain Defender child processes, parts of the DNS Client and Web Account Manager stacks. Inside an LPAC, the process runs with a deny-all token capabilities profile and must declare every Win32 capability it intends to use. The sibling &lt;a href=&quot;https://paragmali.com/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/&quot; rel=&quot;noopener&quot;&gt;AppContainer and LowBox Tokens&lt;/a&gt; article (2026-05-12) covers the model in depth.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Closes:&lt;/em&gt; the attack surface of a few specific Microsoft-shipped contained services.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does NOT close:&lt;/em&gt; the LOCAL SERVICE and NETWORK SERVICE population this article is about is &lt;strong&gt;not&lt;/strong&gt; LPAC-contained by default. Declaring an LPAC service requires rewriting the service to operate inside an AppContainer, which most product teams do not undertake.&lt;/p&gt;

Building an LPAC service is not a configuration flag; it is an architectural commitment. The service must declare every Win32 capability it uses, must be packaged through the modern app installer pipeline, and must accept the deny-by-default file-system view that the LPAC sandbox enforces. The cost is real for legacy code -- file paths and registry keys the service has historically reached without scrutiny become inaccessible, and IPC patterns that assumed a normal token need to be re-engineered through capability-mediated brokers. Even Microsoft uses LPAC narrowly. Third-party adoption among independent software vendors that ship NETWORK SERVICE workloads is essentially nil. The mitigation that *would* containerise the impersonation surface is technically available; in practice almost nobody uses it.
&lt;h3&gt;6.4 group Managed Service Accounts (gMSA, Server 2012+)&lt;/h3&gt;
&lt;p&gt;gMSA is Microsoft&apos;s solution to the credential-hygiene problem for service accounts: a domain-managed identity whose 240-byte password is rotated automatically by the KDS Root Key, retrieved by authorised hosts via Group Policy, and never typed by a human [@ms-learn-gmsa-overview].&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Closes:&lt;/em&gt; domain-credential exposure for service accounts. A service no longer has a memorable password an admin will reuse; the credential lives in AD and is rotated on a schedule.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does NOT close:&lt;/em&gt; anything to do with &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; on the local box. gMSA is a credential-hygiene mitigation, not a privilege-escape mitigation. A service running under a gMSA still holds the same default service-account privileges, and the SilverPotato-class cross-host coerce-and-relay flow [@pierini-2024-silverpotato-post; @nvd-cve-2024-38061] directly exploits a chain that gMSA does not protect against (per-variant patches like CVE-2024-38061 close instances, not the class).&lt;/p&gt;
&lt;h3&gt;6.5 CVE-2021-26414 three-phase DCOM hardening&lt;/h3&gt;
&lt;p&gt;CVE-2021-26414 raised the minimum DCOM client authentication level to &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt;. The rollout was deliberately gradual: phase 1 (2021-06-08) opt-in via registry, phase 2 (2022-06-14) opt-out via registry, phase 3 (2023-03-14) enforced with no opt-out [@nvd-cve-2021-26414].&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Closes:&lt;/em&gt; the original RottenPotato and JuicyPotato OBJREF-with-attacker-OXID chain on phase-3-enforced builds. The DCOM activation surface those variants depended on is meaningfully harder after phase 3.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Does NOT close:&lt;/em&gt; anything that does not depend on DCOM activation. &lt;strong&gt;GodPotato&lt;/strong&gt; (RPCSS OXID handling, not DCOM activation) remains functional [@beichendream-godpotato-readme]; &lt;strong&gt;PrintSpoofer / CoercedPotato&lt;/strong&gt; (non-DCOM RPC coercion) remain functional [@labro-2020-printspoofer-post; @prepouce-coercedpotato-repo]; &lt;strong&gt;JuicyPotatoNG&lt;/strong&gt; found a same-quarter bypass on the DCOM side via the PrintNotify CLSID &lt;code&gt;{854A20FB-2D44-457D-992F-EF13785D2B51}&lt;/code&gt; [@antoniococo-juicypotatong-repo]; &lt;strong&gt;SilverPotato&lt;/strong&gt; used a different CLSID and a cross-host relay until Microsoft fixed it as CVE-2024-38061 in July 2024 [@pierini-2024-silverpotato-post; @nvd-cve-2024-38061] -- a per-variant fix that illustrates exactly why CVE-2021-26414 does not address the cross-host coerce-and-relay class as a whole.&lt;/p&gt;
&lt;h3&gt;6.6 The mitigation that does not exist: &quot;RBAC for services&quot;&lt;/h3&gt;
&lt;p&gt;Windows has shipped no unified RBAC architecture for local services. The SCM provides per-service SDDL controls, the file system and registry provide per-resource ACLs everywhere, and Service SIDs let ACLs name a specific service identity -- but &quot;RBAC for services&quot; as a single named mechanism is non-standard Windows terminology. Azure RBAC and Microsoft Entra RBAC are cloud-side authorisation systems and do not gate the local &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; at all. The §5 Sidenote on the Stage 0a focus-premise retraction covers the audit-trail framing; this subsection states the reader-facing point.&lt;/p&gt;

flowchart TB
    M1[&quot;Service SID Isolation, Vista 2007&quot;]
    M2[&quot;Restricted and Write-Restricted Tokens, Vista 2007 plus MS09-012 backport&quot;]
    M3[&quot;LPAC for select services, Windows 10 plus&quot;]
    M4[&quot;gMSA, Server 2012 plus&quot;]
    M5[&quot;CVE-2021-26414 three-phase DCOM hardening, 2021-2023&quot;]
    Surface1[&quot;Closes lateral movement between same-account services&quot;]
    Surface2[&quot;Closes write access outside restricting-SID set&quot;]
    Surface3[&quot;Closes blast radius of select Microsoft-shipped services&quot;]
    Surface4[&quot;Closes domain-credential exposure&quot;]
    Surface5[&quot;Closes DCOM activation chain, Rotten and Juicy&quot;]
    Core[&quot;Service-account-to-SYSTEM, primitive remains open&quot;]
    M1 --&amp;gt; Surface1
    M2 --&amp;gt; Surface2
    M3 --&amp;gt; Surface3
    M4 --&amp;gt; Surface4
    M5 --&amp;gt; Surface5
    Surface1 -. &quot;does not reach&quot; .-&amp;gt; Core
    Surface2 -. &quot;does not reach&quot; .-&amp;gt; Core
    Surface3 -. &quot;does not reach&quot; .-&amp;gt; Core
    Surface4 -. &quot;does not reach&quot; .-&amp;gt; Core
    Surface5 -. &quot;does not reach&quot; .-&amp;gt; Core
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mitigation&lt;/th&gt;
&lt;th&gt;What it closes&lt;/th&gt;
&lt;th&gt;What it does NOT close&lt;/th&gt;
&lt;th&gt;Primary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Service SID Isolation (Vista 2007)&lt;/td&gt;
&lt;td&gt;Lateral movement between services sharing an account&lt;/td&gt;
&lt;td&gt;Vertical SYSTEM via NETWORK SERVICE LSASS-cached-token defect&lt;/td&gt;
&lt;td&gt;[@forshaw-2017-08-trustedinstaller; @forshaw-2020-04-sharing-logon-session]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restricted / Write-Restricted Tokens&lt;/td&gt;
&lt;td&gt;Write access to non-restricting-SID objects&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; still present; &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; still works&lt;/td&gt;
&lt;td&gt;[@forshaw-2020-01-empirical-wsh]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LPAC (Windows 10+)&lt;/td&gt;
&lt;td&gt;Select-services blast radius&lt;/td&gt;
&lt;td&gt;NETWORK / LOCAL SERVICE population not LPAC-contained by default&lt;/td&gt;
&lt;td&gt;sibling AppContainer article&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gMSA (Server 2012+)&lt;/td&gt;
&lt;td&gt;Domain-credential exposure&lt;/td&gt;
&lt;td&gt;Local &lt;code&gt;SeImpersonate&lt;/code&gt;; SilverPotato-class cross-host relay&lt;/td&gt;
&lt;td&gt;[@ms-learn-gmsa-overview]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVE-2021-26414 phase 3 (2023-03-14)&lt;/td&gt;
&lt;td&gt;DCOM activation chain (Rotten/Juicy)&lt;/td&gt;
&lt;td&gt;GodPotato (RPCSS), PrintSpoofer (non-DCOM), JuicyPotatoNG (same-quarter bypass)&lt;/td&gt;
&lt;td&gt;[@nvd-cve-2021-26414]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; None of this section is an indictment of the mitigations. Each one closes a meaningful surface, and a NETWORK SERVICE host with all five active is materially harder to attack than a host without them. But the surface they collectively leave open -- the &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; plus &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; plus coercion-API combination -- is the surface that every shipping Potato variant lives on. The gap is not a missing patch. The gap is the design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft has shipped five mitigations in nineteen years. Every one narrows the surface around the primitive. None of them closes it. The pattern is too consistent to be accidental. So what is the policy that produces this pattern?&lt;/p&gt;
&lt;h2&gt;7. The MSRC Servicing-Criteria Carve-Out&lt;/h2&gt;

Most of these exploits allow an attacker to break the WSH (Windows Service Hardening) boundary, enabling privilege escalation from a limited service to SYSTEM: a common scenario when dealing with web services like IIS or MSSQL. Interestingly, Microsoft does not consider WSH a security boundary but rather a safety boundary; for this reason, many Potato exploits work (and have been working) on fully updated Windows systems. -- Andrea Pierini and Antonio Cocomazzi, Troopers 24 [@pierini-cocomazzi-troopers24-talk]
&lt;p&gt;This is the Microsoft-position-as-stated-to-researchers anchor for the entire article. The MSRC Windows Security Servicing Criteria page [@msrc-windows-security-servicing-criteria] is the policy-document anchor with the same content: the two-question test &quot;Does the vulnerability violate the goal or intent of a security boundary or a security feature? Does the severity of the vulnerability meet the bar for servicing?&quot; If either answer is no, the vulnerability is considered for the next version of Windows but is not addressed through a security update.&lt;/p&gt;
&lt;p&gt;Service-to-SYSTEM escalation across the Windows Service Hardening boundary is not a violation of a &lt;em&gt;security boundary&lt;/em&gt;. It is a violation of a &lt;em&gt;safety boundary&lt;/em&gt;. The distinction is doctrinal and explicit. Microsoft will fix specific token-source primitives -- LocalPotato got CVE-2023-21746, FakePotato got CVE-2024-38100 -- but the class is, on the record, not within scope for security servicing [@nvd-cve-2023-21746; @nvd-cve-2024-38100].&lt;/p&gt;
&lt;p&gt;Why? Walk through each of the three closure paths Microsoft could in principle take, and the cost of each.&lt;/p&gt;
&lt;h3&gt;7.1 Revoke &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; from NETWORK SERVICE and LOCAL SERVICE&lt;/h3&gt;
&lt;p&gt;The cleanest fix in the model: drop the privilege from the default-assignment list documented on the LOCAL SERVICE and NETWORK SERVICE account pages [@ms-learn-localservice; @ms-learn-networkservice]. Every Potato variant that ends in &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt; fails immediately.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost.&lt;/em&gt; Every RPC server, web server, database server, and Office service that needs to act on a client&apos;s behalf breaks. The privilege exists &lt;em&gt;because&lt;/em&gt; services need it. IIS application pools cannot impersonate authenticated users; SQL Server cannot enforce per-login row security; Exchange cannot operate on mailboxes under the connected user&apos;s identity; the print spooler cannot enforce per-user printer ACLs; the file server cannot enforce per-user file ACLs. The 2003 service-hardening pivot would be reversed -- services would have to run as SYSTEM again to do the work they need to do, which is precisely the worm-target population Microsoft spent the early 2000s migrating away from.&lt;/p&gt;
&lt;h3&gt;7.2 Declare local DCOM activation a security boundary and service it&lt;/h3&gt;
&lt;p&gt;This was the partial path Microsoft did take with CVE-2021-26414 [@nvd-cve-2021-26414]: tighten the DCOM activation surface and ship the change in three phases over twenty-one months. But declaring &lt;em&gt;all&lt;/em&gt; local DCOM activation a security boundary requires a serviceable-CVE pipeline for every cross-session COM activation, every cross-integrity-level activation, every weakly-authenticated marshalled OBJREF.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost.&lt;/em&gt; MSRC has declined to take on that workload. The on-the-record case is RemotePotato0 [@antoniococo-remotepotato0-repo], which was classified &quot;Won&apos;t Fix&quot; by MSRC as the first explicit declination in the lineage -- documented in Forshaw&apos;s 2021 retrospective as still unpatched at the time of writing [@forshaw-2021-10-relaying-dcom-pz]. RemotePotato0 is the empirical evidence that Microsoft has chosen to live with a known cross-session DCOM relay rather than commit to a structural close.&lt;/p&gt;
&lt;h3&gt;7.3 Deprecate &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Remove the named-pipe-server impersonation API from the Win32 surface. Mark it deprecated. Stop callers from using it. Provide a replacement that requires explicit per-request token plumbing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cost.&lt;/em&gt; Most Win32 RPC servers stop being able to impersonate their callers. The SMB redirector, the Print Spooler, the EFS RPC server, and a long tail of named-pipe RPC servers depend on this specific API; their alternatives all compose into the same kernel-side call. The replacement -- a per-request capability handle threading through every RPC binding -- would be a multi-year ABI change with no clean migration path for legacy binaries.&lt;/p&gt;

flowchart LR
    Start[&quot;Closure path&quot;]
    A[&quot;A. Revoke SeImpersonatePrivilege from NETWORK SERVICE and LOCAL SERVICE&quot;]
    B[&quot;B. Declare local DCOM activation a security boundary, service every CVE&quot;]
    C[&quot;C. Deprecate ImpersonateNamedPipeClient&quot;]
    Cost1[&quot;Breaks IIS, Exchange, MSSQL, Office services&quot;]
    Cost2[&quot;Per-CVE servicing pipeline for every cross-session COM activation, MSRC has declined&quot;]
    Cost3[&quot;Breaks SMB redirector, Print Spooler, EFS, every named-pipe RPC server that impersonates&quot;]
    Converge[&quot;Compatibility cost Microsoft has not accepted&quot;]
    Start --&amp;gt; A
    Start --&amp;gt; B
    Start --&amp;gt; C
    A --&amp;gt; Cost1 --&amp;gt; Converge
    B --&amp;gt; Cost2 --&amp;gt; Converge
    C --&amp;gt; Cost3 --&amp;gt; Converge
&lt;p&gt;RemotePotato0 [@antoniococo-remotepotato0-repo] holds a particular place in the lineage because it is the first variant for which MSRC&apos;s &quot;Won&apos;t Fix&quot; classification became public on the record. Forshaw&apos;s 2021 Project Zero retrospective notes the variant as &quot;currently unpatched as of October 2021&quot; [@forshaw-2021-10-relaying-dcom-pz], and Microsoft did not subsequently issue a CVE for it. The Stage 5 outline cross-references the sibling Potato Family article (2026-05-31) for variant detail; in this article RemotePotato0 functions as the empirical proof that the carve-out is not a hypothetical preference but a shipped policy choice.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Eighteen years. Five mitigations. Three closure paths Microsoft has explicitly declined to take. The primitive is not unpatched. It is documented-as-policy not to be patched.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft has chosen, on the record, to treat this boundary as a safety boundary rather than a security boundary. Is that an architectural failure -- or is it a rational policy choice under a deeper structural constraint? Hardy 1988 has an answer.&lt;/p&gt;
&lt;h2&gt;8. The Hardy Ceiling&lt;/h2&gt;
&lt;p&gt;Norm Hardy named the class in 1988. Forty years later, Windows is still demonstrating it. The confused-deputy attack surface is not a Microsoft mistake; it is the predictable behaviour of any identity-and-ACL system in which a server holds more authority than its clients and acts on client requests [@hardy-1988].&lt;/p&gt;
&lt;p&gt;The argument generalises beyond Windows. Any system that lets a process inherit ambient authority from its identity, and then lets that process act on requests from less-authorised principals, has a confused-deputy surface by construction. The only complete defence is capability discipline: bind authority to operations rather than to running identities, and never let a process exercise authority it was not explicitly handed [@hardy-1988]. Lampson&apos;s 1971 access-matrix paper is the formal substrate the argument depends on [@lampson-1971].&lt;/p&gt;
&lt;p&gt;Windows is not a capability system. It is an identity-and-ACL system, as Cutler&apos;s NT 3.1 team chose in 1993 [@ms-learn-windows-internals]. As long as that remains true, &lt;em&gt;some&lt;/em&gt; version of &quot;service-account to higher-privileged identity&quot; is reachable, and the only question is which specific token-source primitive is currently in play. Microsoft&apos;s eighteen-year per-CVE response cadence is consistent with that ceiling. Each individual token source is fixable; the class is not.&lt;/p&gt;

The capability-systems lineage -- KeyKOS, EROS, Coyotos, seL4 -- spent four decades demonstrating that the confused-deputy class is closeable in principle. In a capability system, when Hardy&apos;s user passed the FORTRAN compiler the path to the billing file as a debug-output target, the OS would have handed the compiler a write capability only for the file the *user* could write -- not for `(SYSX)BILL`. The compiler could not have damaged the bill even if it tried. seL4 has a machine-checked proof of this property. But none of those systems is the Windows service-compatibility envelope, and porting Windows to a capability substrate is not on any public roadmap. The road exists; Microsoft has not taken it.
&lt;p&gt;The closest in-architecture approximations Windows has shipped are narrow: AppContainer and LowBox tokens (the sibling AppContainer article 2026-05-12) bind a subset of authority to declared capabilities for select Microsoft components; the &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Adminless / Administrator Protection feature&lt;/a&gt; (sibling Adminless article 2026-05-10) binds elevation authority to per-action prompts for interactive admins. Both are partial applications of the capability principle within an otherwise identity-and-ACL system. Neither extends to the service-account population this article is about.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Windows is an identity-and-ACL system. As long as it remains one, the confused-deputy class is structurally present, and the Potato lineage is its Windows-specific instantiation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the ceiling is structural and Microsoft has chosen the doctrine to match, what is the offensive-research community working on next? And what should defenders be doing in the meantime?&lt;/p&gt;
&lt;h2&gt;9. Open Problems&lt;/h2&gt;
&lt;p&gt;The closure of LocalPotato in 2023, SilverPotato (CVE-2024-38061) in July 2024, and FakePotato (CVE-2024-38100) in July 2024 did not slow the lineage. GodPotato remains functional. The supply of coercion APIs is structurally large. Microsoft has shipped no policy change. The four open questions below define what the lineage looks like through the rest of the decade.&lt;/p&gt;
&lt;h3&gt;9.1 The coercion-API treadmill&lt;/h3&gt;
&lt;p&gt;Generation 4 demonstrated that any Windows RPC interface accepting an attacker-supplied path or endpoint and resolving it server-side under a privileged identity is a viable token source. CoercedPotato&apos;s MS-EFSR catalogue alone lists fourteen entry points (two marked NOT WORKING) [@prepouce-coercedpotato-repo], with additional protocols (MS-RPRN, MS-FSRVP, MS-DFSNM) in the same family. Microsoft patches per CVE -- PrintNightmare cluster around MS-RPRN, targeted MS-EFSR fixes -- but the supply is not exhausted, and there is no public Microsoft commitment to exhaustive enumeration or class-level closure.&lt;/p&gt;
&lt;h3&gt;9.2 GodPotato&apos;s RPCSS OXID path&lt;/h3&gt;
&lt;p&gt;Three years after the three-phase CVE-2021-26414 DCOM hardening completed [@nvd-cve-2021-26414], GodPotato remains functional across the README&apos;s tested Windows matrix (Server 2012-2022 / Windows 8-11) [@beichendream-godpotato-readme]. No public Microsoft patch has been issued for the underlying defect through mid-2026. The architectural question -- is RPCSS itself the right place to harden, or is the LSASS cached-token defect Forshaw documented in April 2020 [@forshaw-2020-04-sharing-logon-session] the right place -- remains open. Microsoft has assigned no CVE.&lt;/p&gt;
&lt;h3&gt;9.3 Credential Guard does not stop this&lt;/h3&gt;
&lt;p&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; protects the &lt;em&gt;NTLM hash and Kerberos TGT&lt;/em&gt; in the LSASS Isolated User Mode trustlet. It does &lt;strong&gt;not&lt;/strong&gt; protect against runtime impersonation of an already-issued token. The boundary between credential-theft mitigations and impersonation mitigations is frequently confused.&lt;/p&gt;
&lt;p&gt;Credential Guard&apos;s actual scope is narrower than its name suggests. The mitigation moves long-term authenticators -- the NT hash, the Kerberos TGT, and certain ticket-granting material -- into an isolated user-mode trustlet whose memory the regular kernel cannot read. None of that touches the runtime token plumbing the Potato lineage exercises. The token you receive from &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; is not a credential and is not held in LSASS-isolated memory; Credential Guard cannot see it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Practitioners frequently treat Credential Guard and Virtualisation-Based Security as a generic answer to &quot;Windows privilege-escalation risk.&quot; For the Potato family they are not. A Credential-Guard-enabled host that runs IIS as NETWORK SERVICE is as vulnerable to PrintSpoofer / CoercedPotato / GodPotato as a host without VBS. The category error matters operationally: a security team that buys Credential Guard expecting it to mitigate this primitive is misallocating defensive budget.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;9.4 The &quot;service boundary&quot; re-definition Microsoft has quietly avoided&lt;/h3&gt;
&lt;p&gt;Adminless / Administrator Protection -- the 2024-2025 feature that re-frames local admin identity as a per-action consent surface [@ms-learn-admin-protection] (covered in the sibling Adminless article 2026-05-10) -- explicitly excludes services from its new boundary.&lt;/p&gt;
&lt;p&gt;The Adminless documentation scopes the feature to interactive administrator accounts on a device [@ms-learn-admin-protection]; services, MSAs, gMSAs, and virtual accounts are out of scope by construction because none of them is an interactive admin account. The new boundary applies to elevation-prompt consent for interactive admins, not to service-account workloads. The open question is whether Microsoft will ever extend the Adminless boundary to include service accounts. As of mid-2026, the answer is &lt;em&gt;not on the public roadmap&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;9.5 Generation-6 candidates&lt;/h3&gt;
&lt;p&gt;Three candidate paths for the next generation of the lineage, none with a pushbutton PoC on the scale of HotPotato / JuicyPotato / PrintSpoofer / GodPotato as of mid-2026:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Kerberos-only loopback coercion.&lt;/em&gt; The existing NTLM-reflection mitigations target NTLM specifically; a coercion primitive that lands as a Kerberos AP-REQ to the same loopback endpoint would sidestep them.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Virtual-account / gMSA token-state defects.&lt;/em&gt; Forshaw&apos;s April 2020 analysis [@forshaw-2020-04-sharing-logon-session] established that the LSASS cached-token logic has surprising behaviours under same-machine authentication; the gMSA-account variant of those edge cases has not been publicly explored.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Cross-host extensions beyond ADCS.&lt;/em&gt; SilverPotato&apos;s coerce-and-relay chain into ADCS infrastructure [@pierini-2024-silverpotato-post] -- patched as CVE-2024-38061 in July 2024 [@nvd-cve-2024-38061] but exemplifying an open class -- is the strongest current exemplar for the &quot;Generation 6&quot; archetype: cross-host coerce-and-relay attacks that combine the existing local impersonation primitive with off-box authentication targets. LDAP, WinRM, and MSSQL-with-cert-auth are obvious next targets for the same class; what matters for taxonomy is the cross-host shape, not the patched-or-unpatched status of any specific variant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the lineage is not closing, what should a defender actually do today?&lt;/p&gt;
&lt;h2&gt;10. Defending, Detecting, and (Carefully) Removing the Privilege&lt;/h2&gt;
&lt;p&gt;Three operational questions: which accounts hold the privilege on your box, can you remove it, and how do you detect when someone is actually using it?&lt;/p&gt;
&lt;h3&gt;10.1 Auditing which accounts hold &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The first defensive action is enumeration -- not removal. Concrete commands, in increasing order of detail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;whoami /priv&lt;/code&gt; -- per-process self-check from any shell. Reports the token&apos;s privileges in the form the article opens with.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;secedit /export /cfg secpol.cfg&lt;/code&gt; -- full local-policy export. Grep the output for &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; to see every SID the local policy grants it to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;accesschk.exe -a SeImpersonatePrivilege&lt;/code&gt; -- the Sysinternals AccessChk tool [@ms-learn-accesschk] enumerates the effective holders directly from the LSA policy database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Get-NtTokenPrivileges&lt;/code&gt; from James Forshaw&apos;s NtObjectManager PowerShell module [@forshaw-ntobjectmanager-repo] -- the same data, scriptable, with the broader NtObjectManager surface available for follow-up (named-pipe enumeration, token-handle leak search, kernel-object introspection).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Invoke-PrivescCheck&lt;/code&gt; from Clement Labro&apos;s PrivescCheck module [@labro-privesccheck-repo] -- the canonical local-privesc check-list. The output includes &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; presence as one of approximately forty enumerated checks.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Author&lt;/th&gt;
&lt;th&gt;What it reports&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;AccessChk (Sysinternals)&lt;/td&gt;
&lt;td&gt;Mark Russinovich&lt;/td&gt;
&lt;td&gt;Effective permissions, account-privilege enumeration via &lt;code&gt;-a&lt;/code&gt; [@ms-learn-accesschk]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NtObjectManager&lt;/td&gt;
&lt;td&gt;James Forshaw&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Get-NtTokenPrivileges&lt;/code&gt;, named-pipe enumeration, token-handle leak search [@forshaw-ntobjectmanager-repo]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PrivescCheck&lt;/td&gt;
&lt;td&gt;Clement Labro&lt;/td&gt;
&lt;td&gt;Canonical local-privesc check-list incl. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; presence [@labro-privesccheck-repo]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;{`
// Logic of: secedit /export /cfg secpol.cfg ; grep SeImpersonate
const secpol = readPolicyExport();              // produced by secedit
const holders = secpol[&apos;SeImpersonatePrivilege&apos;] || [];&lt;/p&gt;
&lt;p&gt;console.log(&apos;SIDs holding SeImpersonatePrivilege:&apos;);
for (const sid of holders) {
  console.log(&apos;  &apos; + sid);
}&lt;/p&gt;
&lt;p&gt;// Typical default on a server-style install:
//   S-1-5-19   (NT AUTHORITY\LOCAL SERVICE)
//   S-1-5-20   (NT AUTHORITY\NETWORK SERVICE)
//   S-1-5-32-544 (BUILTIN\Administrators)
//   S-1-5-6    (NT AUTHORITY\SERVICE)
`}&lt;/p&gt;
&lt;h3&gt;10.2 Removing the privilege where you can&lt;/h3&gt;
&lt;p&gt;The policy path is documented: &lt;code&gt;Computer Configuration -&amp;gt; Windows Settings -&amp;gt; Security Settings -&amp;gt; Local Policies -&amp;gt; User Rights Assignment -&amp;gt; Impersonate a client after authentication&lt;/code&gt; [@ms-learn-impersonate-policy]. The temptation, especially after reading an article like this one, is to remove &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; from NETWORK SERVICE wholesale.&lt;/p&gt;
&lt;p&gt;Do not do that. It will break IIS, Exchange, SQL Server, and most other Windows server products -- the same set the 2003 service-hardening pivot was designed to support. The realistic defensive approach is narrower: &lt;em&gt;audit first&lt;/em&gt;, &lt;em&gt;understand the dependency surface&lt;/em&gt;, then &lt;em&gt;narrow the assignment to the specific service accounts that need it&lt;/em&gt; on the specific hosts where they run. On hosts that do not run an RPC-impersonating workload (jump boxes, build agents, certain hardened-management hosts), the privilege can sometimes be removed safely from the unused well-known accounts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The single most common mistake after reading any Potato writeup is to remove the privilege from NETWORK SERVICE on a production host. Doing so breaks IIS (per-user authentication fails), Exchange (mailbox impersonation fails), SQL Server (per-login row security fails), the SMB redirector (file-server impersonation fails), the Print Spooler (per-user printer ACLs fail), and most third-party Win32 service products. The privilege exists because services need it. Audit before you remove. Remove only after you have positively identified which production services on this host depend on the privilege and confirmed none of them does.&lt;/p&gt;
&lt;/blockquote&gt;

*Hidden behind a spoiler intentionally, so a skimming reader does not accidentally remove the privilege from production NETWORK SERVICE.* Open `gpedit.msc` (or the Group Policy Management Console for a domain-joined host). Navigate Computer Configuration -&amp;gt; Windows Settings -&amp;gt; Security Settings -&amp;gt; Local Policies -&amp;gt; User Rights Assignment -&amp;gt; Impersonate a client after authentication. The right-hand pane lists the SIDs holding the privilege. Note the current list. Do not change it. Compare it against the audit output from Section 10.1. If the local list and the AccessChk output disagree, you have a domain-pushed policy override worth tracing. If they agree and you have a documented business reason to remove a specific account, change the policy for that specific account only, and confirm on a non-production host that the dependent services still function.
&lt;h3&gt;10.3 Detection signatures&lt;/h3&gt;
&lt;p&gt;Detection in this space breaks into two abstractions: &lt;em&gt;primitive-level&lt;/em&gt; rules that match the named-pipe pattern every Potato variant generates, and &lt;em&gt;named-tool&lt;/em&gt; rules that match a specific binary&apos;s fingerprint.&lt;/p&gt;
&lt;p&gt;The primitive-level open-source reference is the Elastic detection rule &lt;code&gt;Privilege Escalation via Rogue Named Pipe&lt;/code&gt; [@elastic-rogue-named-pipe-rule] (as of June 2026; the cited URL pins to the master HEAD), rule_id &lt;code&gt;76ddb638-abf7-42d5-be22-4a70b0bf7241&lt;/code&gt;. The EQL queries Sysmon Event ID 17 (pipe-creation events) and matches paths in which a &lt;code&gt;\pipe\&lt;/code&gt; token appears after another path segment -- the canonical PrintSpoofer-style relay endpoint fingerprint. Because the rule looks for the pattern every Potato variant produces (a service-account process creating a named pipe whose path embeds a coercion-API hint), it survives binary rename, source-recompile, and most CLI variation.&lt;/p&gt;
&lt;p&gt;The named-tool reference is the SigmaHQ LocalPotato rule [@sigmahq-localpotato-rule] (as of June 2026; the cited URL pins to the master HEAD), rule &lt;code&gt;id 6bd75993-9888-4f91-9404-e1e4e4e34b77&lt;/code&gt;. Three OR-joined selectors: image path ending in &lt;code&gt;\LocalPotato.exe&lt;/code&gt;; CLI fingerprint &lt;code&gt;-i C:\&lt;/code&gt; paired with &lt;code&gt;-o Windows\&lt;/code&gt;; specific IMPHASH selectors &lt;code&gt;E1742EE971D6549E8D4D81115F88F1FC&lt;/code&gt; and &lt;code&gt;DD82066EFBA94D7556EF582F247C8BB5&lt;/code&gt;. Useful as a low-noise IOC tripwire; trivially evaded by binary rename or recompilation.&lt;/p&gt;

The Sigma LocalPotato rule is a perfectly competent detection rule for *the LocalPotato binary distributed at a specific commit*. It is essentially useless against the *technique*. An attacker recompiling LocalPotato from source breaks the IMPHASH selectors; renaming the output binary breaks the image-path selector; rewriting the CLI argument parsing breaks the third selector. The rule is brittle by construction, and the brittleness is structural to named-tool detection. The same point this article makes about Microsoft&apos;s per-CVE patches applies one level down: closing this binary does not close the technique; closing this technique does not close the primitive.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Invest detection budget in the Elastic primitive-level rule (or equivalent) and accept the higher false-positive rate that comes with it. The named-tool rules are a useful low-noise tripwire but should not be the primary signal. The same logic that makes the privilege durable against per-CVE patches makes the named-tool rules ephemeral against re-tooling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We have walked the eighteen-year history, named the three-piece system, surveyed the mitigations, articulated the Microsoft policy, hit the Hardy ceiling, scanned the open problems, and listed the operational tools. One thing remains: the eight misconceptions practitioners hold about this primitive that the article must explicitly correct.&lt;/p&gt;
&lt;h2&gt;11. FAQ -- Eight Misconceptions That Will Not Die&lt;/h2&gt;

No. UAC (User Account Control) is an interactive-token consent surface for desktop logons; it gates whether an interactive admin can elevate to a full administrator token at consent-prompt time. Service accounts have no interactive logon and never see a UAC prompt. NETWORK SERVICE and LOCAL SERVICE inherit `SeImpersonatePrivilege` in their default token regardless of UAC settings [@ms-learn-localservice; @ms-learn-networkservice]; the Potato chain runs entirely under the service token without ever touching the interactive consent surface.

No. Credential Guard protects long-term credentials (the NTLM hash, the Kerberos TGT) in an isolated user-mode trustlet whose memory the regular kernel cannot read. The Potato lineage does not steal a credential and does not call into LSASS-isolated memory -- see §9.3 for the architectural detail. The operational takeaway: Credential Guard and VBS are orthogonal to runtime token impersonation, and a security team buying VBS in response to Potato writeups is misallocating defensive budget.

Not if the account holds `SeImpersonatePrivilege`. LOCAL SERVICE and NETWORK SERVICE both hold it by default and have it enabled in their default tokens [@ms-learn-localservice; @ms-learn-networkservice]. The gate is the privilege, not the account name. A service that has been &quot;hardened&quot; by moving from SYSTEM to NETWORK SERVICE still has the gate open. Real hardening requires either removing the privilege from the account on that specific host (with the compatibility risks Section 10.2 describes) or running the service under a custom account that does not get the privilege auto-granted.

No. Microsoft has shipped CVEs for specific token-source primitives -- LocalPotato as CVE-2023-21746 [@nvd-cve-2023-21746], SilverPotato as CVE-2024-38061 [@nvd-cve-2024-38061], FakePotato as CVE-2024-38100 [@nvd-cve-2024-38100], the three-phase DCOM hardening as CVE-2021-26414 [@nvd-cve-2021-26414] -- but the underlying impersonation surface is documented-as-policy not to be addressed as a security boundary [@msrc-windows-security-servicing-criteria; @pierini-cocomazzi-troopers24-talk]. GodPotato remains functional across its tested README matrix (Server 2012-2022 / Windows 8-11) with no public Microsoft patch through mid-2026 [@beichendream-godpotato-readme]. PrintSpoofer and CoercedPotato variants remain functional on most hosts [@labro-2020-printspoofer-post; @prepouce-coercedpotato-repo]. The pattern is per-CVE closure of individual variants while the underlying privilege + coercion-API geometry remains in place.

Both, but the architectural responsibility is Windows&apos;s. The privilege is a Windows design decision; the coerced-authentication primitives are Windows components (RPCSS, Print Spooler, EFS RPC server). A service developer cannot opt out of `SeImpersonatePrivilege` by writing better code -- the SCM grants the privilege as part of the account setup, not at the developer&apos;s request. A service developer *can* run under a custom account configured without the privilege, but most service code paths assume impersonation works (especially Win32-era code, where `RpcImpersonateClient` is the standard idiom) and break in subtle ways without it.

Yes. IIS application pools cannot perform Windows-authenticated user impersonation; Exchange cannot run mailbox operations under the connecting user&apos;s identity; SQL Server cannot enforce per-login row security under Windows authentication; the SMB and EFS RPC servers cannot impersonate their callers [@ms-learn-impersonate-policy; @ms-learn-impersonatenamedpipeclient]. The MSRC policy text on the impersonation-policy page is explicit that the privilege is required for legitimate impersonation [@ms-learn-impersonate-policy]. Audit before you remove.

No. The Adminless / Administrator Protection feature is a per-action consent surface for interactive administrators [@ms-learn-admin-protection]. Service accounts (services, MSAs, gMSAs, virtual accounts) are out of scope by construction because none of them is an interactive admin account. The new boundary does not apply to the service-account population this article is about. There is no public Microsoft roadmap to extend it.

Because the named-pipe RPC server population (the SMB redirector, the Print Spooler, the EFS RPC server, and the long tail of pre-modern Win32 services) depends on this specific API, and the Microsoft-recommended alternatives (`RpcImpersonateClient`, the LSA-side variants) ultimately compose into the same kernel-side call -- §7.3 walks through the full ABI migration cost. The MSRC servicing carve-out [@msrc-windows-security-servicing-criteria] is the policy-level acknowledgement that the cost is not on the table.
&lt;h2&gt;12. The Line, Re-read&lt;/h2&gt;
&lt;p&gt;Bring the reader back to where this started: one line in &lt;code&gt;whoami /priv&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SeImpersonatePrivilege  Impersonate a client after authentication  Enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you know what it means. The line ships in the default token of every IIS application pool worker, every SQL Server service step, every Exchange worker process, and every other LOCAL SERVICE / NETWORK SERVICE-derived account on every shipping Windows release. The line gates &lt;code&gt;CreateProcessWithTokenW&lt;/code&gt;. The kernel-level token-substitution surface sits behind that gate. The named-pipe coercion API on the other side of the gate has shipped since Windows XP / Server 2003 and remains the dominant token source on the platform. Microsoft has shipped five containment mitigations in nineteen years -- each closes a real surface; none closes this primitive. The doctrinal articulation came at Troopers 24: Windows Service Hardening is a &lt;em&gt;safety&lt;/em&gt; boundary, not a &lt;em&gt;security&lt;/em&gt; boundary [@pierini-cocomazzi-troopers24-talk]. The 1988 ceiling that explains why is older than the operating system.&lt;/p&gt;

Microsoft gave every NETWORK SERVICE a privilege that, in the wrong hands, is equivalent to SYSTEM. They knew -- the MSRC said as much in April 2009 [@msrc-blog-2009-04-token-kidnapping]. They could not change it without breaking the service model: every closure path carries a documented compatibility cost they have explicitly declined to accept [@msrc-windows-security-servicing-criteria]. Pierini and Cocomazzi made the doctrine quotable at Troopers 24 [@pierini-cocomazzi-troopers24-talk]: WSH is a safety boundary, not a security boundary. Roughly eighteen years after Cerrudo first put that fact on the record [@cerrudo-2008-pdf], ten years after HotPotato made it pushbutton [@breen-2016-hot-potato], and three years after GodPotato survived the most aggressive DCOM hardening Microsoft has shipped [@beichendream-godpotato-readme; @nvd-cve-2021-26414], the primitive is still in place. It is not unpatched. It is documented-as-policy not to be patched.
&lt;p&gt;For the variant-by-variant chronology this article deliberately deferred -- HotPotato, RottenPotato, JuicyPotato, JuicyPotatoNG, PrintSpoofer, EfsPotato, CoercedPotato, RoguePotato, RemotePotato0, GodPotato, LocalPotato, SilverPotato, FakePotato -- see the sibling Potato Family article (2026-05-31). That article catalogues each named tool&apos;s CLSID, coercion primitive, and patch state. This one was about why the family exists at all.&lt;/p&gt;
&lt;p&gt;The one line in &lt;code&gt;whoami /priv&lt;/code&gt; is not a bug. It is the decision.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;seimpersonateprivilege-and-the-service-account-attack-surface&quot; keyTerms={[
  { term: &quot;SeImpersonatePrivilege&quot;, definition: &quot;Windows user right (constant SE_IMPERSONATE_NAME) that gates CreateProcessWithTokenW and the higher-level forms of ImpersonateNamedPipeClient; default-assigned and enabled on LOCAL SERVICE, NETWORK SERVICE, and Administrators.&quot; },
  { term: &quot;ImpersonateNamedPipeClient&quot;, definition: &quot;Win32 API by which a named-pipe-server thread receives the connected client&apos;s access token; shipped since Windows XP / Server 2003; the dominant token-source primitive on the platform.&quot; },
  { term: &quot;Confused Deputy&quot;, definition: &quot;Norm Hardy&apos;s 1988 name for the structural attack class in which a server holds more authority than its clients and acts on client requests, with no architectural way to keep the two authorities apart. The Potato lineage is the Windows-specific instantiation.&quot; },
  { term: &quot;Primary Token vs Impersonation Token&quot;, definition: &quot;Two flavours of the Windows access-token kernel object: primary tokens attach to processes for the process lifetime; impersonation tokens attach to individual threads and override the primary token for the thread&apos;s access checks.&quot; },
  { term: &quot;Impersonation Level&quot;, definition: &quot;Four-value enum (Anonymous, Identification, Impersonation, Delegation) carried on every impersonation token. Only Impersonation and Delegation tokens can be used to spawn a process under the borrowed identity.&quot; },
  { term: &quot;OXID Resolver&quot;, definition: &quot;The DCOM service that maps an OXID (Object Exporter Identifier) to the RPC binding string for a marshalled COM object. The Rotten/Juicy Potato chain forges OBJREF blobs with attacker-controlled OXID resolver fields.&quot; },
  { term: &quot;Windows Service Hardening (WSH)&quot;, definition: &quot;Microsoft&apos;s umbrella term for the post-2003 service-account mitigation stack (Service SIDs, restricted tokens, integrity levels, LPAC variants). Documented-as-policy a safety boundary, not a security boundary.&quot; },
  { term: &quot;Service SID&quot;, definition: &quot;A SID of the form NT SERVICE\\, generated as the SHA1 hash of the uppercased service name, attached to a service-process token to permit per-service ACLs without granting them to every service sharing the account.&quot; },
  { term: &quot;Restricted Token&quot;, definition: &quot;A token carrying a restricting-SID set in addition to its regular group SIDs; the kernel grants access only when both sets satisfy the ACL. Used to limit a compromised service&apos;s write surface.&quot; },
  { term: &quot;MSRC Servicing Criteria&quot;, definition: &quot;Microsoft&apos;s public policy document defining what counts as a security boundary for servicing purposes. The two-question test gates whether a vulnerability is addressed via a security update or merely considered for a future release.&quot; }
]} questions={[
  { q: &quot;Why does NETWORK SERVICE hold SeImpersonatePrivilege by default?&quot;, a: &quot;Because the 2003 service-hardening pivot moved services off NT AUTHORITY\\SYSTEM, but those services still needed to impersonate their RPC clients to enforce per-user access. The privilege was created as the named user right that lets the new low-privileged accounts keep doing what SYSTEM had implicitly done.&quot; },
  { q: &quot;What three components combine into the three-piece theorem of section 5?&quot;, a: &quot;(1) SeImpersonatePrivilege default-assigned to LOCAL SERVICE and NETWORK SERVICE; (2) the ImpersonateNamedPipeClient coercion API shipped since Windows XP / Server 2003; (3) the MSRC servicing-criteria carve-out treating WSH as a safety boundary rather than a security boundary.&quot; },
  { q: &quot;Why did MS09-012 not close the Potato family?&quot;, a: &quot;Because MS09-012 (the bulletin behind Cerrudo&apos;s &lt;em&gt;Chimichurri&lt;/em&gt; PoC) closed the specific handle-leak surface Cerrudo&apos;s 2008 disclosure used. It did not revoke SeImpersonatePrivilege, did not modify CreateProcessWithTokenW, and did not modify ImpersonateNamedPipeClient. The MSRC blog explicitly acknowledged on the record that the privilege was sufficient for the escalation but elected to fix the symptom, not the gate.&quot; },
  { q: &quot;What is the difference between primitive-level and named-tool detection, and why does it matter?&quot;, a: &quot;Primitive-level detection (e.g., the Elastic rogue-named-pipe rule) matches the pattern every Potato variant generates regardless of binary identity; named-tool detection (e.g., the Sigma LocalPotato rule) matches a specific binary&apos;s fingerprint via IMPHASH and CLI selectors. Named-tool detection is trivially evaded by rename or recompile; primitive-level detection survives re-tooling at the cost of a higher false-positive rate.&quot; },
  { q: &quot;If GodPotato is patchable in principle, why has Microsoft not patched it?&quot;, a: &quot;Because patching GodPotato requires changing either RPCSS&apos;s OXID-handling logic or the LSASS cached-token logic Forshaw documented in April 2020 -- both structural properties whose modification would cascade through dozens of dependent components. The MSRC servicing-criteria carve-out frames the broader class as a safety boundary, so individual variants in that class do not receive security-update servicing. GodPotato sits squarely in the carved-out region.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-internals</category><category>privilege-escalation</category><category>access-tokens</category><category>service-hardening</category><category>potato-family</category><category>msrc</category><category>confused-deputy</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>SYSTEM in Ten Seconds: How the Potato Family Survived Every Microsoft Mitigation</title><link>https://paragmali.com/blog/system-in-ten-seconds-how-the-potato-family-survived-every-m/</link><guid isPermaLink="true">https://paragmali.com/blog/system-in-ten-seconds-how-the-potato-family-survived-every-m/</guid><description>A decade of Windows local privilege escalation -- HotPotato through FakePotato -- rests on one architectural decision Microsoft has refused to revisit.</description><pubDate>Sun, 31 May 2026 00:00:00 GMT</pubDate><content:encoded>
The Potato family is a decade of Windows local privilege escalation, eleven named variants
disclosed between January 2016 (HotPotato) and August 2024 (FakePotato), all pivoting on the same
primitive: `SeImpersonatePrivilege` (introduced as a defined user right in the Windows 2000 SP4 /
XP SP2 / Server 2003 hardening cycle [@msrc-token-kidnapping; @ms-impersonate-policy]) plus `ImpersonateNamedPipeClient`
(a Win32 primitive documented as supported since Windows XP for clients and Windows Server 2003
for servers [@ms-impersonate-api]). Each variant -- HotPotato (January 2016), RottenPotato,
JuicyPotato, RoguePotato, PrintSpoofer, RemotePotato0, JuicyPotatoNG, GodPotato (the 2026
default), LocalPotato (CVE-2023-21746), SilverPotato, FakePotato (CVE-2024-38100) -- defeats a
specific Microsoft mitigation, but no mitigation closes the family. The structural reason is the
MSRC Windows Security Servicing Criteria, which treats the `SeImpersonatePrivilege`-to-SYSTEM
transition as a safety boundary, not a security boundary. The Potato class is therefore an
architectural decision, not a bug.
&lt;h2&gt;1. A Web Shell, Ten Seconds, SYSTEM&lt;/h2&gt;
&lt;p&gt;A red teamer drops a web shell on an Internet Information Services server running as &lt;code&gt;IIS APPPOOL\DefaultAppPool&lt;/code&gt;. Ten seconds later, the shell prints &lt;code&gt;nt authority\system&lt;/code&gt;. The operator did not exploit a memory-corruption bug, did not bypass a kernel security boundary, did not even use an undocumented API. They invoked &lt;code&gt;CoCreateInstance&lt;/code&gt; against a Distributed COM (DCOM) class identifier, waited for the SYSTEM-context RPCSS service to authenticate to a named pipe they owned, and called &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; [@ms-impersonate-api]. Every step was documented Win32 behaviour. The exploit is that Microsoft has spent a decade refusing to call any of those steps a security boundary [@msrc-servicing-criteria; @troopers24].&lt;/p&gt;
&lt;p&gt;The artefact in the operator&apos;s hand is one of several. In May 2026 it is most likely &lt;code&gt;GodPotato.exe -cmd &quot;cmd /c whoami&quot;&lt;/code&gt; -- a single Apache 2.0-licensed binary that BeichenDream published on GitHub on December 23, 2022 [@beichendream-god]. The README says it works on every supported Windows release from Windows 8 through Windows 11, and from Server 2012 through Server 2022 [@beichendream-god]. Community testing has since extended the working range to Server 2025 with default Distributed COM hardening enabled [@compass-three-headed].&lt;/p&gt;

A Windows user-rights assignment that lets a thread substitute another user&apos;s security context for its own (typically via `ImpersonateNamedPipeClient` or `ImpersonateLoggedOnUser`). Granted by default to `LOCAL SERVICE`, `NETWORK SERVICE`, every Internet Information Services application-pool identity, and most service accounts [@ms-impersonate-policy]. Introduced as a defined user right in the Windows 2000 SP4 / XP SP2 / Server 2003 service-hardening cycle that MSRC discusses in its 2009 Token Kidnapping retrospective [@msrc-token-kidnapping], after which possessing it has been one named-pipe round-trip away from being SYSTEM.
&lt;p&gt;The IIS context matters. The default application-pool identity holds &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; because IIS depends on it for legitimate request-scoped impersonation [@itm4n-printspoofer]. So does the default SQL Server service account, the Background Intelligent Transfer Service (BITS) account, the Spooler service account, and every account that hosts a Windows service that may need to &quot;act as&quot; a calling user. Anyone who can run code inside one of those accounts can run code as SYSTEM in seconds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Every step the operator takes -- &lt;code&gt;CoCreateInstance&lt;/code&gt;, the SYSTEM-context RPCSS authentication, &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;, the subsequent &lt;code&gt;CreateProcessWithToken&lt;/code&gt; -- is in Microsoft&apos;s published Win32 contract [@ms-impersonate-api; @ms-dcom-spec]. None of them is a memory-corruption bug. The &quot;exploit&quot; is the existence of a documented call sequence that turns a service account into SYSTEM, on a fully-patched Windows 11 box, in 2026.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the puzzle the rest of the article is here to solve. The technique has been a one-binary operation for nearly a decade [@troopers24]. Microsoft has shipped three named hardening waves against it (a 2019-2020 OXID-resolver fix [@forshaw-pz-2021]; the three-phase CVE-2021-26414 Distributed COM hardening rollout from June 2021 to March 2023 [@ms-kb5004442]; and per-variant CVE patches in 2023 and 2024 [@nvd-cve-2023-21746; @nvd-cve-2024-38100]). None of those waves closed the family. Why?&lt;/p&gt;
&lt;h2&gt;2. The Architectural Primitive&lt;/h2&gt;
&lt;p&gt;The answer is in a Microsoft document called the &lt;a href=&quot;https://paragmali.com/blog/windows-security-boundaries-the-document-that-decides-what-g/&quot; rel=&quot;noopener&quot;&gt;Windows Security Servicing Criteria&lt;/a&gt; [@msrc-servicing-criteria]. It defines what Microsoft will and will not service as a security vulnerability. Quoting the document directly: &quot;A security boundary provides a logical separation between the code and data of security domains with different levels of trust&quot; [@msrc-servicing-criteria]. The page then lists the boundaries Microsoft has defined for Windows -- kernel mode versus user mode, virtual machine versus host, session versus session, and so on. The list is the &lt;em&gt;enumeration&lt;/em&gt; that decides which bug classes get CVEs and which do not.&lt;/p&gt;
&lt;p&gt;The Potato family pivots on a transition that is conspicuously &lt;em&gt;not&lt;/em&gt; on the list: a service account that holds &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; becoming SYSTEM. As Andrea Pierini and Antonio Cocomazzi articulated in the Troopers 24 retrospective, Microsoft&apos;s published position is that the Windows Service Hardening boundary is a &lt;em&gt;safety&lt;/em&gt; boundary rather than a &lt;em&gt;security&lt;/em&gt; boundary, which is why so many Potato exploits continue to work on fully updated Windows systems [@troopers24]. WSH is Microsoft&apos;s own shorthand for &lt;strong&gt;Windows Service Hardening&lt;/strong&gt; -- the family of post-XP-SP2 protections that isolate service accounts from one another. The position is consistent with everything Microsoft has shipped: per-variant patches when a specific vehicle becomes too embarrassing, and silence on the underlying primitive. (The verbatim Troopers 24 articulation appears in §13.)&lt;/p&gt;

The boundary *definition* on `microsoft.com/en-us/msrc/windows-security-servicing-criteria` is rendered in static HTML and can be fetched directly [@msrc-servicing-criteria]. The boundary *enumeration table* immediately below it, which lists the bug classes that do and do not get CVEs, is JavaScript-rendered and does not appear in static fetches. The community-canonical secondary source for what is on that list is the Troopers 24 talk by Pierini and Cocomazzi [@troopers24], cross-referenced against James Forshaw&apos;s Project Zero retrospective from October 2021 [@forshaw-pz-2021] and Mark Russinovich&apos;s `aka.ms/win-security-boundaries` paraphrase. This article cites the primary for the definition and the Troopers retrospective for the enumeration.
&lt;p&gt;Three primitives, taken together, mechanically determine the entire family. Once they are stated, the only remaining question is which SYSTEM-context service is cheapest to coerce.&lt;/p&gt;
&lt;h3&gt;Primitive one: SeImpersonatePrivilege&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is a Windows user-rights assignment that permits a thread to call &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;, &lt;code&gt;ImpersonateLoggedOnUser&lt;/code&gt;, and the related impersonation APIs [@ms-impersonate-policy]. By Windows default, it is granted to &lt;code&gt;LOCAL SERVICE&lt;/code&gt;, &lt;code&gt;NETWORK SERVICE&lt;/code&gt;, every Internet Information Services application-pool identity, and most service accounts that need to act on behalf of clients [@itm4n-printspoofer]. (For when the right was introduced and a working definition, see §1; Decoder&apos;s one-sentence summary of what the grant means in practice is the climactic PullQuote in §6.3.)&lt;/p&gt;
&lt;h3&gt;Primitive two: ImpersonateNamedPipeClient&lt;/h3&gt;

A Win32 API that lets the server end of a named pipe adopt the security context of whoever just connected to that pipe. After the call, the calling thread holds an impersonation token for the client identity, and any subsequent system call (including `CreateProcessWithToken`) executes as that identity. The function has been part of `namedpipeapi.h` since Windows XP for clients and Windows Server 2003 for servers, with no deprecation notice as of the 2025-07-01 documentation revision [@ms-impersonate-api].
&lt;p&gt;The mechanism is exactly the one a SYSTEM-context service uses for legitimate request-scoped impersonation. The Potato class subverts it by getting a SYSTEM-context service to connect to a pipe the attacker owns. No memory corruption, no kernel exploit, no undocumented API. The Win32 reference describes the call as the standard way for a pipe server to &quot;impersonate the client end&quot; [@ms-impersonate-api].&lt;/p&gt;
&lt;h3&gt;Primitive three: the MSRC servicing-criteria carve-out&lt;/h3&gt;
&lt;p&gt;The third primitive is policy, not code. The MSRC document distinguishes a &lt;em&gt;security boundary&lt;/em&gt; (whose violation gets a CVE and a security update) from a &lt;em&gt;safety boundary&lt;/em&gt; (where Microsoft will patch when convenient but does not commit to a service-level objective). The defensible reading, articulated explicitly by Pierini and Cocomazzi at Troopers 24, is that the SYSTEM-from-&lt;code&gt;SeImpersonate&lt;/code&gt; transition lives on the safety side [@troopers24]. The implication is structural: a service account holding &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; &quot;is already privileged&quot; in Microsoft&apos;s policy view. Promoting it to SYSTEM is therefore not a privilege escalation that requires a security update.&lt;/p&gt;

flowchart LR
    A[Service account with SeImpersonatePrivilege] --&amp;gt; B[Coerce SYSTEM-context service to connect to attacker-owned named pipe]
    B --&amp;gt; C[Call ImpersonateNamedPipeClient on server thread]
    C --&amp;gt; D[Thread now holds SYSTEM impersonation token]
    D --&amp;gt; E[CreateProcessWithToken spawns SYSTEM process]
    F[MSRC servicing criteria carve-out] -.-&amp;gt;|&quot;Allows step A to remain a default grant&quot;| A
    F -.-&amp;gt;|&quot;Allows step C to remain a documented Win32 API&quot;| C
&lt;p&gt;Taken together, the three primitives reduce the entire Potato family to a single problem statement: &lt;em&gt;find the cheapest SYSTEM-context service to coerce into a callback&lt;/em&gt;. Every named variant since 2016 is an answer to that problem.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Microsoft does not consider the &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;-to-SYSTEM transition a security boundary; it considers it a safety boundary. The Potato family is the consequence. Variants change vehicles -- NetBIOS spoofing, BITS DCOM, Print Spooler RPC, EFS RPC, RPCSS OXID, ShellWindows -- but every one of them lives on the same architectural carve-out [@troopers24; @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The phrase &lt;code&gt;aka.ms/win-security-boundaries&lt;/code&gt; was popularised by Mark Russinovich&apos;s Channel 9 talks of the late 2010s. Channel 9 was retired on December 1, 2021, so the link is now mostly cited as a memorable handle for the boundary list rather than as a clickable URL. The live equivalent is the MSRC servicing criteria document itself [@msrc-servicing-criteria].&lt;/p&gt;
&lt;p&gt;Given primitives this old and this widely default-granted -- both the named-pipe impersonation API and the &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; user right have been in their current form since the Windows 2000 SP4 / Server 2003 / XP SP2 service-hardening cycle [@msrc-token-kidnapping; @ms-impersonate-policy; @ms-impersonate-api] -- the natural question is why the named Potato family did not appear until 2016. The next section is the answer.&lt;/p&gt;
&lt;h2&gt;3. The Long Pre-Potato Era, 2001-2015&lt;/h2&gt;
&lt;p&gt;In March 2008, Cesar Cerrudo stood on a stage in Dubai at Hack-in-the-Box and demonstrated that a SYSTEM-context Windows service holding &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; was, in effect, one named-pipe call away from SYSTEM [@cerrudo-hitb-slides; @msrc-token-kidnapping]. Microsoft acknowledged the technique on the MSRC blog on April 14, 2009, and shipped MS09-012 -- the patch Cerrudo later nicknamed &quot;Chimichurri&quot; in his Black Hat USA 2010 follow-up [@msrc-token-kidnapping; @blackhat-2010-cerrudo]. Cerrudo extended the work two years later at Black Hat USA 2010 in a paper titled &quot;Token Kidnapping&apos;s Revenge&quot; [@blackhat-2010-cerrudo]. Microsoft patched the specific NetworkService-to-SYSTEM vehicle. They did not revoke the privilege from the service accounts that held it [@msrc-token-kidnapping].&lt;/p&gt;
&lt;p&gt;That pattern -- patch the vehicle, leave the primitive -- is the family&apos;s bequest from Cerrudo.&lt;/p&gt;

NTLM **relay** forwards an NTLM authentication captured from victim A to a different server B, where the attacker authenticates as A. NTLM **reflection** is the special case where B is the same machine (often the same protocol) as A. Microsoft fixed the most obvious same-protocol case with MS08-068 in 2008 [@ms-ms08-068]. Cross-protocol reflection (HTTP-to-SMB, DCOM-to-RPC) was not closed by that patch and became the doorway through which the Potato family entered.
&lt;p&gt;Seven years before Cerrudo, on March 31, 2001, Sir Dystic of the Cult of the Dead Cow stood on a different stage at @lanta.con in Atlanta and released SMBRelay, the first public same-protocol &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;NTLM relay&lt;/a&gt; tool [@cultdeadcow-smbrelay]. Microsoft eventually responded with MS08-068, a &lt;em&gt;same-protocol-only&lt;/em&gt; fix [@ms-ms08-068]. Cross-protocol relay -- HTTP to SMB, DCOM to local RPC -- remained open.&lt;/p&gt;
&lt;p&gt;That opening was the canvas James Forshaw painted on. In December 2014, then at Google Project Zero, Forshaw filed Issue 222 (&quot;Windows: Local WebDAV NTLM Reflection EoP&quot;) demonstrating that the WebClient service performs NTLM authentication when asked to open a WebDAV URL, and that the resulting NTLM session can be reflected cross-protocol to the local SMB service [@forshaw-pz-2021]. A few months later Forshaw filed Issue 325, showing that &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; could coerce a DCOM activation into authenticating to an attacker-controlled TCP endpoint. Microsoft patched the 2015 issue as CVE-2015-2370 [@nvd-cve-2015-2370]. In his October 2021 retrospective Forshaw wrote, with the laconic precision of a researcher whose contributions are still being weaponised seven years later:&lt;/p&gt;

The technique to locally relay authentication for DCOM was something I originally reported back in 2015 (issue 325). This issue was fixed as CVE-2015-2370, however the underlying authentication relay using DCOM remained. This was repurposed and expanded upon by various others for local and remote privilege escalation in the RottenPotato series of exploits. -- James Forshaw, Project Zero, October 2021 [@forshaw-pz-2021]
&lt;p&gt;Cerrudo nicknamed the MS09-012 patch &quot;Chimichurri&quot; after the Argentine green sauce, and used the name when he reprised the work at Black Hat USA 2010 [@blackhat-2010-cerrudo]. Cerrudo was at Argeniss and later IOActive when he developed the technique [@msrc-token-kidnapping; @blackhat-2010-cerrudo].&lt;/p&gt;
&lt;p&gt;The primary artefact for Cerrudo&apos;s March 2008 Hack-in-the-Box Dubai talk (slides, video, abstract) is no longer reachable on the conference site; the MSRC blog&apos;s retrospective is the canonical secondary that anchors the date and venue [@msrc-token-kidnapping]. The Black Hat USA 2010 &quot;Token Kidnapping&apos;s Revenge&quot; whitepaper [@blackhat-2010-cerrudo] is the durable primary for the underlying technique.&lt;/p&gt;

gantt
    title Pre-Potato lineage 2001-2015
    dateFormat YYYY-MM
    section NTLM relay
    SMBRelay (Sir Dystic) :a1, 2001-03, 1M
    MS08-068 same-protocol fix :a2, 2008-10, 1M
    section Token escalation
    Token Kidnapping HITB Dubai (Cerrudo) :b1, 2008-03, 1M
    MS09-012 Chimichurri :b2, 2009-04, 1M
    Token Kidnapping&apos;s Revenge (Cerrudo) :b3, 2010-07, 1M
    section DCOM primitive
    Project Zero Issue 222 (Forshaw) :c1, 2014-12, 1M
    Project Zero Issue 325 (Forshaw) :c2, 2015-04, 1M
    CVE-2015-2370 patch :c3, 2015-07, 1M
&lt;p&gt;By the end of 2015 the three pieces were on the table. A long-standing default privilege grant (Cerrudo&apos;s &quot;SeImpersonate equals SYSTEM&quot; thesis). A specific cross-protocol reflection technique (Forshaw&apos;s WebDAV-to-SMB Issue 222). A specific DCOM-activation coercion primitive (Forshaw&apos;s &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; Issue 325). Microsoft had patched the literal bug in the third piece and explicitly declined to revoke the privilege in the first. The technique was published, the proof-of-concept code was on GitHub, and the family was a binary release away. The next chapter is the moment someone shipped the binary.&lt;/p&gt;
&lt;h2&gt;4. HotPotato, January 16, 2016&lt;/h2&gt;
&lt;p&gt;On January 16, 2016, Stephen Breen of Foxglove Security published a blog post titled &quot;Hot Potato&quot; [@foxglove-hotpotato]. He had just spoken at ShmooCon. The repository, &lt;code&gt;foxglovesec/Potato&lt;/code&gt;, would land on GitHub three weeks later, on February 9, 2016 [@foxglove-potato-repo]. The post&apos;s opening sentence is the family&apos;s birth certificate:&lt;/p&gt;

Hot Potato (aka: Potato) takes advantage of known issues in Windows to gain local privilege escalation in default configurations, namely NTLM relay (specifically HTTP-&amp;gt;SMB relay) and NBNS spoofing. -- Stephen Breen, Foxglove Security, January 16, 2016 [@foxglove-hotpotato]
&lt;p&gt;Breen had not invented NTLM reflection. He had combined three existing primitives into a single-binary, one-click privilege escalation that worked on every default Windows install from Windows 7 through Server 2012 [@foxglove-hotpotato]. The Foxglove post acknowledges the lineage explicitly: &quot;a similar technique was disclosed by the guys at Google Project Zero ... In fact, some of our code was shamelessly borrowed from their PoC&quot; [@foxglove-hotpotato].&lt;/p&gt;
&lt;h3&gt;How HotPotato works&lt;/h3&gt;
&lt;p&gt;The exploit chains three independent tricks. Step one is UDP-port exhaustion. The tool opens enough UDP sockets that the local NetBIOS Name Service (NBNS) name lookups fail, forcing Windows to fall back to broadcast-based name resolution [@foxglove-hotpotato]. Step two is NBNS spoofing of the WPAD hostname, pointed at &lt;code&gt;127.0.0.1&lt;/code&gt;. Step three is the actual reflection: when Windows Update or Windows Defender polls for an update, it consults the WPAD URL, gets the attacker&apos;s proxy auto-configuration script, and routes its HTTP requests through the attacker&apos;s local listener -- which then relays the SYSTEM-context NTLM negotiation to the local SMB service [@foxglove-hotpotato].&lt;/p&gt;

sequenceDiagram
    participant Atk as Hot Potato tool
    participant NBNS as NetBIOS Name Service
    participant WU as Windows Update (SYSTEM)
    participant WPAD as WPAD HTTP listener (attacker)
    participant SMB as Local SMB service
    Atk-&amp;gt;&amp;gt;NBNS: UDP-flood to exhaust ports and force broadcast
    Atk-&amp;gt;&amp;gt;NBNS: Spoof WPAD hostname pointing at 127.0.0.1
    WU-&amp;gt;&amp;gt;WPAD: GET wpad.dat over HTTP
    WPAD--&amp;gt;&amp;gt;WU: Attacker-supplied proxy auto-config
    WU-&amp;gt;&amp;gt;WPAD: HTTP request with SYSTEM-context NTLM negotiate
    WPAD-&amp;gt;&amp;gt;SMB: Reflect the NTLM exchange to local SMB
    SMB--&amp;gt;&amp;gt;Atk: SMB session authenticated as SYSTEM
    Atk-&amp;gt;&amp;gt;Atk: ImpersonateNamedPipeClient and spawn SYSTEM shell
&lt;p&gt;The result was a single binary that produced a SYSTEM shell from any local user account on the target host -- because on a default Windows install every authenticated local user can run code, open UDP sockets, and bind a loopback HTTP listener, which is all HotPotato needs to bootstrap.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; HotPotato does not use Distributed COM activation at all. It uses NetBIOS spoofing, WPAD hijacking, and HTTP-to-SMB cross-protocol relay. The family is named for HotPotato but the &lt;em&gt;defining&lt;/em&gt; primitive of every later variant -- DCOM activation -- is absent. HotPotato is in the family because it pivots through the same &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; plus named-pipe-impersonation core, which is the actual definition of the family. The repository name &lt;code&gt;Potato&lt;/code&gt; and the family naming convention are both Breen&apos;s [@foxglove-potato-repo].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The naming pattern that has now produced eleven variants started with the GitHub repository name &lt;code&gt;foxglovesec/Potato&lt;/code&gt; [@foxglove-potato-repo]. Breen later wrote that &quot;Hot&quot; was a riff on the fact that the SYSTEM token was passed around like a hot potato; the suffix convention spread from there organically.&lt;/p&gt;
&lt;h3&gt;Why HotPotato did not last&lt;/h3&gt;
&lt;p&gt;HotPotato had three structural weaknesses. NetBIOS spoofing is unreliable: the UDP-port exhaustion can fail under load, group policy can pin a real WPAD URL, and a legitimate WPAD response can win the race. NetBIOS is disabled in security-hardened environments as a matter of routine. And the HTTP-to-SMB cross-protocol path was the very thing Extended Protection for Authentication and SMB channel-binding tokens were designed to close [@crowdstrike-drop-mic]. On a Windows 10 1607 host with EPA on the SMB server, HotPotato failed.&lt;/p&gt;
&lt;p&gt;Researchers needed a coercion vehicle that was deterministic, did not rely on broadcast spoofing, and used a protocol Microsoft had not yet hardened end-to-end. Forshaw&apos;s Project Zero Issue 325 -- the &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; DCOM trigger -- met all three criteria [@forshaw-pz-2021]. The next variant weaponised it.&lt;/p&gt;
&lt;h2&gt;5. The DCOM-Activation Breakthrough, 2016-2018&lt;/h2&gt;
&lt;h3&gt;5.1 RottenPotato (DerbyCon 6, September 2016)&lt;/h3&gt;
&lt;p&gt;Eight months after HotPotato, Stephen Breen returned with a co-author and a new vehicle. The talk was on September 23, 2016 -- the Friday of DerbyCon 6 -- and the blog post followed three days later [@foxglove-rottenpotato]. The Foxglove post identifies the co-author by name: &quot;myself and my partner in crime, Chris Mallz (@vvalien1) spoke at DerbyCon about a project we&apos;ve been working on for the last few months&quot; [@foxglove-rottenpotato].&lt;/p&gt;
&lt;p&gt;Many secondary sources credit Andrea Pierini (Decoder) as the RottenPotato co-author. The Foxglove primary disproves this verbatim [@foxglove-rottenpotato]. Decoder enters the family lineage two years later, with JuicyPotato in 2018 [@ohpe-juicy]. Chris Mallz is the actual RottenPotato co-author.&lt;/p&gt;
&lt;p&gt;RottenPotato replaced HotPotato&apos;s NetBIOS-and-WPAD chain with Forshaw&apos;s DCOM-activation primitive. The hard-coded target was the Background Intelligent Transfer Service (BITS) Distributed COM server, class identifier &lt;code&gt;{4991d34b-80a1-4291-83b6-3328366b9097}&lt;/code&gt;, and the hard-coded listener port was &lt;code&gt;127.0.0.1:6666&lt;/code&gt; [@foxglove-rottenpotato; @foxglove-rotten-repo].&lt;/p&gt;

A Win32 OLE function that instantiates a Distributed COM object using a marshalled `IStorage` interface pointer as the activation source. By marshalling an `IStorage` whose object exporter identifier (OXID) resolves to an attacker-controlled TCP endpoint, the activator can redirect the resulting authentication callback to a listener it owns. Forshaw filed this as Project Zero Issue 325 in 2015 [@forshaw-pz-2021]; RottenPotato weaponised it.

sequenceDiagram
    participant Atk as RottenPotato (service account)
    participant Pipe as Local listener on 127.0.0.1:6666
    participant DCOM as DCOM activation (RPCSS)
    participant BITS as BITS COM server (SYSTEM)
    participant RPC as Local RPC on port 135
    Atk-&amp;gt;&amp;gt;Pipe: Start TCP listener on 127.0.0.1:6666
    Atk-&amp;gt;&amp;gt;DCOM: CoGetInstanceFromIStorage with BITS CLSID and marshalled IStorage
    DCOM-&amp;gt;&amp;gt;BITS: Spawn BITS under SYSTEM context
    BITS-&amp;gt;&amp;gt;Pipe: Callback to the marshalled endpoint
    Pipe-&amp;gt;&amp;gt;RPC: Forward COM packets to local RPC on port 135
    RPC--&amp;gt;&amp;gt;Pipe: Reply containing SYSTEM-context NTLM exchange
    Pipe--&amp;gt;&amp;gt;Atk: SYSTEM authentication captured
    Atk-&amp;gt;&amp;gt;Atk: ImpersonateNamedPipeClient and CreateProcessWithToken
&lt;p&gt;The technique was 100% reliable on Windows 7 through Windows 10 1803 and Server 2008 R2 through Server 2016 [@foxglove-rottenpotato]. There was no broadcast spoofing on the wire, no race condition, and no dependence on Windows Update polling. The price was rigidity: the hard-coded BITS class identifier and port 6666 made the tool brittle to BITS being disabled, and the original release depended on the Metasploit framework.&lt;/p&gt;
&lt;h3&gt;5.2 RottenPotatoNG and lonelypotato&lt;/h3&gt;
&lt;p&gt;In December 2017, the user &lt;code&gt;breenmachine&lt;/code&gt; published RottenPotatoNG, a C++ port that removed the Metasploit dependency: &quot;New version of RottenPotato as a C++ DLL and standalone C++ binary - no need for meterpreter or other tools&quot; [@breenmachine-rottenng]. The codebase that JuicyPotato would later generalise was now in place.&lt;/p&gt;

Many surveys date the `decoder-it/lonelypotato` variant to &quot;early 2018&quot; and place it as the link between RottenPotatoNG and JuicyPotato. The GitHub REST API reports `created_at: 2020-02-08T16:30:00Z` for the repository [@decoder-lonely], a full two years later. Decoder&apos;s first appearance in the Potato lineage is actually the December 6, 2019 post &quot;We thought they were Potatoes but they were Beans&quot; [@decoder-beans], with `lonelypotato` arriving in February 2020 as a post-OXID-hardening cleanup variant adjacent to RoguePotato [@decoder-lonely]. The 2017-2018 attribution is a citation error that has propagated across several survey papers.
&lt;h3&gt;5.3 JuicyPotato (Pierini + Trotta, July-August 2018)&lt;/h3&gt;
&lt;p&gt;What if any class identifier, not just the BITS one, could be the activation target? On July 27, 2018, Andrea Pierini and Giuseppe Trotta published the answer. The repository &lt;code&gt;ohpe/juicy-potato&lt;/code&gt; was created that day per the GitHub REST API; the blog post followed on August 10, 2018 [@ohpe-juicy]. The repository description reads: &quot;Juicy Potato (abusing the golden privileges) -- A sugared version of RottenPotatoNG, with a bit of juice&quot; [@ohpe-juicy].&lt;/p&gt;
&lt;p&gt;The original JuicyPotato blog post at &lt;code&gt;decoder.cloud/2018/08/10/juicy-potato-abusing-the-golden-privileges/&lt;/code&gt; returns HTTP 404 in 2026, and no Wayback Machine snapshot exists for that exact URL. The &lt;code&gt;ohpe/juicy-potato&lt;/code&gt; README is the live verbatim mirror of the title and the technique walkthrough [@ohpe-juicy]. Pierini&apos;s blog has reorganised several times; older posts that survive elsewhere on &lt;code&gt;decoder.cloud&lt;/code&gt; include the October 2018 &quot;No more Rotten/Juicy Potato&quot; [@decoder-no-more-rotten] and the December 2019 &quot;We thought they were Potatoes&quot; [@decoder-beans].&lt;/p&gt;
&lt;p&gt;JuicyPotato turned RottenPotato into a search engine. The README ships a per-Windows-version class identifier matrix: each row a Windows release, each column a CLSID that activates under SYSTEM context and implements the &lt;code&gt;IMarshal&lt;/code&gt; interface [@ohpe-juicy]. The tool accepts a tunable listener port (replacing the hard-coded 6666), a tunable process-creation mode (&lt;code&gt;CreateProcessWithToken&lt;/code&gt; for &lt;code&gt;SeImpersonate&lt;/code&gt; holders, &lt;code&gt;CreateProcessAsUser&lt;/code&gt; for &lt;code&gt;SeAssignPrimaryToken&lt;/code&gt; holders, or both), and a TEST mode for class-identifier discovery [@ohpe-juicy].&lt;/p&gt;

Microsoft does not freeze the set of registered Distributed COM class identifiers across Windows builds. Default COM-server registrations change between releases as components are added, removed, or refactored. A class identifier that activates under SYSTEM on Windows 10 1709 may not exist on Server 2019. JuicyPotato&apos;s CLSID matrix is therefore not a static lookup table -- it is the precomputed result of an empirical per-build search [@ohpe-juicy]. Every red-team handbook published between 2018 and 2020 references this matrix; subsequent variants (RoguePotato, JuicyPotatoNG) inherit and update it.

flowchart TD
    A[Enumerate registered DCOM CLSIDs on target build] --&amp;gt; B{&quot;For each CLSID&quot;}
    B --&amp;gt; C[Attempt CoGetInstanceFromIStorage with marshalled IStorage]
    C --&amp;gt; D{&quot;Activation reaches attacker listener?&quot;}
    D --&amp;gt;|No| B
    D --&amp;gt;|Yes| E{&quot;Callback authenticates as SYSTEM?&quot;}
    E --&amp;gt;|No| B
    E --&amp;gt;|Yes| F[Log CLSID into per-OS matrix]
    F --&amp;gt; B
    B --&amp;gt; G[Output: working CLSID for this Windows build]
&lt;p&gt;The Potato class was now universal. From mid-2018 through 2019 it was the default tool in every red-team handbook, every Metasploit-adjacent post-exploitation cheat-sheet, and every penetration-testing certification&apos;s lab. Microsoft had noticed.&lt;/p&gt;
&lt;h2&gt;6. The Mitigation Arms Race, 2020-2024&lt;/h2&gt;
&lt;p&gt;Every subsection below is the same shape: Microsoft ships a mitigation, researchers find a counter-move, MSRC produces an artifact (a CVE, a &quot;Won&apos;t Fix&quot; decision, or silence), and the architectural reading gets one more empirical confirmation.&lt;/p&gt;
&lt;h3&gt;6.1 The first Distributed COM mitigation, 2019-2020&lt;/h3&gt;
&lt;p&gt;In late 2018, Windows 10 1809 and Server 2019 began shipping a change to RPCSS. JuicyPotato stopped working. Researchers who reverse-engineered the change discovered that the OXID resolver address on the local Distributed COM activation path was now hard-coded to &lt;code&gt;127.0.0.1:135&lt;/code&gt;. The marshalled &lt;code&gt;IStorage&lt;/code&gt; callback could no longer be redirected to an arbitrary loopback port. Forshaw described it bluntly three years later:&lt;/p&gt;

Being able to redirect the OXID resolver RPC connection locally to a different TCP port was not by design and Microsoft eventually fixed this in Windows 10 1809/Server 2019. -- James Forshaw, October 2021 [@forshaw-pz-2021]
&lt;p&gt;No CVE was assigned. The change shipped silently as part of the regular Patch Tuesday cycle [@forshaw-pz-2021]. Pierini and Cocomazzi tested it on their own workloads and confirmed the failure mode publicly in October 2018: &quot;Recently I downloaded the new Windows server 2019 and upgraded my Win10 box to 1809 ... the juicy/rotten exploit ... did not work on both OS&quot; [@decoder-no-more-rotten].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The 2019-2020 OXID-resolver change is the first Microsoft response to the Potato family. It does not declare Distributed COM activation a security boundary. It narrows the resolver port to 135 and leaves the underlying primitive (coerce SYSTEM context via OXID resolver, then impersonate the resulting token) intact. The mitigation defines exactly one specific bypass; researchers had to discover that themselves [@forshaw-pz-2021; @decoder-no-more-rotten].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.2 RoguePotato (Cocomazzi + Pierini, May 2020)&lt;/h3&gt;
&lt;p&gt;On May 10, 2020, Antonio Cocomazzi published the RoguePotato repository on GitHub [@antonio-rogue]. The disclosure post appeared the next day, May 11. The README banner is &quot;RoguePotato @splinter_code &amp;amp; @decoder_it&quot; -- the same Pierini-and-Cocomazzi team that goes on to author RemotePotato0, JuicyPotatoNG, LocalPotato, and SilverPotato [@antonio-rogue].&lt;/p&gt;
&lt;p&gt;The counter-move accepts the hard-coded port-135 constraint and works around it. RoguePotato is two pieces. On an attacker-controlled remote host, run a port forwarder that listens on TCP 135 and redirects to a chosen attacker port. On the target, run &lt;code&gt;RoguePotato.exe&lt;/code&gt; pointing the OXID resolver at the remote forwarder. RPCSS dutifully sends the resolution request to the remote host on port 135 (since Microsoft hard-coded the &lt;em&gt;port&lt;/em&gt;, not the &lt;em&gt;host&lt;/em&gt;); the forwarder bounces the traffic back to the target on the attacker-chosen port; RoguePotato impersonates the OXID resolver and steers the activation back to a SYSTEM-context COM server [@antonio-rogue]. Standard NTLM relay and named-pipe impersonation finish the job.&lt;/p&gt;

flowchart LR
    A[RoguePotato.exe on target] --&amp;gt; B[RPCSS sends OXID resolution to remote-host port 135]
    B --&amp;gt; C[Remote port forwarder on attacker VPS]
    C --&amp;gt; D[Forward to target on attacker-chosen port]
    D --&amp;gt; E[Fake OXID resolver inside RoguePotato]
    E --&amp;gt; F[Steer activation to SYSTEM-context COM server]
    F --&amp;gt; G[Named-pipe impersonation, CreateProcessWithToken, SYSTEM shell]
&lt;p&gt;{&lt;code&gt;// Step 1 -- on an attacker-controlled remote host (any internet-reachable VPS): const forwarder = &quot;socat tcp-listen:135,reuseaddr,fork tcp:10.0.0.3:9999&quot;; // Step 2 -- on the target with SeImpersonatePrivilege: const exploit = &apos;RoguePotato.exe -r 10.0.0.3 -e &quot;C:\\\\windows\\\\system32\\\\cmd.exe&quot; -l 9999&apos;; console.log(&quot;Remote forwarder:&quot;, forwarder); console.log(&quot;Target exploit  :&quot;, exploit); console.log(&quot;Expected output : nt authority\\\\system&quot;);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;RoguePotato proved that the mitigation Microsoft chose did not break the underlying primitive. It only forced the attack to phone home. Two failure modes followed: in egress-filtered networks where outbound TCP 135 is blocked, the technique cannot run, and the remote forwarder is operationally noisy. Researchers needed a workaround that lived entirely on the target.&lt;/p&gt;
&lt;h3&gt;6.3 PrintSpoofer (Clément Labro, early May 2020)&lt;/h3&gt;
&lt;p&gt;Around the same time as RoguePotato, in early May 2020 (GitHub repository &lt;code&gt;itm4n/PrintSpoofer&lt;/code&gt; created April 28, 2020; blog post first archived in the Wayback Machine on May 3, 2020), Clément Labro -- writing as &lt;code&gt;itm4n&lt;/code&gt; -- published &quot;PrintSpoofer -- Abusing Impersonation Privileges on Windows 10 and Server 2019&quot; [@itm4n-printspoofer]. The mechanism uses no Distributed COM at all.&lt;/p&gt;
&lt;p&gt;The Print Spooler service exposes an RPC call, &lt;code&gt;RpcRemoteFindFirstPrinterChangeNotificationEx&lt;/code&gt;, that accepts a UNC path; the Spooler -- running as SYSTEM -- connects to that path to deliver printer-change notifications. Point the path at an attacker-owned named pipe; the Spooler connects; call &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;; done [@itm4n-printspoofer]. Labro articulated the family&apos;s thesis statement in the post, attributing it to Decoder:&lt;/p&gt;

If you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM. -- attributed to Andrea Pierini (@decoder_it), quoted by Clément Labro in the PrintSpoofer writeup, May 2020 [@itm4n-printspoofer]

sequenceDiagram
    participant Atk as PrintSpoofer (SeImpersonate holder)
    participant Pipe as Attacker-owned named pipe
    participant Spooler as Print Spooler (SYSTEM)
    Atk-&amp;gt;&amp;gt;Pipe: Create named pipe and start accept loop
    Atk-&amp;gt;&amp;gt;Spooler: RpcRemoteFindFirstPrinterChangeNotificationEx with attacker UNC
    Spooler-&amp;gt;&amp;gt;Pipe: Connect to UNC path under SYSTEM context
    Pipe-&amp;gt;&amp;gt;Atk: ImpersonateNamedPipeClient on server thread
    Atk-&amp;gt;&amp;gt;Atk: CreateProcessWithToken spawns SYSTEM shell
&lt;p&gt;This is the moment the architectural reading clicks. The family is &lt;em&gt;not&lt;/em&gt; about Distributed COM activation. Closing DCOM would not close the family. The next variant would use Spooler RPC, the one after that would use the Encrypting File System RPC, and the one after that would use Microsoft Distributed Transaction Coordinator RPC. Forshaw&apos;s contemporaneous April 2020 tiraniddo.dev post on shared logon sessions makes the same architectural point from a different angle [@forshaw-tiraniddo-2020].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Potato family is about the primitive, not the vehicle. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; plus &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; plus any SYSTEM-context Windows service with a callback-style API equals SYSTEM. Closing one vehicle (Distributed COM activation) leaves every other vehicle (Spooler RPC, EFS RPC, the next service that gets a callback interface) wide open [@itm4n-printspoofer; @forshaw-tiraniddo-2020].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.4 RemotePotato0 and the &quot;Won&apos;t Fix&quot;&lt;/h3&gt;
&lt;p&gt;In April 2021, Cocomazzi and Pierini pushed the technique across the network in a SentinelLabs post titled &quot;Relaying Potatoes: DCE/RPC NTLM Relay EoP&quot; [@sentinellabs-relaying]. The repository tagline names the outcome bluntly: &quot;Just another &apos;Won&apos;t Fix&apos; Windows Privilege Escalation from User to Domain Admin&quot; [@antonio-remote].&lt;/p&gt;
&lt;p&gt;The mechanism is cross-session NTLM relay over Distributed COM and RPC. An unprivileged local user triggers the Distributed COM activation service to make another user logged on the same machine (typically an administrator in an interactive RDP session) authenticate via NTLM. The captured NTLM exchange is then cross-protocol relayed (RPC to LDAP, with a port forwarder bridging the gap) to a domain controller with LDAP signing disabled. The attacker writes their own account into a privileged group or registers resource-based constrained delegation, and the engagement is over [@sentinellabs-relaying].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s response is the most quoted sentence in the family&apos;s history:&lt;/p&gt;

The current status of this vulnerability is &apos;won&apos;t fix&apos; ... Although Microsoft considers the vulnerability an important privilege escalation, it has been classified as &apos;Won&apos;t Fix&apos;. -- SentinelLabs disclosure of RemotePotato0, April 2021 [@sentinellabs-relaying]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; RemotePotato0 was a fully working exploit chain that promoted any local low-privilege user to Domain Admin. Microsoft was given the disclosure, replicated the technique, and declined to issue a CVE. This is the moment the architectural reading stops being a researcher narrative and becomes a documented MSRC decision [@sentinellabs-relaying]. Microsoft eventually shipped a partial mitigation in October 2022 that broke the RPC-to-LDAP scenario specifically, but the underlying primitive survives in adjacent variants [@antonio-remote].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.5 The CVE-2021-26414 Distributed COM hardening rollout&lt;/h3&gt;
&lt;p&gt;Two months after the RemotePotato0 disclosure, Microsoft began the only DCOM-side hardening it would ship under a CVE. KB5004442 documents a three-phase rollout, quoted verbatim from the article: &quot;The first phase of DCOM updates was released on June 8, 2021. In that update, DCOM hardening was disabled by default. ... The second phase of DCOM updates was released on June 14, 2022. ... The final phase of DCOM updates will be released in March 2023. It will keep the DCOM hardening enabled and remove the ability to disable it&quot; [@ms-kb5004442].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Phase 1&lt;/td&gt;
&lt;td&gt;June 8, 2021&lt;/td&gt;
&lt;td&gt;DCOM hardening shipped, &lt;em&gt;disabled by default&lt;/em&gt;. Administrators may opt in via registry.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phase 2&lt;/td&gt;
&lt;td&gt;June 14, 2022&lt;/td&gt;
&lt;td&gt;Hardening &lt;em&gt;enabled by default&lt;/em&gt;. Registry opt-out still available.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phase 3&lt;/td&gt;
&lt;td&gt;March 14, 2023&lt;/td&gt;
&lt;td&gt;Hardening &lt;em&gt;enforced with no opt-out&lt;/em&gt;. The &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; minimum is mandatory.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The RPC authentication-level constant that requires every packet of an RPC exchange to be signed for integrity (level 5 of 6). CVE-2021-26414 raises the *minimum* DCOM activation authentication level to this constant, rejecting legacy Distributed COM clients that activate at lower levels. The full rejection appears in Windows Event ID 10036 as &quot;The server-side authentication level policy does not allow the user %1\\%2 SID (%3) from address %4 to activate DCOM server. Please raise the activation authentication level at least to RPC_C_AUTHN_LEVEL_PKT_INTEGRITY in client application&quot; [@ms-kb5004442].
&lt;p&gt;The hardening raised the bar for legacy Distributed COM client authentication. It did not declare Distributed COM activation a security boundary [@ms-kb5004442; @ms-techcommunity-dcom]. The &quot;Manage changes&quot; framing in the KB title is deliberate: this is a compatibility migration with telemetry events (10036 server-side, 10037 and 10038 client-side) so enterprises can find legacy clients before the final cut [@ms-kb5004442].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Distributed COM is everywhere in Windows. Removing the ability to activate at a lower authentication level breaks legacy Distributed COM applications that have not been updated since at least 2014. Microsoft&apos;s 21-month rollout window between Phase 1 (June 2021) and Phase 3 (March 2023) was a compatibility migration -- the telemetry events let enterprise IT find and fix the legacy clients before the final cut [@ms-kb5004442; @ms-techcommunity-dcom]. The hardening is the most aggressive Distributed COM mitigation Microsoft has ever shipped, and even so it does not declare Distributed COM activation a security boundary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Researchers had 21 months to find a way around it. They took 18.&lt;/p&gt;
&lt;h3&gt;6.6 JuicyPotatoNG (Pierini + Cocomazzi, September 21, 2022)&lt;/h3&gt;
&lt;p&gt;Pierini and Cocomazzi returned on September 21, 2022, with JuicyPotatoNG -- the last pre-Phase-3 Distributed COM activation variant [@decoder-juicyng]. The blog post is titled &quot;Giving JuicyPotato a second chance: JuicyPotatoNG&quot; and walks through three counter-moves combined into a single binary [@decoder-juicyng; @antonio-juicyng].&lt;/p&gt;
&lt;p&gt;First, the tool embeds Forshaw&apos;s October 2021 local-OXID trick. Forshaw had shown that an OXID resolution request could be answered by a local Distributed COM server on a randomly selected port, dropping the need for an external forwarder [@forshaw-pz-2021]. JuicyPotatoNG ships that trick as a default. Second, it falls back to a tight set of usable class identifiers; the default is &lt;code&gt;{854A20FB-2D44-457D-992F-EF13785D2B51}&lt;/code&gt;, the PrintNotify class [@antonio-juicyng]. Third, it calls &lt;code&gt;LogonUser&lt;/code&gt; with &lt;code&gt;LOGON32_LOGON_NEW_CREDENTIALS&lt;/code&gt; to sidestep the INTERACTIVE-group restriction that constrained earlier post-RoguePotato attempts [@decoder-juicyng].&lt;/p&gt;
&lt;p&gt;The cross-pollination is worth marking. Forshaw&apos;s October 2021 Project Zero post on relaying Distributed COM authentication described the local-OXID trick as a research result [@forshaw-pz-2021]. Pierini and Cocomazzi picked it up eleven months later and shipped it as the default mode of JuicyPotatoNG [@decoder-juicyng]. SilverPotato (April 2024) and the Compass Security follow-on (September 2024) cite the same trick [@compass-three-headed]. Forshaw&apos;s blog has been the unofficial reference implementation for the lineage&apos;s offensive primitives for half its lifetime.&lt;/p&gt;
&lt;p&gt;JuicyPotatoNG also implements a Security Support Provider Interface (SSPI) hook on &lt;code&gt;AcceptSecurityContext&lt;/code&gt; to capture the SYSTEM token without requiring &lt;code&gt;RpcImpersonateClient&lt;/code&gt;. The effect is to make the tool work for both &lt;code&gt;SeImpersonate&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;SeAssignPrimaryToken&lt;/code&gt; holders [@decoder-juicyng]. The result is a clean, single-binary, no-external-infrastructure local-DCOM-activation exploit -- which is the version that worked between Phase 2 (June 14, 2022, enabled by default) and Phase 3 (March 14, 2023, enforced with no opt-out) of the CVE-2021-26414 rollout [@ms-kb5004442].&lt;/p&gt;
&lt;p&gt;The next variant would need to survive Phase 3.&lt;/p&gt;
&lt;h3&gt;6.7 GodPotato (BeichenDream, December 23, 2022)&lt;/h3&gt;
&lt;p&gt;Three months after JuicyPotatoNG, on December 23, 2022, the Chinese-speaking researcher BeichenDream published GodPotato to GitHub [@beichendream-god]. The README is bilingual English and Chinese, and it opens with a precise summary of where the variant fits in the lineage:&lt;/p&gt;

Based on the history of Potato privilege escalation for 6 years, from the beginning of RottenPotato to the end of JuicyPotatoNG, I discovered a new technology by researching DCOM, which enables privilege escalation in Windows 2012 - Windows 2022 ... There are some defects in rpcss when dealing with oxid, and rpcss is a service that must be opened by the system, so it can run on almost any Windows OS, I named it GodPotato. -- BeichenDream, GodPotato README, December 2022 [@beichendream-god]
&lt;p&gt;The mechanism manipulates the OXID-handling flow &lt;em&gt;inside&lt;/em&gt; RPCSS so the activated Distributed COM server&apos;s authentication callback returns to a tool-controlled endpoint &lt;em&gt;without&lt;/em&gt; requiring the OXID resolver to be redirected. Because the redirect itself is what the CVE-2021-26414 hardening rejects, GodPotato sidesteps the hardening entirely [@beichendream-god]. RPCSS is a mandatory Windows service -- it cannot be disabled without breaking the operating system -- so the technique works on every supported Windows release as of disclosure.&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;// On a target host where the calling account holds SeImpersonatePrivilege // (default for every IIS app-pool identity, MSSQL service account, BITS account, etc.) const command = &apos;GodPotato -cmd &quot;cmd /c whoami&quot;&apos;; console.log(&quot;Run:&quot;, command); console.log(&quot;Expected output: nt authority\\\\system&quot;); console.log(&quot;Working OS coverage: Windows 8 through Windows 11; Server 2012 through Server 2025&quot;); console.log(&quot;Underlying primitive: RPCSS OXID-handling defect, no external infra, single binary&quot;);&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;Microsoft has not assigned a CVE to the underlying RPCSS defect [@beichendream-god; @compass-three-headed].Apache 2.0 licensing matters here: red-team operators routinely recompile GodPotato from source to bypass binary-hash signatures, and the permissive license makes redistribution unproblematic [@beichendream-god]. The pattern is consistent with the servicing-criteria reading. GodPotato is in May 2026 the practitioner default on every in-support Windows release: single binary, no external infrastructure, no separate OXID resolver, Apache-2.0-licensed and freely re-buildable when EDR vendors signature the public binary [@beichendream-god].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; GodPotato survives every Microsoft mitigation because Microsoft has not declared the underlying primitive a security boundary. Three named hardening waves (the 2019-2020 OXID-resolver change, the three-phase CVE-2021-26414 rollout from June 2021 to March 2023, and the per-variant CVE patches in 2023 and 2024) leave GodPotato working on Server 2025 and Windows 11 24H2 as of this writing [@beichendream-god; @ms-kb5004442; @compass-three-headed].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.8 LocalPotato and CVE-2023-21746&lt;/h3&gt;
&lt;p&gt;Three weeks after GodPotato landed, Microsoft assigned the first-ever CVE in the local Potato lineage. The variant was LocalPotato, the CVE was CVE-2023-21746, and the patch shipped in the January 2023 Patch Tuesday [@nvd-cve-2023-21746; @msrc-cve-2023-21746]. The Decoder writeup, published February 13, 2023, walks through the timeline:&lt;/p&gt;

&quot;We reported our findings to the Microsoft Security Response Center (MSRC) on September 9, 2022, and it was resolved with the release of the January 2023 patch Tuesday and assigned the CVE number CVE-2023-21746.&quot; -- Andrea Pierini, &quot;LocalPotato&quot; writeup, February 2023 [@decoder-localpotato]
&lt;p&gt;LocalPotato is not a Distributed COM activation Potato. It attacks the local NTLM authentication protocol itself. During a local NTLM exchange, the Type 2 (Challenge) message carries a &quot;Reserved&quot; field that, in the local-NTLM case, encodes the upper bytes of the local server context handle the client should associate with. By racing two simultaneous local NTLM authentications -- one privileged client to attacker server, one attacker client to a real local server -- and swapping the Reserved fields in the two Type 2 messages, LSASS binds the privileged identity to the attacker&apos;s low-privilege context [@decoder-localpotato; @localpotato-com]. The result is an arbitrary file-read and file-write primitive that chains cleanly to SYSTEM.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Pierini and Cocomazzi had been pushing on the architectural carve-out for seven years before they got a CVE. The boundary that made the difference: LocalPotato attacks the local user-to-local-user NTLM authentication context, which &lt;em&gt;is&lt;/em&gt; on the servicing-criteria boundary list. The underlying &lt;code&gt;SeImpersonate&lt;/code&gt;-to-SYSTEM primitive is not. Microsoft will service the parts of the protocol that are inside the boundary; it will not service the parts that are outside [@decoder-localpotato; @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The LocalPotato writeup credits Elad Shamir for the original hint that started the research [@decoder-localpotato]. The dedicated companion site &lt;code&gt;localpotato.com&lt;/code&gt; carries the canonical title &quot;LocalPotato -- When swapping the context leads you to SYSTEM&quot; and links the CVE [@localpotato-com].&lt;/p&gt;
&lt;h3&gt;6.9 SilverPotato (Pierini + Cocomazzi, April 24, 2024)&lt;/h3&gt;
&lt;p&gt;A year later, on April 24, 2024, Pierini and Cocomazzi extended the cross-session Distributed COM activation primitive that RemotePotato0 had pioneered into a fully practical &lt;em&gt;domain&lt;/em&gt; attack. The blog post title is &quot;Hello, I&apos;m your domain admin and I want to authenticate against you&quot; [@decoder-silverpotato]. The Troopers 24 abstract refers to the technique by its other name, ADCSCoercePotato [@troopers24; @decoder-adcs-coerce-repo]; both names refer to the same primitive.&lt;/p&gt;
&lt;p&gt;The mechanism: members of the &lt;strong&gt;Distributed COM Users&lt;/strong&gt; or &lt;strong&gt;Performance Log Users&lt;/strong&gt; built-in groups can remotely trigger an NTLM authentication from any user currently logged on the target server -- including a Domain Administrator on a Domain Controller -- and relay it. The specific vehicle is the &lt;code&gt;sppui&lt;/code&gt; Distributed COM application (class identifier &lt;code&gt;F87B28F1-DA9A-4F35-8EC0-800EFCF26B83&lt;/code&gt;, &quot;SPPUIObjectInteractive Class&quot;, hosted in &lt;code&gt;slui.exe&lt;/code&gt;), which runs under the Interactive User identity [@decoder-silverpotato]. Pierini&apos;s wording in the post is unsparing:&lt;/p&gt;

&quot;Members of Distributed COM Users or Performance Log Users Groups can trigger from remote and relay the authentication of users connected on the target server, including Domain Controllers.&quot; -- Andrea Pierini, &quot;SilverPotato&quot; writeup, April 2024 [@decoder-silverpotato]
&lt;p&gt;The captured authentication is relayed via &lt;code&gt;ntlmrelayx&lt;/code&gt; to &lt;a href=&quot;https://paragmali.com/blog/certified-pre-owned-ad-cs-and-active-directorys-second-trust/&quot; rel=&quot;noopener&quot;&gt;AD CS Web Enrollment&lt;/a&gt; or LDAP, then chained with &lt;code&gt;ForgeCert&lt;/code&gt; and &lt;code&gt;Rubeus&lt;/code&gt; into a full Domain Admin Kerberos TGT [@decoder-silverpotato]. The Compass Security follow-on from September 2024 extends the chain further by modifying the KrbRelay project to make it remote and cross-session capable: &quot;I modified the KrbRelay project to make it remote and cross-session capable, because Andrea did not release his PoC code ... DCOM hardening only allows relay to HTTP or unprotected LDAP&quot; [@compass-three-headed]. Tianze Ding&apos;s Black Hat Asia 2024 talk on &quot;CertifiedDCOM&quot; landed in the same window [@blackhat-asia-2024]. Pierini&apos;s February 2024 post on the ADCS server side of the same surface foreshadowed the chain a few weeks earlier [@decoder-adcs-server].&lt;/p&gt;

flowchart LR
    A[Member of Distributed COM Users on target DC] --&amp;gt; B[Cross-session DCOM activation against sppui CLSID]
    B --&amp;gt; C[Logged-on Domain Admin session authenticates via NTLM]
    C --&amp;gt; D[ntlmrelayx forwards NTLM to AD CS Web Enrollment]
    D --&amp;gt; E[Computer-template certificate issued]
    E --&amp;gt; F[ForgeCert and Rubeus mint Domain Admin Kerberos TGT]
    F --&amp;gt; G[Domain compromise]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Troopers 24 abstract describes SilverPotato as &quot;still in review by MSRC&quot; as of June 2024 [@troopers24]. The Compass Security follow-on demonstrates a working end-to-end chain four months later [@compass-three-headed]. The default Distributed COM group memberships on Domain Controllers that grant the activation rights SilverPotato weaponises have not changed in any shipping Windows release as of May 2026. No CVE has been assigned [@decoder-silverpotato; @troopers24].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.10 FakePotato and CVE-2024-38100&lt;/h3&gt;
&lt;p&gt;Four months after SilverPotato, on August 2, 2024, Pierini published the most recent named variant. He called it FakePotato, and he was up front about the name:&lt;/p&gt;

&quot;You might be wondering why I called it the &apos;Fake&apos; Potato. Initially, I thought it could be exploited using the same techniques as the *Potato families, but it turned out to be different and much simpler in this case.&quot; -- Andrea Pierini, &quot;The Fake Potato&quot; writeup, August 2024 [@decoder-fakepotato]
&lt;p&gt;FakePotato abuses the &lt;strong&gt;ShellWindows&lt;/strong&gt; Distributed COM application (AppID &lt;code&gt;{9BA05972-F6A8-11CF-A442-00A0C90A8F39}&lt;/code&gt;), hosted in &lt;code&gt;explorer.exe&lt;/code&gt; and registered to run under the Interactive User identity. Cross-session activation via &lt;code&gt;BindToMoniker(&quot;session:N!new:&amp;lt;CLSID&amp;gt;&quot;)&lt;/code&gt; invokes &lt;code&gt;ShellExecute&lt;/code&gt; in the target session. There is no NTLM relay, no token impersonation, no &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; requirement -- any Authenticated User suffices because &lt;code&gt;explorer.exe&lt;/code&gt; in High Integrity Level (UAC-disabled administrator) granted the Authenticated Users group execute permission via the DCOM Access Security ACL [@decoder-fakepotato].&lt;/p&gt;
&lt;p&gt;{&lt;code&gt;$obj = [System.Runtime.InteropServices.Marshal]::BindToMoniker(&quot;session:2!new:9BA05972-F6A8-11CF-A442-00A0C90A8F39&quot;) $p = $obj.item(0).document.application $p.ShellExecute(&quot;c:\\temp\\reverse.bat&quot;, &quot;&quot;, &quot;c:\\windows&quot;, $null, 0)&lt;/code&gt;}&lt;/p&gt;
&lt;p&gt;Microsoft assigned CVE-2024-38100 and shipped the patch in the July 2024 Patch Tuesday cumulative updates on July 9, 2024 (KB5040434 for Windows 10 1607 / Windows Server 2016; equivalent KBs for Windows 11, Server 2019, Server 2022, and Server 2025) -- four weeks before the public disclosure [@decoder-fakepotato; @nvd-cve-2024-38100; @msrc-cve-2024-38100]. The patch corrects the &lt;code&gt;explorer.exe&lt;/code&gt; ACL in High Integrity Level contexts so the Authenticated Users permission required for activation is no longer granted. The underlying cross-session Distributed COM activation primitive that SilverPotato and FakePotato share is untouched [@decoder-silverpotato; @decoder-fakepotato].&lt;/p&gt;
&lt;p&gt;FakePotato is not, in the relay sense, a Potato at all. It is a misconfiguration of the &lt;code&gt;ShellWindows&lt;/code&gt; Distributed COM application&apos;s permissions in High Integrity Level contexts [@decoder-fakepotato]. Pierini&apos;s &quot;Fake&quot; framing acknowledges the divergence from the NTLM-reflection pattern that defined the family from RottenPotato through GodPotato. The naming choice is itself a small piece of taxonomy: not every member of the family is a token-relay exploit, even if every member exploits the same architectural carve-out.&lt;/p&gt;
&lt;p&gt;After nearly a decade of patching specific vehicles and refusing to declare the underlying primitive a boundary, Microsoft&apos;s pattern is hard to miss.&lt;/p&gt;
&lt;h2&gt;7. Eleven Variants at a Glance&lt;/h2&gt;
&lt;p&gt;Nine years of named-variant disclosures, eleven named variants, one architectural argument. The table below is sourced cell by cell from the preceding sections.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Authors&lt;/th&gt;
&lt;th&gt;Coercion vehicle&lt;/th&gt;
&lt;th&gt;Mitigation it bypassed&lt;/th&gt;
&lt;th&gt;Microsoft response&lt;/th&gt;
&lt;th&gt;Still works in 2026?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;HotPotato [@foxglove-hotpotato]&lt;/td&gt;
&lt;td&gt;Jan 16, 2016&lt;/td&gt;
&lt;td&gt;Stephen Breen&lt;/td&gt;
&lt;td&gt;NBNS spoof + WPAD + HTTP-to-SMB relay&lt;/td&gt;
&lt;td&gt;MS08-068 same-protocol-only fix&lt;/td&gt;
&lt;td&gt;None named; EPA/SMB hardening eventually closed the vehicle&lt;/td&gt;
&lt;td&gt;Only on pre-1607 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RottenPotato [@foxglove-rottenpotato]&lt;/td&gt;
&lt;td&gt;Sep 23, 2016&lt;/td&gt;
&lt;td&gt;Stephen Breen + Chris Mallz&lt;/td&gt;
&lt;td&gt;DCOM activation via BITS CLSID on 127.0.0.1:6666&lt;/td&gt;
&lt;td&gt;(none yet)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Only pre-1809 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RottenPotatoNG [@breenmachine-rottenng]&lt;/td&gt;
&lt;td&gt;Dec 29, 2017&lt;/td&gt;
&lt;td&gt;breenmachine&lt;/td&gt;
&lt;td&gt;Same as RottenPotato (C++ port; no Metasploit)&lt;/td&gt;
&lt;td&gt;(none yet)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Only pre-1809 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JuicyPotato [@ohpe-juicy]&lt;/td&gt;
&lt;td&gt;Jul 27, 2018&lt;/td&gt;
&lt;td&gt;Andrea Pierini + Giuseppe Trotta&lt;/td&gt;
&lt;td&gt;Generalised DCOM activation; CLSID matrix&lt;/td&gt;
&lt;td&gt;(none yet)&lt;/td&gt;
&lt;td&gt;OXID-resolver hard-coding in Win10 1809 / Server 2019 [@forshaw-pz-2021]&lt;/td&gt;
&lt;td&gt;Only pre-1809 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RoguePotato [@antonio-rogue]&lt;/td&gt;
&lt;td&gt;May 10, 2020&lt;/td&gt;
&lt;td&gt;Antonio Cocomazzi + Andrea Pierini&lt;/td&gt;
&lt;td&gt;DCOM activation through remote TCP-135 forwarder&lt;/td&gt;
&lt;td&gt;2019-2020 OXID-resolver hardening&lt;/td&gt;
&lt;td&gt;None (no CVE)&lt;/td&gt;
&lt;td&gt;Only pre-Phase-3 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PrintSpoofer [@itm4n-printspoofer]&lt;/td&gt;
&lt;td&gt;Early May 2020&lt;/td&gt;
&lt;td&gt;Clément Labro&lt;/td&gt;
&lt;td&gt;Print Spooler RPC &lt;code&gt;RpcRemoteFindFirstPrinterChangeNotificationEx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All DCOM-side hardening (irrelevant)&lt;/td&gt;
&lt;td&gt;None (no CVE)&lt;/td&gt;
&lt;td&gt;Yes, when Spooler is running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RemotePotato0 [@sentinellabs-relaying]&lt;/td&gt;
&lt;td&gt;Apr 2021&lt;/td&gt;
&lt;td&gt;Antonio Cocomazzi + Andrea Pierini&lt;/td&gt;
&lt;td&gt;Cross-session DCOM/RPC NTLM relay&lt;/td&gt;
&lt;td&gt;(defines a new threat surface)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&quot;Won&apos;t Fix&quot;&lt;/strong&gt;; partial Oct 2022 RPC-to-LDAP mitigation&lt;/td&gt;
&lt;td&gt;Partially (primitive intact)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JuicyPotatoNG [@antonio-juicyng; @decoder-juicyng]&lt;/td&gt;
&lt;td&gt;Sep 21, 2022&lt;/td&gt;
&lt;td&gt;Andrea Pierini + Antonio Cocomazzi&lt;/td&gt;
&lt;td&gt;Local-OXID trick + LogonUser NewCredentials&lt;/td&gt;
&lt;td&gt;CVE-2021-26414 Phase 1 and Phase 2&lt;/td&gt;
&lt;td&gt;None (no CVE)&lt;/td&gt;
&lt;td&gt;Only pre-Phase-3 builds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GodPotato [@beichendream-god]&lt;/td&gt;
&lt;td&gt;Dec 23, 2022&lt;/td&gt;
&lt;td&gt;BeichenDream&lt;/td&gt;
&lt;td&gt;RPCSS OXID-handling defect (no resolver redirect)&lt;/td&gt;
&lt;td&gt;All three CVE-2021-26414 phases&lt;/td&gt;
&lt;td&gt;None (no CVE)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes -- the 2026 default&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LocalPotato / CVE-2023-21746 [@decoder-localpotato; @nvd-cve-2023-21746]&lt;/td&gt;
&lt;td&gt;Patched Jan 10, 2023&lt;/td&gt;
&lt;td&gt;Andrea Pierini + Antonio Cocomazzi&lt;/td&gt;
&lt;td&gt;NTLM Type-2 &quot;Reserved&quot; field context swap&lt;/td&gt;
&lt;td&gt;(orthogonal -- attacks LSASS)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CVE-2023-21746&lt;/strong&gt; (first local-Potato CVE)&lt;/td&gt;
&lt;td&gt;No -- patched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SilverPotato / ADCSCoercePotato [@decoder-silverpotato; @troopers24]&lt;/td&gt;
&lt;td&gt;Apr 24, 2024&lt;/td&gt;
&lt;td&gt;Andrea Pierini + Antonio Cocomazzi&lt;/td&gt;
&lt;td&gt;Cross-session DCOM against &lt;code&gt;sppui&lt;/code&gt; AppID&lt;/td&gt;
&lt;td&gt;Post-RemotePotato0 partial mitigations&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Still in review by MSRC as of mid-2026&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes -- unpatched&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FakePotato / CVE-2024-38100 [@decoder-fakepotato; @nvd-cve-2024-38100]&lt;/td&gt;
&lt;td&gt;Disclosed Aug 2, 2024&lt;/td&gt;
&lt;td&gt;Andrea Pierini&lt;/td&gt;
&lt;td&gt;Cross-session DCOM against &lt;code&gt;ShellWindows&lt;/code&gt; AppID (ACL bug)&lt;/td&gt;
&lt;td&gt;(orthogonal)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CVE-2024-38100&lt;/strong&gt; in the July 2024 Patch Tuesday (KB5040434 for 1607/Server 2016; per-build KBs elsewhere)&lt;/td&gt;
&lt;td&gt;No -- patched&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Two CVEs in nine years of named-variant disclosures. One &quot;Won&apos;t Fix&quot; decision on a working Domain Admin escalation. Zero declarations of &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or Distributed COM activation as a security boundary. The pattern is consistent across every column [@troopers24; @msrc-servicing-criteria].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Two CVEs in a decade, against a family with eleven named variants. The first CVE was for a piece of the &lt;em&gt;local NTLM protocol&lt;/em&gt; that is on the servicing-criteria list, not for the underlying &lt;code&gt;SeImpersonate&lt;/code&gt;-to-SYSTEM primitive. The second was for a &lt;em&gt;Distributed COM access-control list misconfiguration&lt;/em&gt;, not for cross-session activation as a class. Microsoft will assign CVEs to specific vehicles when forced. It will not declare the architectural primitive a security boundary [@nvd-cve-2023-21746; @nvd-cve-2024-38100; @troopers24].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;8. The 2026 Decision Surface&lt;/h2&gt;
&lt;p&gt;In May 2026, an operator with &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; on a default Windows 11 box has a small menu of working tools, plus three legacy variants that remain useful on unpatched fleets. The current toolkit:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Coercion vehicle&lt;/th&gt;
&lt;th&gt;OS coverage&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GodPotato&lt;/strong&gt; [@beichendream-god]&lt;/td&gt;
&lt;td&gt;RPCSS OXID defect&lt;/td&gt;
&lt;td&gt;Win 8 to Win 11; Server 2012 to Server 2025&lt;/td&gt;
&lt;td&gt;Default first try on any in-support Windows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SweetPotato&lt;/strong&gt; [@ccob-sweet]&lt;/td&gt;
&lt;td&gt;Selectable: PrintSpoofer (default), DCOM, EfsRpc, WinRM&lt;/td&gt;
&lt;td&gt;Win 7+ depending on selected mode&lt;/td&gt;
&lt;td&gt;When GodPotato&apos;s binary signature is blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SharpEfsPotato&lt;/strong&gt; [@bugch3ck-efs]&lt;/td&gt;
&lt;td&gt;EFS RPC (&lt;code&gt;EfsRpcOpenFileRaw&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Server 2019+, Win 10/11 with EFS RPC enabled&lt;/td&gt;
&lt;td&gt;DCOM locked down &lt;em&gt;and&lt;/em&gt; Spooler disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PrintSpoofer&lt;/strong&gt; [@itm4n-printspoofer]&lt;/td&gt;
&lt;td&gt;Print Spooler RPC&lt;/td&gt;
&lt;td&gt;Any host with Spooler running&lt;/td&gt;
&lt;td&gt;The lowest-noise option on Spooler-enabled hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JuicyPotatoNG&lt;/strong&gt; [@antonio-juicyng]&lt;/td&gt;
&lt;td&gt;Local-OXID + legacy CLSID&lt;/td&gt;
&lt;td&gt;Pre-Phase-3 DCOM hardening only&lt;/td&gt;
&lt;td&gt;Corporate fleets with delayed CVE-2021-26414 rollout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RoguePotato&lt;/strong&gt; [@antonio-rogue]&lt;/td&gt;
&lt;td&gt;Remote TCP-135 forwarder&lt;/td&gt;
&lt;td&gt;Pre-Phase-3 DCOM hardening&lt;/td&gt;
&lt;td&gt;Pre-2022 hardened-OXID-only systems with attacker remote infra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SilverPotato&lt;/strong&gt; [@decoder-silverpotato]&lt;/td&gt;
&lt;td&gt;Cross-session DCOM against DC&lt;/td&gt;
&lt;td&gt;Default DCs with &lt;code&gt;Distributed COM Users&lt;/code&gt; or &lt;code&gt;Performance Log Users&lt;/code&gt; membership&lt;/td&gt;
&lt;td&gt;Domain-tier escalation -- the only currently-unpatched cross-session variant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Plus three legacy variants worth knowing about: JuicyPotato on pre-1809 builds, RottenPotato on Server 2008 R2 / Windows 7 ESU-eligible builds, and HotPotato as the canonical naming origin and the source of the family&apos;s &quot;documented Win32 calls&quot; framing [@ohpe-juicy; @foxglove-rotten-repo; @foxglove-hotpotato]. Embedded Windows builds (Windows 10 IoT LTSC 2019, some industrial controllers, ATM images) frequently fall behind the OXID-resolver mitigation and remain JuicyPotato-vulnerable through 2026.&lt;/p&gt;

SharpEfsPotato&apos;s canonical repository is `github.com/bugch3ck/SharpEfsPotato` [@bugch3ck-efs]. A widely shared `ly4k/SharpEfsPotato` fork exists and is referenced in some red-team writeups, but the upstream is the `bugch3ck` repo per the README&apos;s own credit chain (&quot;Built from SweetPotato by @\_EthicalChaos\_ and SharpSystemTriggers/SharpEfsTrigger by @cube0x0&quot;) [@bugch3ck-efs]. Operators citing the `ly4k` URL are pointing at a fork.
&lt;p&gt;Every one of these tools has a Microsoft mitigation in its history. None of those mitigations closed the family. The next section asks what mitigation could.&lt;/p&gt;
&lt;h2&gt;9. What Would It Take To Close the Family?&lt;/h2&gt;
&lt;p&gt;A counterfactual sharpens the question. Suppose Microsoft decided in 2026 that the family must end. Three closure options exist, and each carries a compatibility cost.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Closure option&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Compatibility cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1. Declare &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; a security boundary&lt;/td&gt;
&lt;td&gt;Revoke the privilege from default service accounts (IIS app pools, SQL Server, BITS, Task Scheduler, the Spooler)&lt;/td&gt;
&lt;td&gt;Operationally prohibitive: thousands of third-party services depend on the default grant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Declare Distributed COM activation a security boundary&lt;/td&gt;
&lt;td&gt;Validate the activator&apos;s identity against the activated CLSID&apos;s registered identity on every activation&lt;/td&gt;
&lt;td&gt;Breaks 25 years of legacy Distributed COM applications written between 1996 and 2021 [@ms-dcom-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Deprecate &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; as a Win32 primitive&lt;/td&gt;
&lt;td&gt;Remove the call from &lt;code&gt;namedpipeapi.h&lt;/code&gt; or gate it behind a Trustlet validation&lt;/td&gt;
&lt;td&gt;Breaks parts of CSRSS, the console subsystem, and LSASS itself; no deprecation notice exists in the API reference as of mid-2026 [@ms-impersonate-api]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The CVE-2021-26414 hardening creeps toward option 2 for &lt;em&gt;remote&lt;/em&gt; Distributed COM but explicitly does not for &lt;em&gt;local&lt;/em&gt; Distributed COM [@ms-kb5004442]. The &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;Adminless direction&lt;/a&gt; in Windows 11 24H2 -- Microsoft&apos;s &quot;Administrator protection&quot; platform feature, currently a preview shipped first via Windows Insider builds and not yet generally available [@ms-administrator-protection] -- introduces a per-application admin-elevation gate, but operates &lt;em&gt;above&lt;/em&gt; the SYSTEM-impersonation primitive, not below it. &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; isolates LSASS secrets in a &lt;a href=&quot;https://paragmali.com/blog/vbs-trustlets-what-actually-runs-in-the-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Virtualization-Based Security Trustlet&lt;/a&gt; -- which protects NTLM hashes from extraction but does not gate &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; or &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; [@ms-credential-guard]. &lt;a href=&quot;https://paragmali.com/blog/living-off-the-land-on-windows-the-lolbin-catalog-and-the-st/&quot; rel=&quot;noopener&quot;&gt;Smart App Control&lt;/a&gt; restricts arbitrary binary execution but does not block in-process exploitation by a SYSTEM-running service [@ms-smart-app-control].&lt;/p&gt;
&lt;p&gt;The lower bound on attack cost is therefore O(1) per invocation, and it stays O(1) as long as the servicing-criteria carve-out holds. No combination of currently-shipping mitigations moves it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Potato family is a fixed point of the current Windows architecture. Every closure option carries a compatibility cost that no currently-announced Microsoft release accepts. Until the MSRC Windows Security Servicing Criteria changes the position on &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; and Distributed COM activation, the family&apos;s lower attack cost is O(1) and no servicing patch can move it [@msrc-servicing-criteria; @troopers24].&lt;/p&gt;
&lt;/blockquote&gt;

The claim is empirical, not formal. A &quot;fixed point&quot; in the algorithmic sense is a value where a function returns its own input. For the Potato family the analogue is: every Microsoft mitigation that does not change the servicing-criteria document returns a family that is still alive. The fixed-point status is consistent with eleven variants over nine years of named-variant disclosures (HotPotato January 2016 -&amp;gt; FakePotato August 2024) against three named hardening waves. It would be invalidated by a major-version Windows release that explicitly revoked the default `SeImpersonatePrivilege` grant on service accounts. No such release is on the public roadmap as of May 2026 [@msrc-servicing-criteria].
&lt;h2&gt;10. Open Problems&lt;/h2&gt;
&lt;p&gt;Five questions sit at the research frontier in 2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The next coercion vehicle.&lt;/strong&gt; Each Potato variant is one SYSTEM-context service with a callback-style API. As the family has matured, researchers have mapped a growing surface of candidates: EFS RPC (which SharpEfsPotato already weaponises [@bugch3ck-efs]), Print Spooler async RPC (MS-PAR), Windows Search remote protocol (MS-WSP), and Microsoft Distributed Transaction Coordinator RPC. The community-empirical conjecture, repeated across Troopers 24 [@troopers24] and the Compass Security retrospective [@compass-three-headed], is that any SYSTEM-context Windows service with a callback-style API becomes a Potato vehicle within roughly eighteen months of operational need.&lt;/p&gt;
&lt;p&gt;The &quot;eighteen-month vehicle cadence&quot; is an informal community claim, not a measured statistic. It originates in the Troopers 24 retrospective by Pierini and Cocomazzi [@troopers24] and is reinforced by the Compass Security follow-on documenting how the SilverPotato chain was productised within months of Pierini&apos;s February 2024 ADCS-server post [@decoder-adcs-server; @compass-three-headed]. The number should be read as a rule of thumb, not a benchmark.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux and Windows Subsystem for Linux extension.&lt;/strong&gt; No Linux analogue of &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; exists. There are partial precedents in the impacket cross-protocol relay work, but no Potato-class primitive that produces a SYSTEM token on a Linux host. Open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Will defence-in-depth combine to close the family without ever declaring a new boundary?&lt;/strong&gt; Microsoft has shipped Credential Guard [@ms-credential-guard], &lt;a href=&quot;https://paragmali.com/blog/wdac--hvci-code-integrity-at-every-layer-in-windows/&quot; rel=&quot;noopener&quot;&gt;Hypervisor-Protected Code Integrity&lt;/a&gt; [@ms-hvci], Smart App Control [@ms-smart-app-control], and the experimental Administrator-protection direction in Windows 11 24H2 [@ms-administrator-protection]. Each changes the runtime trust model in some way. No combination of currently-shipping technologies closes the family as of May 2026 -- the Potato primitives live below the layer those technologies operate on [@troopers24; @compass-three-headed].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A defensive detection primitive that catches every variant.&lt;/strong&gt; The unifying invariant is &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; being called from a thread that holds &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; against a named pipe that has just received a SYSTEM-context authentication originating from a service the calling process did not initiate. Per-variant detection rules exist for each named tool (GodPotato, PrintSpoofer, JuicyPotato). A generalising rule has not been published [@ms-impersonate-api]. The informal community position is that the family is &lt;em&gt;non-detectable as a class&lt;/em&gt; because the primitive is in the legitimate hot path of nearly every Windows service.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MSRC servicing-criteria position on cross-session Distributed COM activation.&lt;/strong&gt; LocalPotato (CVE-2023-21746) received a CVE for a piece of the local NTLM protocol [@nvd-cve-2023-21746]. FakePotato (CVE-2024-38100) received a CVE for an access-control list misconfiguration on the &lt;code&gt;ShellWindows&lt;/code&gt; AppID [@nvd-cve-2024-38100]. SilverPotato is still unpatched [@decoder-silverpotato; @troopers24]. The boundary that distinguishes these three is unclear: why was the &lt;code&gt;ShellWindows&lt;/code&gt; cross-session activation patched while the &lt;code&gt;sppui&lt;/code&gt; cross-session activation has not been? The answer determines the next decade of the family. The defensible reading is that Microsoft will service variants that look like permission misconfigurations on a single AppID but not the underlying cross-session Distributed COM activation primitive itself.&lt;/p&gt;
&lt;h2&gt;11. How to Use a Potato in 2026&lt;/h2&gt;
&lt;p&gt;The practitioner question is operational. Given a foothold and a goal, which Potato variant does the job? The decision tree below walks through the path researchers settle into on red-team engagements.&lt;/p&gt;

flowchart TD
    A[Target OS in support?] --&amp;gt;|&quot;No&quot;| Z1[JuicyPotato on pre-2020 builds, or RoguePotato on 2020-2022 builds]
    A --&amp;gt;|&quot;Yes&quot;| B[Operator privilege?]
    B --&amp;gt;|&quot;SeImpersonate or SeAssignPrimaryToken&quot;| C[Spooler running?]
    B --&amp;gt;|&quot;Standard user, cross-session victim present&quot;| Z2[FakePotato technique illustrative -- patched in KB5040434]
    B --&amp;gt;|&quot;DCOM-group member on a DC&quot;| Z3[SilverPotato with ntlmrelayx to AD CS]
    C --&amp;gt;|&quot;Yes&quot;| D[SweetPotato -e PrintSpoofer default]
    C --&amp;gt;|&quot;No&quot;| E[EFS RPC reachable?]
    E --&amp;gt;|&quot;Yes&quot;| F[SharpEfsPotato]
    E --&amp;gt;|&quot;No&quot;| G[GodPotato as fallback]
&lt;p&gt;The first-try heuristic is short. &lt;strong&gt;GodPotato first&lt;/strong&gt;, because it is the single binary that works on every in-support Windows release [@beichendream-god]. If the GodPotato binary signature is blocked by Endpoint Detection and Response, &lt;strong&gt;SweetPotato with &lt;code&gt;-e PrintSpoofer&lt;/code&gt;&lt;/strong&gt; (or &lt;code&gt;-e EfsRpc&lt;/code&gt; on a Domain Controller where Spooler is off) [@ccob-sweet]. If both are blocked, &lt;strong&gt;SharpEfsPotato&lt;/strong&gt; as the lower-public-exposure third choice [@bugch3ck-efs]. For pre-2023 unpatched fleets, &lt;strong&gt;JuicyPotatoNG&lt;/strong&gt; during the Phase-2 hardening window and &lt;strong&gt;JuicyPotato&lt;/strong&gt; on pre-1809 builds [@antonio-juicyng; @ohpe-juicy]. For domain escalation against a DC, &lt;strong&gt;SilverPotato&lt;/strong&gt; with the Compass Security KrbRelay modifications [@decoder-silverpotato; @compass-three-headed].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; GodPotato. If signature-blocked, SweetPotato with &lt;code&gt;-e PrintSpoofer&lt;/code&gt;. If both blocked, SharpEfsPotato. The rest of the family is for situations the first three do not cover (legacy fleets, DC escalation, technique illustration of patched variants) [@beichendream-god; @ccob-sweet; @bugch3ck-efs].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Several implementation pitfalls catch new operators. The named-pipe path that GodPotato uses (&lt;code&gt;\pipe\&amp;lt;token&amp;gt;\pipe\epmapper&lt;/code&gt;) is widely signatured by EDR vendors -- see the detection-engineering Spoiler below for the specific Sigma and Elastic rules [@sigma-potato-hktl; @elastic-rogue-pipe] -- and recompiling from source with a different pipe template is the standard countermeasure. A token &lt;em&gt;holding&lt;/em&gt; &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; does not necessarily &lt;em&gt;enable&lt;/em&gt; it -- explicit &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt; with &lt;code&gt;SE_PRIVILEGE_ENABLED&lt;/code&gt; is required, and custom adaptations frequently miss the step [@ms-adjusttokenprivileges]. SweetPotato&apos;s default &lt;code&gt;-e PrintSpoofer&lt;/code&gt; mode fails silently on a Domain Controller where Spooler is disabled per the PrintNightmare aftermath; the correct DC default is GodPotato or SharpEfsPotato. RoguePotato&apos;s outbound TCP 135 to attacker infrastructure is blocked by default in most enterprise networks. FakePotato and SilverPotato both require the victim identity to be actively logged in, since both depend on a live cross-session activation surface [@itm4n-printspoofer; @antonio-rogue; @decoder-silverpotato; @decoder-fakepotato].&lt;/p&gt;

If you defend Windows rather than attack it, the detection target is the conjunction of (a) named-pipe creation by an IIS or SQL or service account, (b) a SYSTEM-context process connecting to that pipe shortly after, and (c) `CreateProcessWithToken` from the original service-account process. None of the three events alone is anomalous. The conjunction is. Sysmon Event ID 1 (Process Create) paired with Event IDs 17 and 18 (PipeEvent: Pipe Created and Pipe Connected) plus ETW providers `Microsoft-Windows-COM` and `Microsoft-Windows-RPC` cover the activation-plus-pipe half [@ms-sysmon]; Sysmon Event ID 10 (ProcessAccess) on `lsass.exe` from the originating service account is the third pillar that surfaces the impersonation handle acquisition [@ms-sysmon]. Per-variant signatures are published as Sigma rules for the public LocalPotato, CoercedPotato, JuicyPotato, RottenPotato, and EfsPotato binaries [@sigma-potato-hktl; @sigma-localpotato], and Elastic&apos;s `privilege_escalation_via_rogue_named_pipe` rule fires on the PrintSpoofer / EfsPotato pipe-path pattern that GodPotato shares [@elastic-rogue-pipe]. A class-generalising rule that fires on the *primitive* (rather than per-binary) has not been published.
&lt;p&gt;Library and framework support follows the same shape as any post-exploitation primitive (the picture here is community-empirical, drawn from public BOF and module repositories rather than vendor reference architectures). Cobalt Strike Beacon Object Files wrapping GodPotato, PrintSpoofer, and SweetPotato are widely shared in the red-team community -- &lt;code&gt;incursi0n/GodPotatoBOF&lt;/code&gt; is one publicly published example that integrates with &lt;code&gt;BeaconUseToken()&lt;/code&gt; for in-Beacon SYSTEM-token application [@godpotato-bof] -- and the same wrappers load into Sliver. PowerShell wrappers around PrintSpoofer and JuicyPotato are integrated into Empire and Starkiller. The Metasploit &lt;code&gt;incognito&lt;/code&gt; post-exploitation module handles token impersonation as a primitive but does not wrap GodPotato directly [@msf-incognito]. The &lt;code&gt;impacket&lt;/code&gt; toolkit&apos;s &lt;code&gt;ntlmrelayx&lt;/code&gt; is the canonical relay engine for the tail of SilverPotato [@fortra-impacket], and OleViewDotNet -- Forshaw&apos;s tool -- is the discovery oracle that surfaced the &lt;code&gt;sppui&lt;/code&gt; and &lt;code&gt;ShellWindows&lt;/code&gt; AppIDs in the first place [@tyranid-oleview; @decoder-silverpotato; @decoder-fakepotato].&lt;/p&gt;
&lt;h2&gt;12. Frequently Asked Questions&lt;/h2&gt;


The name `Potato` originates with Stephen Breen&apos;s `foxglovesec/Potato` repository, created February 9, 2016, three weeks after the January 16, 2016 HotPotato blog post [@foxglove-potato-repo; @foxglove-hotpotato]. HotPotato is in the family because it pivots through the same `SeImpersonatePrivilege` plus named-pipe-impersonation primitive that every later variant exploits -- the vehicle is different (NetBIOS spoofing + WPAD + HTTP-to-SMB rather than Distributed COM) but the architectural carve-out is the same. See §4 for the bracketing-variant framing.


Because every Internet Information Services application-pool identity is granted the privilege by Windows default [@itm4n-printspoofer]. The grant exists for legitimate request-scoped impersonation -- it is the mechanism IIS uses to &quot;act as&quot; a calling user during authenticated request handling. The same default grant is the entire vulnerability surface for the Potato family. The Microsoft Security Servicing Criteria document treats the resulting `SeImpersonate`-to-SYSTEM transition as a safety boundary rather than a security boundary [@msrc-servicing-criteria; @troopers24].


No. CVE-2021-26414 hardening raises the *authentication* bar for Distributed COM clients to `RPC_C_AUTHN_LEVEL_PKT_INTEGRITY` and was fully enforced on March 14, 2023 in Phase 3 of the rollout [@ms-kb5004442]. It does not declare Distributed COM activation a security boundary. The proof is that GodPotato, which exploits an RPCSS OXID-handling defect rather than the activation authentication level, survives all three phases of the rollout and remains the practitioner default in 2026 [@beichendream-god].


Open question, with a defensible reading. LocalPotato attacks the local-user-to-local-user NTLM authentication context handle, which *is* on the servicing-criteria boundary list [@decoder-localpotato; @msrc-servicing-criteria]. RemotePotato0 attacks the `SeImpersonate`-to-SYSTEM transition via cross-session Distributed COM activation, which is *not* on the list and was therefore deemed an extension of the existing carve-out [@sentinellabs-relaying; @troopers24]. The two boundaries (local NTLM authentication context vs cross-session Distributed COM activation) are not equivalent in Microsoft&apos;s published servicing position.


Yes, on every patched Windows 11 / Server 2025 build as of this writing [@beichendream-god]. The RPCSS OXID-handling defect that GodPotato weaponises survives all three CVE-2021-26414 hardening phases [@ms-kb5004442; @compass-three-headed]. Microsoft has not assigned a CVE to the underlying defect, consistent with the servicing-criteria reading. Operationally, the only thing that changes between releases is the binary signature -- EDR vendors signature the public Apache-2.0 binary by hash, and operators recompile from source with cosmetic changes to evade [@beichendream-god].


Does not exist as of May 2026. If a 2025-2026 variant appears under an unfamiliar name -- French or otherwise -- verify against the canonical sources before citing: `decoder.cloud` for the Pierini and Cocomazzi line, `github.com/antonioCoco/*` for the Cocomazzi-authored repositories, `github.com/BeichenDream/*` for the BeichenDream line, and `itm4n.github.io` for the PrintSpoofer / SweetPotato line [@decoder-silverpotato; @antonio-rogue; @beichendream-god; @itm4n-printspoofer]. The Troopers 24 retrospective is the community-canonical lineage list as of the most recent consolidated talk [@troopers24].


Informally, no. The primitive `ImpersonateNamedPipeClient` is in the legitimate hot path of nearly every Windows service [@ms-impersonate-api]. Per-variant signatures exist for the public binaries (GodPotato, PrintSpoofer, JuicyPotato), and ETW providers `Microsoft-Windows-COM` and `Microsoft-Windows-RPC` surface the activation-and-RPC events that the Distributed COM variants generate. A class-generalising detection rule has not been published as of May 2026, and the false-positive rate on legitimate Windows services is high for any rule that fires on `ImpersonateNamedPipeClient` alone [@troopers24].

&lt;h2&gt;13. The Architectural Decision&lt;/h2&gt;
&lt;p&gt;Return to the opening scene. The same Internet Information Services web shell, the same &lt;code&gt;GodPotato.exe&lt;/code&gt;, the same ten-second SYSTEM shell. The reader now knows this is not a zero-day. It has been a single-binary operation for the better part of a decade. Every step is documented Win32 behaviour. And every step is permitted by Microsoft&apos;s published servicing position [@beichendream-god; @msrc-servicing-criteria; @troopers24].&lt;/p&gt;
&lt;p&gt;Nine years of named-variant disclosures. Eleven named variants. Three Microsoft hardening waves. Two CVEs -- LocalPotato in January 2023, FakePotato in July 2024 [@nvd-cve-2023-21746; @nvd-cve-2024-38100]. One &quot;Won&apos;t Fix&quot; decision on a working Domain Admin escalation in April 2021 [@sentinellabs-relaying]. Zero declarations of &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or Distributed COM activation as a security boundary [@troopers24; @msrc-servicing-criteria]. The MSRC Windows Security Servicing Criteria document, the one whose boundary definition fetches in static HTML and whose enumeration table is JavaScript-rendered, is the through-line [@msrc-servicing-criteria]. Pierini and Cocomazzi say it bluntly in the Troopers 24 abstract:&lt;/p&gt;

Microsoft does not consider WSH a security boundary but rather a safety boundary; for this reason, many Potato exploits work (and have been working) on fully updated Windows systems. -- Pierini and Cocomazzi, Troopers 24 abstract [@troopers24]
&lt;p&gt;Microsoft will never fix the Potato class because fixing it requires declaring Distributed COM activation a security boundary, and they have spent twenty-five years insisting it is not. What would change that? A major-version Windows release that explicitly revokes the default &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; grant from service accounts -- a compatibility-breaking change that breaks IIS, SQL Server, BITS, the Spooler, and most third-party services that depend on the legitimate impersonation contract. No such release is on the public roadmap as of May 2026 [@msrc-servicing-criteria; @ms-kb5004442; @beichendream-god].&lt;/p&gt;
&lt;p&gt;Until then, the family is alive, and the ten-second SYSTEM shell is the default outcome of any IIS or service-account foothold on a fully-patched Windows machine. That is not the unintended consequence of an unpatched bug. That is the intended consequence of a published architectural decision.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Potato family is not a stack of bugs Microsoft is slowly working through. It is the long-running consequence of a published architectural decision: that the &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;-to-SYSTEM transition is a safety boundary, not a security boundary. Eleven variants over nine years of named-variant disclosures (HotPotato January 2016 -&amp;gt; FakePotato August 2024) are the empirical proof of how stable that decision is [@troopers24; @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The following retention block summarises the six key terms above. Citations for each definition live in §2.1, §2.2, §6.5, §6.1, §3, and §2 of the body respectively (the StudyGuide MDX wrapper does not render &lt;code&gt;@ref-id&lt;/code&gt; links inline).&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;potato-family-decade-ntlm-reflection&quot; keyTerms={[
  { term: &quot;SeImpersonatePrivilege&quot;, definition: &quot;Windows user-rights assignment that permits a thread to substitute another user&apos;s security context for its own; granted by default to LOCAL SERVICE, NETWORK SERVICE, and most service accounts (see §2.1 for full citation).&quot; },
  { term: &quot;ImpersonateNamedPipeClient&quot;, definition: &quot;Win32 API that lets a named-pipe server adopt the security context of whoever just connected to the pipe; documented today as supported since Windows XP for clients and Windows Server 2003 for servers (see §2.2 for full citation).&quot; },
  { term: &quot;OXID resolver&quot;, definition: &quot;RPCSS subsystem that resolves Object Exporter Identifiers during DCOM activation; hard-coded to 127.0.0.1:135 in Windows 10 1809 / Server 2019 to mitigate JuicyPotato (see §6.1).&quot; },
  { term: &quot;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&quot;, definition: &quot;RPC authentication-level constant requiring per-packet integrity signing; the minimum CVE-2021-26414 enforces on DCOM activation in Phase 3 (March 14, 2023) (see §6.5).&quot; },
  { term: &quot;NTLM reflection&quot;, definition: &quot;Special case of NTLM relay where the authentication is forwarded back to the originating machine, typically across protocols (HTTP to SMB, DCOM to local RPC) (see §3).&quot; },
  { term: &quot;Security boundary vs safety boundary&quot;, definition: &quot;MSRC servicing-criteria distinction: security boundaries get CVEs and security updates; safety boundaries are patched when convenient but carry no service-level guarantee (see §2).&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>privilege-escalation</category><category>ntlm-relay</category><category>dcom</category><category>msrc</category><category>red-team</category><category>post-exploitation</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Every UAC Prompt Is an ALPC Handshake: A Field Guide to Windows&apos; Most-Attacked Local IPC Fabric</title><link>https://paragmali.com/blog/every-uac-prompt-is-an-alpc-handshake-a-field-guide-to-windo/</link><guid isPermaLink="true">https://paragmali.com/blog/every-uac-prompt-is-an-alpc-handshake-a-field-guide-to-windo/</guid><description>ALPC and LRPC are the asynchronous local-IPC fabric under every Windows service. This is the story of the kernel object Microsoft does not document and the attack surface almost every Patch Tuesday still fixes.</description><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><content:encoded>
Every Windows service that exposes a local API does so through **LRPC**, the RPC runtime&apos;s local-only transport, and LRPC rides on top of **ALPC**, the kernel&apos;s asynchronous message-and-attribute IPC primitive. The kernel layer is settled engineering. The interface-callback layer in user-mode RPC application code is the load-bearing local elevation-of-privilege surface that almost every Patch Tuesday since 2018 has shipped fixes for. Microsoft does not publish a Win32 or WDK reference for the kernel-side ALPC API; the public knowledge of both layers comes from a handful of named researchers reverse-engineering it. And per-connection ALPC ports are unnamed, which is the asymmetry that makes the threat model coherent -- Section 4 walks why.
&lt;h2&gt;1. Every UAC Prompt Is an ALPC Handshake&lt;/h2&gt;
&lt;p&gt;Double-click an installer. The screen dims, a familiar dialog asks whether you want to allow this app to make changes, and a moment later either nothing happens or the installer keeps running. That moment of dim-and-prompt -- the &lt;a href=&quot;https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/&quot; rel=&quot;noopener&quot;&gt;User Account Control&lt;/a&gt; consent dialog -- is the most-seen artefact of one of the most-attacked primitives in the Windows kernel: a four-phase handshake on an asynchronous local-IPC port whose name does not appear in any Win32 or WDK reference Microsoft publishes.&lt;/p&gt;
&lt;p&gt;Trace the call from the user side. The Explorer shell invokes &lt;code&gt;ShellExecuteEx&lt;/code&gt; with the verb set to &lt;code&gt;runas&lt;/code&gt;. That call does not magically elevate the process; it sends a request &lt;em&gt;to another process&lt;/em&gt;, the &lt;strong&gt;Application Information service&lt;/strong&gt; (&lt;code&gt;appinfo&lt;/code&gt;) running as &lt;code&gt;svchost.exe -k netsvcs&lt;/code&gt; with SYSTEM authority [@msdocs-svchost] [@forshaw-rpc-2019]. The hand-off is an RPC call. The RPC runtime, asked for a local endpoint, selects the &lt;code&gt;ncalrpc&lt;/code&gt; protocol sequence -- &quot;Local procedure call&quot; in Microsoft&apos;s own protocol-sequence reference [@msdocs-protseq]. Underneath that string is the LRPC transport in &lt;code&gt;rpcrt4.dll&lt;/code&gt;, and underneath the LRPC transport is a kernel ALPC port that lives at the &lt;a href=&quot;https://paragmali.com/blog/the-object-manager-namespace/&quot; rel=&quot;noopener&quot;&gt;Object Manager name&lt;/a&gt; &lt;code&gt;\RPC Control\appinfo&lt;/code&gt;. The kernel resolves the name, the handshake completes, and a single syscall named &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt; [@ntdoc-ntalpc] carries the request message into the SYSTEM-context server and the reply back.&lt;/p&gt;
&lt;p&gt;That syscall is the load-bearing entry point for the entire local-IPC fabric. Microsoft Learn does not publish a reference page for it. The de facto reference is a community-maintained header dump at &lt;code&gt;ntdoc.m417z.com&lt;/code&gt; [@ntdoc-ntalpc] that lists all eight parameters of the function. The kernel object behind the call is the &lt;code&gt;_ALPC_PORT&lt;/code&gt;, and the per-connection structure layouts are documented only on Geoff Chappell&apos;s site [@chappell-alpc] [@chappell-alpcp] and inside the chapter named &lt;em&gt;Advanced local procedure call (ALPC)&lt;/em&gt; of &lt;em&gt;Windows Internals 7e Part 2&lt;/em&gt; [@wininternals-7e].&lt;/p&gt;

The kernel object and syscall family that replaced classic LPC in Windows Vista (November 2006). ALPC is an asynchronous, message-and-attribute IPC primitive built around the `_ALPC_PORT` object. The user-mode entry points are the undocumented `Nt*Alpc*` and `Alpc*` functions exported from `ntdll.dll`. Every local RPC call in modern Windows transits an ALPC port [@csandker-alpc].

The Microsoft RPC runtime&apos;s transport selected when an application binds to the `ncalrpc` protocol sequence [@msdocs-protseq]. LRPC layers the RPC interface-registration model -- IDL, NDR marshalling, security callbacks -- on top of ALPC ports. LRPC is implemented inside `rpcrt4.dll`; the kernel does not know it exists. The kernel sees only ALPC messages.
&lt;p&gt;The abbreviation collision is real and bites every newcomer. &lt;strong&gt;LPC&lt;/strong&gt; is the original Windows NT 3.1 kernel primitive. &lt;strong&gt;LRPC&lt;/strong&gt; is the RPC runtime&apos;s local transport, named in Windows NT 3.5 (1994), a full decade before ALPC existed [@custer-solomon-2e]. LRPC was a transport name when the underlying kernel object was still LPC. Vista renamed the kernel object to ALPC; nobody renamed the transport. The two abbreviations differ by one letter and refer to different layers.&lt;/p&gt;
&lt;p&gt;Two layers sit on top of one kernel object. The kernel layer is what &lt;code&gt;Nt*Alpc*&lt;/code&gt; syscalls touch. The user-mode layer is the RPC runtime&apos;s interface dispatch -- the IDL stubs, the NDR encoders, the per-interface security callback the application registers with &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; [@msdocs-rpcregisterif2]. The rest of this article pulls these two layers apart, walks the history that produced them, and explains why almost every Patch Tuesday since 2018 has shipped fixes inside the second one.&lt;/p&gt;

sequenceDiagram
    participant Client as Client (ShellExecuteEx peer)
    participant ConnPort as Connection port \RPC Control\appinfo
    participant CommPort as Per-connection communication ports (unnamed)
    participant Server as AppInfo service (SYSTEM)
    Client-&amp;gt;&amp;gt;ConnPort: NtAlpcConnectPort (CONNECT)
    ConnPort-&amp;gt;&amp;gt;Server: ALPC connect message queued
    Server-&amp;gt;&amp;gt;CommPort: NtAlpcAcceptConnectPort (ACCEPT, returns paired handles)
    Client-&amp;gt;&amp;gt;CommPort: NtAlpcSendWaitReceivePort (REQUEST)
    CommPort-&amp;gt;&amp;gt;Server: ALPC message with NDR-encoded args
    Server-&amp;gt;&amp;gt;CommPort: NtAlpcSendWaitReceivePort (REPLY)
    CommPort-&amp;gt;&amp;gt;Client: NDR-encoded reply delivered
    Client-&amp;gt;&amp;gt;CommPort: NtAlpcDisconnectPort (CLOSE)
&lt;p&gt;The diagram is the article in miniature. Three of the four labelled actors are kernel objects: a named connection port, an unnamed pair of communication ports, and the message queue between them. The fourth is application code running in two different processes. The bugs of the next thirteen years live in the application code. The diagram&apos;s correctness rests on a structural fact almost every secondary writeup gets wrong, and Section 4 spells it out in full.&lt;/p&gt;
&lt;p&gt;If this primitive is everywhere, why does nobody talk about it? Because nobody had to, for thirteen years.&lt;/p&gt;
&lt;h2&gt;2. Origins -- Cutler&apos;s NT and the Birth of LPC (1989-1993)&lt;/h2&gt;
&lt;p&gt;Dave Cutler talked about it, in October 1988, to a room of people he was trying to recruit out of Digital Equipment Corporation [@zachary-showstopper]. The pitch was a from-scratch portable operating system at Microsoft. The architectural commitment that mattered for our story was a microkernel-style design: the Windows personality, the OS/2 personality, the POSIX personality would all run as user-mode subsystems, each in its own process, talking to clients through a fast in-machine remote procedure call. The kernel would not implement the Win32 API directly. The kernel would implement an IPC primitive shaped like a procedure call and cheap enough to use for every Win32 API a process made.&lt;/p&gt;
&lt;p&gt;That decision created a design problem the team had to solve before any of the subsystems could be written. Microkernel-style separation of subsystems means that the Win32 client of &lt;code&gt;CreateWindow&lt;/code&gt; is in one process and the Win32 server that draws the window is in another. Every API call crosses a process boundary. The IPC primitive that carries the crossing has to look like a function call, return like a function call, and cost no more than tens of microseconds. The Cutler team -- Lou Perazzoli, Mark Lucovsky, Steven Wood, Darryl Havens, and the larger NT design group [@zachary-showstopper] -- shipped that primitive as &lt;strong&gt;Local Procedure Call&lt;/strong&gt;, or LPC, with the first release of Windows NT in July 1993. Helen Custer documented the design that same year in &lt;em&gt;Inside Windows NT&lt;/em&gt; [@custer-print], the canonical first-edition print primary.&lt;/p&gt;

The original Windows NT kernel IPC primitive, introduced with NT 3.1 in July 1993 as a synchronous inter-process communication facility [@csandker-alpc]. LPC was synchronous-call-shaped, used three port objects per connection (one named connection port plus two unnamed communication ports), and was the transport for every Win32 API call into the Client/Server Runtime Subsystem (CSRSS) until Windows Vista. The kernel removed classic LPC entirely by Windows 7; legacy `NtCreatePort` callers were silently redirected onto the ALPC implementation [@csandker-alpc].
&lt;p&gt;The classic LPC mechanism worked like this. A server process calls &lt;code&gt;NtCreatePort&lt;/code&gt; to create a &lt;em&gt;connection port&lt;/em&gt; under an Object Manager name (for example, &lt;code&gt;\Windows\ApiPort&lt;/code&gt; for CSRSS). The server then waits on the connection port. A client process opens the connection port by name and calls &lt;code&gt;NtConnectPort&lt;/code&gt; to request a session. The kernel creates two new, unnamed &lt;em&gt;communication ports&lt;/em&gt; -- one the client holds, one the server holds -- and ties them to the connection through the kernel&apos;s port-routing tables. From that point on, the client and server send messages through their respective communication-port handles; neither party has to look up the other in the Object Manager namespace. The three-port model is the architectural ancestor of every ALPC handshake the rest of this article will walk.&lt;/p&gt;

flowchart LR
    A[Client process] -- &quot;NtConnectPort by name&quot; --&amp;gt; B[Connection port \Windows\ApiPort -- NAMED]
    B -- &quot;NtAcceptConnectPort&quot; --&amp;gt; C[Server process]
    C -- &quot;issues a pair of handles&quot; --&amp;gt; D[Client comm port -- UNNAMED]
    C -- &quot;issues a pair of handles&quot; --&amp;gt; E[Server comm port -- UNNAMED]
    A -- &quot;NtRequestWaitReplyPort&quot; --&amp;gt; D
    D -- &quot;kernel routes the message&quot; --&amp;gt; E
    E -- &quot;delivered to&quot; --&amp;gt; C
&lt;p&gt;The two design pinch-points that Vista would later have to fix are visible already in the 1993 mechanism. First, the call surface was synchronous: &lt;code&gt;NtRequestWaitReplyPort&lt;/code&gt; sent a message and blocked the caller until the reply came back, which forced the higher-level RPC runtime to wrap its own asynchronous machinery around the syscall and doubled the syscall cost for every async RPC. Second, the message payload had a small fixed inline budget -- on the order of 256 bytes [@csandker-alpc] -- with anything larger requiring an explicit &lt;code&gt;NtMapViewOfSection&lt;/code&gt; dance to set up a shared section the server would then peek into. The split between &quot;short message in the syscall&quot; and &quot;long payload in a shared section&quot; was awkward, racy, and a perennial source of off-by-one bugs in the server stubs.&lt;/p&gt;
&lt;p&gt;The third pinch-point was security, and it is the one Cesar Cerrudo will name in 2006. LPC&apos;s access check happened once, at &lt;code&gt;NtConnectPort&lt;/code&gt;, against the connection port&apos;s discretionary access control list (DACL). After the handshake, the kernel had no further opinion about who could send what to whom over the established channel. The server trusted every message it received because the kernel had already vouched that the client cleared the DACL at connect time. In 1993 that trust model was fine. The only callers of CSRSS were Win32 client processes the team controlled. POSIX clients talked to the POSIX subsystem; OS/2 clients talked to the OS/2 subsystem; the trust boundaries were the subsystem boundaries and nobody crossed them on purpose.&lt;/p&gt;

The microkernel idea -- pull as much out of the kernel as possible, run it as user-mode servers -- was a late-1980s academic enthusiasm, energised by Carnegie Mellon&apos;s Mach. Cutler brought it to NT after building VMS and the never-shipped Mica research kernel at Digital. The catch was performance. Every API call that used to be a function call inside the kernel now had to be a context switch, a message copy, and a reply, twice. If that round trip cost a millisecond, Windows would feel like a 1980s timesharing system. LPC&apos;s job was to make it cost microseconds, and the team&apos;s success there is one reason NT could ship at all. The structural cost -- a synchronous primitive whose security check ran once and then trusted the channel -- was not the 1993 team&apos;s problem, because they controlled both ends of every conversation.
&lt;p&gt;The 1993 design assumed the only callers of CSRSS were Win32 client processes the team controlled. That assumption held for thirteen years.&lt;/p&gt;
&lt;h2&gt;3. The First Reckoning -- LPC&apos;s Failure Modes and Cerrudo&apos;s WLSI 2006&lt;/h2&gt;
&lt;p&gt;In March 2006, at Black Hat Europe in Amsterdam, Cesar Cerrudo gave a talk titled &lt;em&gt;WLSI -- Windows Local Shellcode Injection&lt;/em&gt;. Twelve weeks later, Microsoft shipped the Vista ALPC redesign. The temporal compression is intentional, but it is not the whole story: the Vista redesign had been underway inside the kernel team for years before Cerrudo&apos;s talk. What the talk did was give the public security community a name and a shape for the structural class of bug the redesign was about to address.&lt;/p&gt;
&lt;p&gt;Cerrudo&apos;s paper, archived at Exploit-DB under the title &lt;em&gt;WLSI Windows Local Shellcode Injection&lt;/em&gt; and dated March 14, 2006 [@cerrudo-exploitdb], with the speaker deck mirrored on Black Hat&apos;s own server [@cerrudo-bh-pdf], walked an end-to-end attack on an LPC server inside CSRSS. The exact server is less important than the attack&apos;s three-clause shape, which Cerrudo articulated and which would recur, over the next two decades, in every later ALPC and LRPC privilege-escalation primitive.&lt;/p&gt;

flowchart LR
    A[Port is reachable -- the connection port DACL admits the attacker] --&amp;gt; D[Local elevation-of-privilege primitive]
    B[Server trusts the message -- no per-message identity check or per-procedure authorization] --&amp;gt; D
    C[Channel survives the access check -- LPC checks the DACL once at NtConnectPort, then forgets] --&amp;gt; D
&lt;p&gt;Clause one: &lt;em&gt;the port is reachable&lt;/em&gt;. The LPC connection port has a DACL; the attacker happens to be inside it. For CSRSS&apos;s &lt;code&gt;\Windows\ApiPort&lt;/code&gt;, that means &quot;any Win32 process on the desktop&quot;, which is exactly what NT was supposed to permit. Clause two: &lt;em&gt;the DACL is permissive&lt;/em&gt;. Every authenticated user is in scope of the LPC servers that brokered the user-mode Win32 API surface, by design. Clause three: &lt;em&gt;the server trusts the message&lt;/em&gt;. The LPC kernel object exposes a &lt;code&gt;PORT_MESSAGE&lt;/code&gt; header with two fields the receiver can use for bookkeeping -- a process ID and a thread ID. The fields are not authenticated. The receiving server, in the WLSI demonstration, read attacker-controlled offsets and lengths out of the message body and walked into the server&apos;s own address space.&lt;/p&gt;
&lt;p&gt;The three clauses together produce a local elevation primitive. None of the clauses, taken individually, is a kernel bug. None, taken individually, is even an application bug. The bug -- in the WLSI exemplar -- is that the CSRSS server trusted a length field that came from a process the server itself had no reason to trust. The OS did exactly what its security model promised. The application did exactly what the IPC primitive made easy.&lt;/p&gt;

A Windows access control list attached to a securable object (a file, a registry key, a kernel object such as an LPC or ALPC port) that names the security principals allowed or denied each access right. For an LPC connection port, the DACL governs whether a calling process is allowed to open the port at all. Once the port is opened, the DACL is no longer consulted for messages flowing across the established connection -- which is exactly the once-and-done check at the centre of Cerrudo&apos;s structural class.

The 1993 trust model held until 2006 because the team controlled both ends of every conversation. Cerrudo named the class of bug that emerged when that assumption stopped holding.
&lt;p&gt;That structural class is the load-bearing reason the Vista redesign was about to be a redesign and not a patch. The three LPC failure modes the kernel team had identified -- the ones that motivated re-architecting the primitive rather than fixing the WLSI server -- compose a near-perfect mirror of Cerrudo&apos;s three clauses. They are: (1) the synchronous-only design forced the RPC runtime to layer its own asynchronous wrapper around &lt;code&gt;NtRequestWaitReplyPort&lt;/code&gt;, doubling the per-call syscall cost for async RPC; (2) the 256-byte inline plus shared-section dance was awkward and prone to race conditions in the server stub; (3) the port-DACL-only security model checked access once at connect and then trusted the channel, with no kernel primitive for per-message caller identity. A redesign was the only way to attack all three at once without breaking every NT 4-era server in the field.&lt;/p&gt;
&lt;p&gt;One LPC failure mode that did not make Cerrudo&apos;s slide and that Microsoft has never publicly discussed in detail was the reply-port confusion class. In classic LPC, a server&apos;s reply traveled back over the client&apos;s communication port handle, and a misbehaving server could be tricked into replying to the wrong client when multiple connections were interleaved. Microsoft addressed this quietly in the Vista era; the only public references are footnotes in &lt;em&gt;Windows Internals&lt;/em&gt; editions and the occasional aside in csandker [@csandker-alpc]. The public security community did not catch the bug class at the time.&lt;/p&gt;
&lt;p&gt;In November 2006 -- eight months after WLSI -- Windows Vista shipped. The new kernel called the replacement primitive &lt;strong&gt;Advanced LPC&lt;/strong&gt;. The redesign closed half of Cerrudo&apos;s structural class -- the &lt;em&gt;permissive port DACL&lt;/em&gt; half, by giving servers fine-grained tools to control who reaches their connection ports and by introducing a per-message security attribute the server could query for caller identity. It left the other half completely intact, because the other half is not a kernel property. The other half lives in the user-mode RPC runtime and in the application code that registers RPC interfaces on top of ALPC ports. That intact half is what the next thirteen years of public security research is about.&lt;/p&gt;
&lt;p&gt;The naive read of Cerrudo&apos;s paper is &quot;Microsoft will fix the bug.&quot; The structural read is harder: Cerrudo did not find a bug. He named a class of bug whose root cause is a property of the trust model. The Vista redesign closed the half of the class the kernel could close. It could not close the rest, because the rest is application code, and the kernel cannot inspect application code.&lt;/p&gt;
&lt;h2&gt;4. The Breakthrough -- ALPC, the Vista Redesign, and the Message-Attribute System&lt;/h2&gt;
&lt;p&gt;The Vista kernel team&apos;s answer to Cerrudo was not a patch. It was a complete replacement of the kernel object.&lt;/p&gt;
&lt;p&gt;ALPC re-cast the LPC port as an &lt;strong&gt;asynchronous, message-and-attribute-based&lt;/strong&gt; primitive. The classic LPC quartet -- &lt;code&gt;NtRequestPort&lt;/code&gt;, &lt;code&gt;NtReplyPort&lt;/code&gt;, &lt;code&gt;NtRequestWaitReplyPort&lt;/code&gt;, &lt;code&gt;NtReplyWaitReplyPort&lt;/code&gt; -- collapsed into a single syscall, &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt; [@ntdoc-ntalpc], with eight parameters whose combinations express every variant the older quartet supported. The kernel object behind the syscall is the &lt;code&gt;_ALPC_PORT&lt;/code&gt;. The structure layout is documented only in the chapter named &lt;em&gt;Advanced local procedure call (ALPC)&lt;/em&gt; of &lt;em&gt;Windows Internals 7e Part 2&lt;/em&gt; [@wininternals-7e], in the reverse-engineered header dumps on Geoff Chappell&apos;s site [@chappell-alpc] [@chappell-alpcp], and in the community-maintained &lt;code&gt;phnt&lt;/code&gt; headers that the Process Hacker project ships. None of those is a Microsoft Learn page.&lt;/p&gt;

The kernel object at the centre of Vista-and-later local IPC. Named connection ports are referenced by Object Manager name (typically under `\RPC Control`, `\BaseNamedObjects`, or per-session AppContainer subtrees). The per-connection communication ports created by `NtAlpcAcceptConnectPort` are unnamed and exist only as handles in the connecting and accepting processes. The structure layout is undocumented by Microsoft; the canonical reverse-engineered reference is Geoff Chappell&apos;s site [@chappell-alpc].
&lt;p&gt;The user-mode syscall surface, enumerated as exhaustively as anyone outside Microsoft can: &lt;code&gt;NtAlpcCreatePort&lt;/code&gt;, &lt;code&gt;NtAlpcConnectPort&lt;/code&gt;, &lt;code&gt;NtAlpcAcceptConnectPort&lt;/code&gt;, &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt;, &lt;code&gt;NtAlpcDisconnectPort&lt;/code&gt;, &lt;code&gt;NtAlpcCancelMessage&lt;/code&gt;, &lt;code&gt;NtAlpcCreatePortSection&lt;/code&gt;, &lt;code&gt;NtAlpcCreateResourceReserve&lt;/code&gt;, plus the &lt;code&gt;PORT_ATTRIBUTES&lt;/code&gt; and message-attribute structures that decorate each call. Microsoft Learn does not list any of them under a Win32 or WDK developer-facing reference. NtDoc [@ntdoc-ntalpc] is the de facto syscall reference, and the &lt;em&gt;Windows Internals 7e Part 2&lt;/em&gt; chapter is the de facto architectural reference.&lt;/p&gt;

Microsoft has documented the user-mode RPC runtime exhaustively on Learn -- the IDL syntax, the marshalling rules, the binding-handle API, the interface-registration flags. The `Nt*Alpc*` and `Alpc*` kernel surface is the deliberate exception. Microsoft&apos;s framing is that ALPC is an *internal* implementation detail of the RPC runtime, not a stable developer-facing API. Application authors are supposed to write RPC code, not ALPC code. The framing is defensible -- the ALPC ABI does change between Windows versions -- but it leaves the entire defender community reverse-engineering the surface from public symbols, the *Windows Internals* book series, NtDoc, Geoff Chappell, and the open-source `phnt` headers. The Vista-and-later structural correctness story this article tells is one that Microsoft has never written down for outside readers.
&lt;p&gt;The structural break with classic LPC is the &lt;strong&gt;message-attribute&lt;/strong&gt; system. Every ALPC message can carry four optional attributes, each of which targets one of the awkward LPC patterns the old kernel forced server authors to roll by hand.&lt;/p&gt;

An optional decoration on an ALPC message that lets the sender or receiver request a kernel service in band with the message itself. The four attribute types are **Context**, **Handle**, **Security**, and **View**. Each one targets a workflow that classic LPC required application code to perform out of band; in ALPC the kernel does the work atomically with the message exchange.
&lt;p&gt;&lt;strong&gt;The Context attribute&lt;/strong&gt; carries a per-message per-client cookie the server uses to associate the message with a logical operation. In classic LPC, a server tracking a multi-step protocol had to maintain its own client-to-state map indexed by client process ID, with all the race conditions that map invited; the Context attribute moves that bookkeeping into the kernel and makes it correct by construction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Handle attribute&lt;/strong&gt; is first-class handle passing inside the message itself. In classic LPC, transferring a kernel handle from sender to receiver required the sender to call &lt;code&gt;DuplicateHandle&lt;/code&gt; with the receiver&apos;s process handle, hope the receiver hadn&apos;t exited, and then send the resulting handle value in the message body. The Handle attribute lets the kernel do the duplication atomically with delivery; the receiver finds the duplicated handle already in its own handle table when the message lands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Security attribute&lt;/strong&gt; is the per-message identity primitive whose absence Cerrudo had named in 2006. The sender can opt to attach its caller token to a message; the receiver can opt to query the token (process ID, thread ID, integrity level, AppContainer SID) when it dispatches the message. The classic LPC pattern -- &quot;trust the channel because the kernel checked the DACL at connect&quot; -- gets replaced by &quot;ask the kernel who is actually sending this message right now.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The View attribute&lt;/strong&gt; is the shared-section dance, rewritten. In classic LPC, payloads larger than the inline budget required the sender to call &lt;code&gt;NtCreateSection&lt;/code&gt;, both parties to call &lt;code&gt;NtMapViewOfSection&lt;/code&gt;, and the receiver to peek into the shared mapping. The View attribute hands the receiver a section view automatically as a side effect of message delivery; no out-of-band coordination is required.&lt;/p&gt;

flowchart TD
    A[Context attribute] --&amp;gt; A1[Replaces: server-side client-to-state map indexed by PID]
    B[Handle attribute] --&amp;gt; B1[Replaces: out-of-band DuplicateHandle dance]
    C[Security attribute] --&amp;gt; C1[Replaces: trust the channel because DACL was checked at connect]
    D[View attribute] --&amp;gt; D1[Replaces: NtCreateSection plus NtMapViewOfSection dance for large payloads]
&lt;p&gt;The handshake topology survives from classic LPC and tightens. The server creates a named connection port with &lt;code&gt;NtAlpcCreatePort&lt;/code&gt;. The client opens the connection port by name with &lt;code&gt;NtAlpcConnectPort&lt;/code&gt; and sends an initial connect message; the kernel queues the connect on the server&apos;s port. The server calls &lt;code&gt;NtAlpcAcceptConnectPort&lt;/code&gt;, and the kernel returns a &lt;em&gt;pair&lt;/em&gt; of communication-port handles -- one to the client, one to the server -- that are bound to that single connection. From that point on, the kernel routes messages through the paired handles, and every send or receive is a single call to &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt;. Asynchronous is the default; synchronous semantics are a flag combination. The per-port message queue, the blocked-receiver wake, and the cross-port routing all run inside the kernel dispatcher.&lt;/p&gt;

flowchart LR
    A[Client process] -- &quot;NtAlpcConnectPort by name&quot; --&amp;gt; B[Connection port -- NAMED in \RPC Control]
    B -- &quot;kernel queues the connect&quot; --&amp;gt; C[Server process]
    C -- &quot;NtAlpcAcceptConnectPort&quot; --&amp;gt; D[Paired comm ports -- UNNAMED]
    A -- &quot;NtAlpcSendWaitReceivePort&quot; --&amp;gt; D
    D -- &quot;kernel routing&quot; --&amp;gt; C
&lt;p&gt;Here is the structural correction the input premise to this article got wrong, and that almost every secondary writeup gets wrong. &lt;strong&gt;Only the named connection port has an Object Manager name.&lt;/strong&gt; The per-connection communication ports created by &lt;code&gt;NtAlpcAcceptConnectPort&lt;/code&gt; are unnamed. They have no path under &lt;code&gt;\RPC Control&lt;/code&gt; or &lt;code&gt;\BaseNamedObjects&lt;/code&gt; or anywhere else. They exist only as handles in the address spaces of the two processes that completed the handshake. No third party can open them, because no third party has a name with which to ask the Object Manager for them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; ALPC&apos;s structural correctness rests on a single move: the per-connection communication ports are unnamed. Only the parties that completed the handshake can address the channel. The kernel does not let anyone else find it. This is the half of Cerrudo&apos;s structural class the Vista redesign actually closed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A statement like &quot;every ALPC port has an Object Manager name&quot; is wrong, and it propagates a wrong threat model. Named ports are the entry points an attacker can knock on. Unnamed communication ports are the established channels the attacker cannot reach without first being admitted through the connection port&apos;s DACL. Defenders who get this wrong start hunting for the unnamed children in the Object Manager namespace and find nothing, then conclude the tooling is broken. The tooling is fine. The ports are not there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft&apos;s documentation choice has consequences for tooling. The Wireshark dissector for MSRPC handles the on-the-wire NDR encoding well, but it has no view into the kernel ALPC layer because the kernel does not emit a packet capture. To see ALPC at the kernel level the tooling has to subscribe to the &lt;code&gt;Microsoft-Windows-Kernel-ALPC&lt;/code&gt; ETW provider [@msdocs-etwsys], and even that provider is gated behind &lt;code&gt;EVENT_TRACE_SYSTEM_LOGGER_MODE&lt;/code&gt;, which a non-SYSTEM caller cannot enable. The structural opacity of the kernel layer is partly an artefact of the deliberate &quot;no public WDK developer-facing reference&quot; position.&lt;/p&gt;
&lt;p&gt;Backward compatibility was preserved by silent rewiring rather than by parallel kernel objects. The classic LPC syscall names continue to link in any pre-Vista binary, but from Windows 7 onward the kernel routes those calls into the ALPC implementation underneath [@csandker-alpc]. Classic LPC, as an independent kernel object, no longer exists. The 1993 syscall surface is alive only as a thin compatibility shim. The 2006 kernel object is what every modern Windows service actually uses.&lt;/p&gt;
&lt;p&gt;The Vista redesign closed the &lt;em&gt;permissive port DACL&lt;/em&gt; half of the structural problem. It left the &lt;em&gt;interface callback returns RPC_S_OK when it should return RPC_S_ACCESS_DENIED&lt;/em&gt; half completely intact.The Vista kernel team&apos;s collective attribution stops short of naming individual ALPC architects. &lt;em&gt;Windows Internals 7e Part 2&lt;/em&gt; [@wininternals-7e] credits the work institutionally rather than to a single engineer, and no public Microsoft artefact identifies a single ALPC architect by name; secondary attributions in conference talks and blog posts trace back to footnotes rather than to primary record. That intact half is the rest of this article.&lt;/p&gt;
&lt;h2&gt;5. The Universalisation -- ALPC as the Local IPC Fabric (2009-2013)&lt;/h2&gt;
&lt;p&gt;By 2013, ALPC ran the local-IPC traffic of every Windows service that mattered. The kernel team had removed classic LPC. The Vista replacement had not been &lt;em&gt;replaced&lt;/em&gt;; it had been &lt;em&gt;adopted&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The transition was technically backwards-compatible. Pre-Vista binaries that called &lt;code&gt;NtCreatePort&lt;/code&gt; and &lt;code&gt;NtRequestWaitReplyPort&lt;/code&gt; continued to link and run; the kernel preserved the syscall names and silently rerouted the calls into the ALPC implementation underneath [@csandker-alpc]. The compatibility was not lossless -- the old single-message-per-call semantics map onto the ALPC asynchronous primitive only at the cost of an extra wait -- but it was good enough that no Microsoft-shipped service ever needed a port from classic LPC. Every service author upgrading to Vista or later was implicitly upgraded to ALPC.&lt;/p&gt;
&lt;p&gt;By Windows 8.1 the roll-call of services riding LRPC on ALPC was effectively the roll-call of services that ship with Windows. The Client/Server Runtime Subsystem (CSRSS) had been ALPC-only since Vista. The Local Security Authority Subsystem Service (LSASS) -- which brokers logon, token issuance, and Kerberos ticket caching -- exposes its API surface over LRPC. The Service Control Manager (SCM, &lt;code&gt;services.exe&lt;/code&gt;) accepts service-control commands over an LRPC interface. The DCOM activation service (&lt;code&gt;rpcss&lt;/code&gt;) marshals every local COM activation request through an LRPC pipeline. Windows Error Reporting, the audio service (&lt;code&gt;audiosrv&lt;/code&gt;), Task Scheduler (&lt;code&gt;schedsvc&lt;/code&gt;/&lt;code&gt;schrpc&lt;/code&gt;), the Application Information service (&lt;code&gt;appinfo&lt;/code&gt;) that brokers UAC, the Encrypting File System extension (&lt;code&gt;efslsaext&lt;/code&gt;, the EFSRPC server documented in the [MS-EFSR] specification [@ms-efsr]), the print spooler (&lt;code&gt;spoolsv&lt;/code&gt;), and the Background Intelligent Transfer Service (BITS) all expose at least one LRPC interface for client communication [@csandker-rpc].&lt;/p&gt;

flowchart TD
    K[Kernel ALPC layer -- _ALPC_PORT objects, NtAlpcSendWaitReceivePort dispatcher]
    K --&amp;gt; CSRSS[CSRSS -- Win32 subsystem]
    K --&amp;gt; LSASS[LSASS -- logon and token issuance]
    K --&amp;gt; SCM[Service Control Manager]
    K --&amp;gt; RPCSS[RPCSS -- DCOM activator and epmapper]
    K --&amp;gt; APPINFO[AppInfo -- UAC consent broker]
    K --&amp;gt; SPOOL[Print Spooler]
    K --&amp;gt; SCHRPC[Task Scheduler -- schrpc and schedsvc]
    K --&amp;gt; BITS[BITS -- background transfers]
    K --&amp;gt; AUDIO[Audio service -- audiosrv]
    K --&amp;gt; EFS[EFS -- efslsaext]
&lt;p&gt;That fan-out is the article&apos;s load-bearing diagram for understanding why ALPC is the most-attacked local IPC fabric in modern Windows. Every named service in that diagram is reachable over an LRPC interface. Every LRPC interface registers a per-interface security callback through &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; [@msdocs-rpcregisterif2] or &lt;code&gt;RpcServerRegisterIf3&lt;/code&gt; [@msdocs-rpcregisterif3]. Every callback is application code that the kernel cannot inspect. A single permissive interface in a single one of those services is a structural primitive that works against the transport every service uses. Trail of Bits, announcing their RPC Investigator tool in January 2023, captured the surface area in one line: MSRPC is &quot;involved on some level in nearly every activity that you can take on a Windows system, from logging in to your laptop to opening a file&quot; [@tob-rpcinv-blog].&lt;/p&gt;

MSRPC is involved on some level in nearly every activity that you can take on a Windows system, from logging in to your laptop to opening a file. -- Trail of Bits, *RPC Investigator* announcement, January 2023 [@tob-rpcinv-blog]
&lt;p&gt;To see the fabric in operation, walk one call. An unprivileged user invokes &lt;code&gt;StartServiceW&lt;/code&gt; from the SCM client library inside &lt;code&gt;sechost.dll&lt;/code&gt;. The library binds to the SCM&apos;s local RPC endpoint -- the &lt;code&gt;\RPC Control\ntsvcs&lt;/code&gt; ALPC port that the Service Control Manager registers at boot. The MIDL-generated client stub packs the service name and arguments into NDR and hands them to &lt;code&gt;NdrClientCall3&lt;/code&gt;. &lt;code&gt;rpcrt4.dll&lt;/code&gt; crosses into the kernel through &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt;. The kernel routes the ALPC message to the SCM&apos;s blocked worker thread inside &lt;code&gt;services.exe&lt;/code&gt;. The worker, running as SYSTEM, unpacks the NDR body with &lt;code&gt;NdrStubCall3&lt;/code&gt; and prepares to dispatch the server-side procedure. Before the procedure runs, the RPC runtime invokes the interface security callback, which checks whether the caller&apos;s token holds &lt;code&gt;SC_MANAGER_CONNECT&lt;/code&gt; and the target service&apos;s DACL grants &lt;code&gt;SERVICE_START&lt;/code&gt;. If the callback returns &lt;code&gt;RPC_S_OK&lt;/code&gt;, the SCM starts the service. The reply -- an NDR-encoded error code -- rides another &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt; back to the client. One user call, five layers crossed, and the kernel never knew it was running an RPC.&lt;/p&gt;
&lt;p&gt;One consequence of the silent kernel rewiring is that pre-Vista NT 4-era code samples appear to work on Windows 11. A textbook example from a 1996 driver-development book that calls &lt;code&gt;NtCreatePort&lt;/code&gt; will link, load, and exchange messages just fine; the messages are travelling over the 2006 ALPC kernel object behind a 1993 syscall name. This is unusual generosity from a kernel team that breaks driver ABIs every few releases, and it is one of the reasons Microsoft has preserved the option not to publish a &lt;code&gt;Nt*Alpc*&lt;/code&gt; developer-facing reference: as long as everyone is supposed to use the RPC runtime, the kernel object can keep evolving.&lt;/p&gt;
&lt;p&gt;Once the transport was universal, enumeration became valuable. If only LSASS used ALPC, listing LSASS&apos;s interfaces by hand was fine. Once every service did, automation was the only tractable methodology. The answer to who built that automation is the next section.&lt;/p&gt;
&lt;h2&gt;6. The Eureka Year -- Public Tooling and the Interface-Callback Class (2017-2019)&lt;/h2&gt;
&lt;p&gt;In an eighteen-month span between October 2017 and December 2019, four researchers turned ALPC from internal NT plumbing into the most-attacked local-IPC surface in modern Windows. The exemplars were structurally identical: an LRPC server registered an RPC interface with a callback that either was NULL or returned &lt;code&gt;RPC_S_OK&lt;/code&gt; for a caller that should have received &lt;code&gt;RPC_S_ACCESS_DENIED&lt;/code&gt;. The kernel ALPC layer behaved correctly in every one of them. The application code did not.&lt;/p&gt;

gantt
    title Public ALPC and LRPC research, October 2017 to December 2019
    dateFormat YYYY-MM
    section Tooling and disclosure
    PacSec -- A view into ALPC-RPC plus CVE-2017-11783       :2017-10, 1M
    SandboxEscaper -- CVE-2018-8440 0-day on GitHub          :2018-08, 1M
    Forshaw -- PPL and COM injection through LRPC            :2018-10, 1M
    Ormandy -- CVE-2019-1162 MSCTF disclosure                :2019-08, 1M
    Forshaw -- Calling local RPC servers from .NET           :2019-12, 1M
&lt;p&gt;The first publication is &lt;strong&gt;Clement Rouault and Thomas Imbert&apos;s &quot;A view into ALPC-RPC&quot;&lt;/strong&gt;, presented at PacSec in November 2017 [@hakril-pacsec] [@slideshare-pacsec] and at Hack.lu the same season [@youtube-hacklu]. The talk is the first end-to-end mechanical walk of the LRPC-over-ALPC stack to appear at a public security conference, and the talk&apos;s deliverable was a working NDR-aware fuzzer named &lt;strong&gt;RPCForge&lt;/strong&gt; [@rpcforge]. RPCForge surfaced &lt;strong&gt;CVE-2017-11783&lt;/strong&gt; [@nvd-cve-2017-11783], the first publicly-acknowledged ALPC elevation-of-privilege issue surfaced by an outside-Microsoft fuzzer. The NVD entry phrases the bug class as &quot;the way it handles calls to Advanced Local Procedure Call (ALPC)&quot; -- the canonical &quot;ALPC EoP&quot; classification that NVD reuses for every later instance.&lt;/p&gt;
&lt;p&gt;The second is &lt;strong&gt;James Forshaw&apos;s &lt;code&gt;NtObjectManager&lt;/code&gt; tooling&lt;/strong&gt;, distributed through the &lt;code&gt;sandbox-attacksurface-analysis-tools&lt;/code&gt; repository at Google Project Zero [@forshaw-saatools]. The tooling is a PowerShell module backed by a .NET library originally called &lt;code&gt;NtApiDotNet&lt;/code&gt; and renamed to &lt;code&gt;NtCoreLib&lt;/code&gt; in 2024. Forshaw introduced the design intent in a December 17, 2019 Project Zero post titled &lt;em&gt;Calling Local Windows RPC Servers from .NET&lt;/em&gt; [@forshaw-rpc-2019], opening with what amounts to a personal manifesto: &lt;em&gt;&quot;As much as I enjoy finding security vulnerabilities in Windows, in many ways I prefer the challenge of writing the tools to make it easier for me and others to do the hunting.&quot;&lt;/em&gt; The post named a gap in his own methodology -- &lt;em&gt;&quot;one of my big blind spots was anything which directly interacted with a Local RPC server&quot;&lt;/em&gt; -- and introduced &lt;code&gt;Get-RpcServer&lt;/code&gt;, &lt;code&gt;Get-NtAlpcServer&lt;/code&gt;, and &lt;code&gt;New-RpcClient&lt;/code&gt; as the cmdlets that closed it.&lt;/p&gt;

As much as I enjoy finding security vulnerabilities in Windows, in many ways I prefer the challenge of writing the tools to make it easier for me and others to do the hunting. -- James Forshaw, *Calling Local Windows RPC Servers from .NET*, Project Zero, December 17, 2019 [@forshaw-rpc-2019]
&lt;p&gt;The conceptual workflow Forshaw&apos;s tooling enables is short enough to fit on one screen. Enumerate every DLL on the system that contains RPC interface metadata. Parse the metadata to recover the IDL-equivalent description of each interface -- the UUID, the version, the procedures, the parameter types. Filter to the ones bound to a local-only protocol sequence. The result is an inventory of &quot;every local RPC procedure callable on this Windows install.&quot; Diff the inventory across a Patch Tuesday and the changes -- new procedures, retired procedures, changed security descriptors -- become a research backlog.&lt;/p&gt;
&lt;p&gt;{`
// PowerShell equivalent (run inside an elevated session with NtObjectManager installed):
//   Install-Module NtObjectManager
//   Get-RpcServer -DbgHelpPath &apos;C:\\Program Files\\Debugging Tools for Windows\\dbghelp.dll&apos; |
//     Where-Object { $&lt;em&gt;.Endpoints.ProtocolSequence -eq &apos;ncalrpc&apos; } |
//     Select-Object Name, InterfaceId, @{N=&apos;ProcCount&apos;;E={$&lt;/em&gt;.Procedures.Count}}&lt;/p&gt;
&lt;p&gt;// The runnable below mirrors the same logic in plain JS so the in-browser engine can execute it.
const interfaces = [
  { name: &apos;AppInfo&apos;,        interfaceId: &apos;201ef99a-7fa0-444c-9399-19ba84f12a1a&apos;, protocolSequence: &apos;ncalrpc&apos;, procedures: 12 },
  { name: &apos;schrpc&apos;,         interfaceId: &apos;86d35949-83c9-4044-b424-db363231fd0c&apos;, protocolSequence: &apos;ncalrpc&apos;, procedures: 27 },
  { name: &apos;spoolss&apos;,        interfaceId: &apos;12345678-1234-abcd-ef00-0123456789ab&apos;, protocolSequence: &apos;ncacn_np&apos;, procedures: 96 },
  { name: &apos;lsarpc-local&apos;,   interfaceId: &apos;12345778-1234-abcd-ef00-0123456789ab&apos;, protocolSequence: &apos;ncalrpc&apos;, procedures: 81 },
  { name: &apos;epmapper&apos;,       interfaceId: &apos;e1af8308-5d1f-11c9-91a4-08002b14a0fa&apos;, protocolSequence: &apos;ncalrpc&apos;, procedures: 5  },
];&lt;/p&gt;
&lt;p&gt;const local = interfaces
  .filter(i =&amp;gt; i.protocolSequence === &apos;ncalrpc&apos;)
  .map(i =&amp;gt; ({ name: i.name, interfaceId: i.interfaceId, procCount: i.procedures }));&lt;/p&gt;
&lt;p&gt;console.log(&apos;Local RPC interfaces (ncalrpc only):&apos;);
local.forEach(i =&amp;gt; console.log(`  ${i.name.padEnd(16)} ${i.interfaceId}  procs=${i.procCount}`));
console.log(`Total: ${local.length}`);
`}&lt;/p&gt;
&lt;p&gt;The third publication is &lt;strong&gt;SandboxEscaper&apos;s CVE-2018-8440&lt;/strong&gt; [@nvd-cve-2018-8440], dropped as a 0-day on GitHub on August 27, 2018, and triaged by CERT/CC as VU#906424 on August 28 with the note that the vulnerability was &quot;being exploited in the wild&quot; [@cert-vu906424]. The 0patch team published a micropatch within days and walked the bug specifics [@0patch-micropatch]. The structural shape of the bug is canonical and is worth tracing carefully.&lt;/p&gt;

sequenceDiagram
    participant Att as Unprivileged attacker process
    participant Sch as Task Scheduler ALPC port \RPC Control\atsvc
    participant Srv as schedsvc.dll worker thread (SYSTEM)
    participant FS as Target file -- C:\WINDOWS\System32\example.dll
    Att-&amp;gt;&amp;gt;Sch: NtAlpcConnectPort plus LRPC SchRpcSetSecurity request
    Sch-&amp;gt;&amp;gt;Srv: dispatch -- IfCallbackFn is NULL, no security callback runs
    Srv-&amp;gt;&amp;gt;FS: SetSecurityInfo as SYSTEM, grant Everyone:F to attacker-chosen path
    Srv-&amp;gt;&amp;gt;Att: RPC_S_OK
    Att-&amp;gt;&amp;gt;FS: overwrite the now-writable file
    Note over Att,FS: next call into the modified binary executes attacker code as SYSTEM
&lt;p&gt;The Task Scheduler service exposes an LRPC interface containing a procedure named &lt;code&gt;SchRpcSetSecurity&lt;/code&gt;, registered through &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; with &lt;code&gt;IfCallbackFn&lt;/code&gt; set to NULL. NULL has a specific meaning, documented verbatim on Microsoft Learn: &lt;em&gt;&quot;IfCallbackFn: Security-callback function, or NULL for no callback&quot;&lt;/em&gt; [@msdocs-rpcregisterif2]. No callback means the RPC runtime dispatches the call without asking the application whether the caller should be allowed.&lt;/p&gt;
&lt;p&gt;Once dispatched, &lt;code&gt;SchRpcSetSecurity&lt;/code&gt; running in the SYSTEM-context Task Scheduler worker thread set a permissive DACL on a file the attacker specified. The attacker chose a file the attacker did not have write access to. The SYSTEM-context service made it writable. The attacker then wrote attacker-controlled bytes into the file, triggered execution, and inherited SYSTEM.&lt;/p&gt;
&lt;p&gt;The 0patch micropatch writeup named the structural pattern as &quot;the Task Scheduler fails to impersonate the requesting client&quot; [@0patch-micropatch] -- which is to say, the service did the operation in its own privileged identity instead of the caller&apos;s. CERT/CC framed the same bug in transport terms: a vulnerability &quot;in the handling of ALPC&quot; that lets an authenticated user overwrite an arbitrary file [@cert-vu906424].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A NULL &lt;code&gt;IfCallbackFn&lt;/code&gt; is the canonical elevation-of-privilege-by-default bug shape. Microsoft Learn documents it as a legal value [@msdocs-rpcregisterif2], and the runtime accepts it without warning. Every notable LRPC EoP since 2017 either left the callback NULL or registered a callback whose body said the wrong thing. Defenders auditing in-house LRPC services should treat any &lt;code&gt;RpcServerRegisterIf2(..., NULL)&lt;/code&gt; in production code as a finding.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fourth is &lt;strong&gt;Tavis Ormandy&apos;s CVE-2019-1162&lt;/strong&gt; [@nvd-cve-2019-1162], disclosed in the August 13, 2019 Project Zero post &lt;em&gt;Down the Rabbit-Hole...&lt;/em&gt; [@ormandy-ctf-2019]. The bug class Ormandy named is the structural exemplar of &quot;shared system ALPC ports that ignore caller integrity.&quot; The Microsoft Text Services Framework (MSCTF) shipped a global ALPC port -- present since Windows XP in 2001 -- that any process on the desktop could open regardless of integrity level. The CTF subsystem trusted clients to identify themselves correctly in the messages they sent; the protocol had no integrity-level check or AppContainer enforcement. A low-integrity browser process could send messages that impersonated a high-integrity privileged process, and the CTF service would honour them. The fix narrowed the specific instance and left the general class of &quot;shared ALPC ports without caller-integrity enforcement&quot; open.&lt;/p&gt;
&lt;p&gt;A partially-overlapping fifth example -- the same interface-callback class expressed through DCOM activation rather than direct LRPC -- is &lt;strong&gt;Forshaw&apos;s October 18, 2018 Project Zero post&lt;/strong&gt; &lt;em&gt;Injecting Code into Windows Protected Processes using COM&lt;/em&gt; [@forshaw-com-ppl-2018]. The post documented a class of &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) bypass in which a DCOM activator marshalled an impersonated client token into a privileged COM server, and the server&apos;s interface callback trusted the marshalled identity too early in the dispatch flow. The kernel ALPC layer is doing exactly what the spec says; the bug is in the user-mode interface code that interprets the message.&lt;/p&gt;

Before `NtObjectManager`, a researcher looking at an LRPC service had to disassemble the service&apos;s DLL by hand, locate the calls to `RpcServerRegisterIf2`, read out the interface UUID and procedure-table pointer, parse the MIDL-generated stub manually, and assemble enough information to send a single well-formed call. After `NtObjectManager`, the same workflow was a one-line PowerShell pipeline. The methodology change cascaded into the Patch-Tuesday cycle. Differential analysis on the RPC interface inventory across a single Patch Tuesday became a research workflow that a small team could run in a single afternoon. Forshaw&apos;s December 2019 post named it explicitly: he wrote the tools because the tools were the bottleneck.

The application-supplied function whose pointer is passed as the `IfCallbackFn` argument to `RpcServerRegisterIf2` [@msdocs-rpcregisterif2] or `RpcServerRegisterIf3` [@msdocs-rpcregisterif3]. The RPC runtime invokes the callback after the port-level access check passes and before the call is dispatched to the IDL-named procedure. The callback inspects the binding handle, the calling user&apos;s token, the integrity level, and any other attribute the application chooses to consult. The callback returns `RPC_S_OK` to permit the call or any other status code to reject it. A NULL callback pointer is documented as a legal value and means &quot;permit every call that reaches the runtime.&quot;

The wire format that LRPC payloads marshal through. NDR is the original 32-bit Network Data Representation transfer syntax used by DCE/RPC; NDR64 is the 64-bit extension Microsoft introduced for 64-bit Windows [@msdocs-ndr64]. Local LRPC and remote MSRPC use the same transfer syntax; the only difference is that local calls travel inside an ALPC `PORT_MESSAGE` body rather than over a TCP or named-pipe transport.
&lt;p&gt;By the end of 2019, the inventory was visible, the bug class had been named, and four worked exemplars had been published. The mechanism underneath -- what an interface-registration callback actually is, why the OS cannot enforce its correctness -- is what the next section unpacks.&lt;/p&gt;
&lt;p&gt;The deeper realisation is that none of these are kernel bugs. The kernel ALPC layer behaved correctly in every one; the bugs live in the user-mode interface-callback layer that Section 7 walks next.&lt;/p&gt;
&lt;h2&gt;7. The LRPC Overlay -- Interface Registration and the Asymmetry the OS Cannot Fix&lt;/h2&gt;
&lt;p&gt;Look at the signature of &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt;. The seventh parameter is named &lt;code&gt;IfCallbackFn&lt;/code&gt;. Microsoft&apos;s own reference page documents that NULL is a legal value, and that NULL means &quot;no callback&quot; [@msdocs-rpcregisterif2]. That parameter is the asymmetry the rest of this section is about.&lt;/p&gt;
&lt;p&gt;A canonical server-side LRPC startup sequence looks like this. The service compiles an IDL file with MIDL; MIDL emits an &lt;code&gt;RPC_SERVER_INTERFACE&lt;/code&gt; structure that pins down the interface&apos;s UUID, version, and procedure table. The service calls &lt;code&gt;RpcServerUseProtseqEp&lt;/code&gt; with the protocol sequence &lt;code&gt;&quot;ncalrpc&quot;&lt;/code&gt;, an endpoint name, and a security descriptor; that call asks the kernel, by way of the RPC runtime, to create an ALPC connection port at the requested name under &lt;code&gt;\RPC Control&lt;/code&gt;. The service calls &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; or, since Windows 8, &lt;code&gt;RpcServerRegisterIf3&lt;/code&gt; [@msdocs-rpcregisterif3]. The newer call additionally accepts a per-interface security descriptor that the runtime enforces before consulting the callback. Both calls store the IDL spec, the interface-registration flags, and the per-interface security callback. Finally the service calls &lt;code&gt;RpcServerListen&lt;/code&gt;, and worker threads in the RPC runtime block inside &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Per call, the dispatch sequence is: accept the inbound ALPC connection, read the NDR-encoded request from the message body, invoke the registered security callback (if any), dispatch to the MIDL-generated server stub, and marshal the reply back.&lt;/p&gt;

sequenceDiagram
    participant Client as Client stub (rpcrt4.dll, user mode)
    participant Kernel as Kernel ALPC dispatcher
    participant Worker as Server worker thread (rpcrt4.dll, user mode)
    participant Cb as Interface security callback (application code)
    participant Stub as MIDL-generated server stub (application code)
    Client-&amp;gt;&amp;gt;Kernel: NtAlpcSendWaitReceivePort (REQUEST with NDR body)
    Kernel-&amp;gt;&amp;gt;Worker: deliver message to blocked worker
    Worker-&amp;gt;&amp;gt;Cb: invoke IfCallbackFn (if registered)
    Cb-&amp;gt;&amp;gt;Worker: return RPC_S_OK or RPC_S_ACCESS_DENIED
    Worker-&amp;gt;&amp;gt;Stub: dispatch to MIDL procedure (if callback returned OK)
    Stub-&amp;gt;&amp;gt;Worker: result returned through NDR encoder
    Worker-&amp;gt;&amp;gt;Kernel: NtAlpcSendWaitReceivePort (REPLY)
    Kernel-&amp;gt;&amp;gt;Client: deliver reply
&lt;p&gt;The kernel&apos;s job ends at &quot;deliver the message to a worker thread.&quot; Everything after that is application code. The RPC runtime is a DLL that the service loads into its own address space, and the runtime&apos;s notion of authorization is whatever the callback returns. If the callback returns &lt;code&gt;RPC_S_OK&lt;/code&gt;, the call proceeds. If the callback is NULL, the call proceeds without ever asking the application. The kernel has no notion of &quot;this call requires &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;&quot; or &quot;this call requires the caller to be in the local Administrators group&quot;, because those notions are policy choices the application makes, not properties of the IPC primitive.&lt;/p&gt;

The RPC service-discovery primitive at the well-known ALPC port `\RPC Control\epmapper`. An LRPC client that knows the interface UUID it wants to call -- but not which endpoint name a particular service is listening on -- calls into the endpoint mapper, hands over the UUID, and gets back the endpoint name. The mapper is itself an LRPC service; it bootstraps the rest. `rpcss` (the DCOM activator service) hosts the endpoint mapper on every Windows install.

The Microsoft dialect of OSF DCE IDL used to declare RPC interfaces. An `.idl` file pins down the interface UUID, version, methods, and parameter types; the MIDL compiler produces three artifacts: a header for both client and server, a client-side stub that marshals call arguments into NDR, and a server-side stub that unmarshals NDR back into call arguments and dispatches to the application&apos;s implementation.
&lt;p&gt;The interface-registration flag inventory tells the same story from a different angle. Microsoft Learn enumerates the flags on a single reference page [@msdocs-ifflags]; the four that matter for this section are quoted verbatim from that page.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;What Microsoft says it does&lt;/th&gt;
&lt;th&gt;What it closes&lt;/th&gt;
&lt;th&gt;What it leaves open&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&quot;the RPC runtime invokes the registered security callback for all calls, regardless of identity, protocol sequence, or authentication level of the client&quot;&lt;/td&gt;
&lt;td&gt;Forces the callback to run even for unauthenticated calls&lt;/td&gt;
&lt;td&gt;The correctness of the callback&apos;s return value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RPC_IF_ALLOW_SECURE_ONLY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rejects callers that did not authenticate at the runtime&apos;s minimum authentication level&lt;/td&gt;
&lt;td&gt;Unauthenticated callers&lt;/td&gt;
&lt;td&gt;Authenticated-but-unauthorized callers; Microsoft notes verbatim that &quot;Using the RPC_IF_ALLOW_SECURE_ONLY flag does not imply or guarantee a high level of privilege on the part of the calling user&quot; [@msdocs-ifflags]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RPC_IF_SEC_NO_CACHE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&quot;Disables security callback caching, forcing a security callback for each RPC call on a given interface&quot;&lt;/td&gt;
&lt;td&gt;Stale cached approval after a token-state change&lt;/td&gt;
&lt;td&gt;The correctness of the callback&apos;s body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RPC_IF_ALLOW_LOCAL_ONLY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rejects remote callers at the runtime layer&lt;/td&gt;
&lt;td&gt;Cross-machine reachability&lt;/td&gt;
&lt;td&gt;Local elevation primitives&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The table is the argument. Every flag closes a specific known-bad pattern. No flag changes the fact that the per-interface authorization decision is application code. The runtime can be configured to &lt;em&gt;force the callback to run&lt;/em&gt;. It cannot be configured to &lt;em&gt;make the callback return the right answer&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Port-level security is kernel infrastructure. Interface-level security is application code. The kernel can enforce the first; it cannot enforce the second. Everything in the rest of this article follows from that asymmetry.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft Learn&apos;s verbatim note on &lt;code&gt;IfCallbackFn&lt;/code&gt; reads: &lt;em&gt;&quot;Security-callback function, or NULL for no callback. Each registered interface can have a different callback function.&quot;&lt;/em&gt; [@msdocs-rpcregisterif2] A NULL callback means &quot;anyone who can open the connection port can call any procedure on this interface.&quot; Many in-house services interpret the parameter as if NULL meant &quot;default deny.&quot; It does not. NULL is a default &lt;em&gt;allow&lt;/em&gt;, gated only by the port DACL. The CVE-2018-8440 SchRpcSetSecurity disclosure [@cert-vu906424] [@0patch-micropatch] is the canonical example of what that interpretation costs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;RpcServerRegisterIf3&lt;/code&gt;, introduced in Windows 8 [@msdocs-rpcregisterif3], partially mitigates the structural concern by adding a per-interface security descriptor argument the runtime checks before the callback runs. Microsoft Learn documents the order: &lt;em&gt;&quot;If both SecurityDescriptor and IfCallbackFn are specified, the security descriptor in SecurityDescriptor will be checked first and the callback in IfCallbackFn will be called after the access check against the security descriptor passes.&quot;&lt;/em&gt; The &lt;code&gt;If3&lt;/code&gt; API also bakes in an &lt;a href=&quot;https://paragmali.com/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/&quot; rel=&quot;noopener&quot;&gt;AppContainer&lt;/a&gt; default-deny: in the absence of an explicit security descriptor, the runtime refuses calls from AppContainer processes. These are real defences. They do not change the underlying property that the per-call authorization decision -- the one that says &quot;this caller is allowed to invoke this procedure with these arguments&quot; -- is delegated to an application function the kernel cannot inspect.&lt;/p&gt;
&lt;p&gt;The kernel-vs-application boundary inside &lt;code&gt;rpcrt4.dll&lt;/code&gt; is unusual and easy to miss. The same DLL contains both the user-mode side of the kernel ALPC syscall surface (the thin wrappers around &lt;code&gt;NtAlpcSendWaitReceivePort&lt;/code&gt; that the runtime threads call) and the interface dispatch loop that ends in the application callback. Both halves run inside the service process; both halves are user-mode code from the kernel&apos;s point of view. The kernel does not know which RPC interface a given ALPC message is going to dispatch to. It just hands the message to a worker thread and forgets.&lt;/p&gt;
&lt;p&gt;The endpoint-mapper bootstrap path is the other piece of the LRPC overlay worth naming. A client that knows the interface UUID it wants to talk to -- say, the AppInfo interface UUID for UAC -- but does not know which endpoint name &lt;code&gt;appinfo&lt;/code&gt; happens to be listening on, opens the well-known ALPC port &lt;code&gt;\RPC Control\epmapper&lt;/code&gt;, sends a query containing the UUID, and gets back the endpoint name. The endpoint mapper is itself an LRPC service running inside &lt;code&gt;rpcss&lt;/code&gt;. It bootstraps the rest of the local-IPC fabric.&lt;/p&gt;
&lt;p&gt;NDR and NDR64 are the wire format. &lt;code&gt;NdrClientCall3&lt;/code&gt; on the client side packs the call arguments into the NDR representation Microsoft documents on Learn [@msdocs-ndr64]; the bytes ride inside an ALPC &lt;code&gt;PORT_MESSAGE&lt;/code&gt; body to the server; &lt;code&gt;NdrStubCall3&lt;/code&gt; on the server side unpacks them. The same NDR format that travels over a TCP socket for cross-machine MSRPC travels through an ALPC port for local LRPC. The transport is the only thing that differs.&lt;/p&gt;

The intuitive question -- &quot;if the callback is the problem, why doesn&apos;t the kernel just check it?&quot; -- bumps into two impossibility results. First, the callback is a function pointer into application code. The kernel cannot symbolically execute the function to determine whether its return value is correct; that is a halting-problem-shaped task in the general case. Second, even if the kernel could execute the function, the kernel does not know what &quot;correct&quot; means for an arbitrary application&apos;s authorization policy. &quot;Correct&quot; is the application&apos;s specification of who should be allowed to call what, and the application is the only party that has that specification. Closing the gap requires either a new ABI in which the application declares its authorization policy in a language the OS can validate, or a runtime sandbox that confines what the callback can do. Neither has been proposed as a stable Microsoft direction in any public artefact.
&lt;p&gt;The structural punchline is that the RPC runtime is application code -- the callback runs in user mode in the server&apos;s address space, the runtime trusts whatever the callback returns, and the OS cannot validate the callback&apos;s body. The CVE-2019-1162 MSCTF disclosure [@ormandy-ctf-2019] and the local-COM-over-LRPC PPL-bypass class [@forshaw-com-ppl-2018] are &lt;em&gt;both&lt;/em&gt; structural instances of this asymmetry; no kernel change could have prevented them.&lt;/p&gt;
&lt;p&gt;That asymmetry is the engine. Almost every CVE on the Patch-Tuesday treadmill since 2018 -- the Task Scheduler ACL bug, the CTF subsystem disclosure, the PPL-COM bypasses, the Potato-family activations -- is structurally the same shape. Some are LRPC bugs. Some are not. The next section explains which is which.&lt;/p&gt;
&lt;h2&gt;8. Competing Approaches -- Named Pipes, COM, Filter Ports, and the Potato Disambiguation&lt;/h2&gt;
&lt;p&gt;Roughly half the time a defender reads &quot;Potato&quot; in a CVE writeup, the underlying primitive is not ALPC. The other half of the time, it is. Knowing which is which is the single most-cited reason defenders mis-classify privilege-escalation attacks. The disambiguation matters because the mitigations differ: an LRPC-on-ALPC Potato is closed (or worsened) by RPC interface-flag changes; a named-pipe Potato is closed (or worsened) by &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; policy.&lt;/p&gt;
&lt;p&gt;Before the Potato classification, four local-IPC primitives sit alongside LRPC-on-ALPC and deserve a brief tour.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Named pipes&lt;/strong&gt; [@msdocs-protseq] [@msdocs-impnp] [@csandker-np] are the first-class alternative that works both locally &lt;em&gt;and&lt;/em&gt; across machines over SMB. The Windows RPC runtime supports a &lt;code&gt;ncacn_np&lt;/code&gt; (Network Computing Architecture, Connection-oriented, Named Pipe) protocol sequence that lets an RPC interface be reached either through &lt;code&gt;\\.\pipe\name&lt;/code&gt; locally or through an SMB tree-connect remotely. The load-bearing security primitive for the named-pipe-Potato class is &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; [@msdocs-impnp], a Win32 API that lets the server end of a named pipe impersonate the client process; the API requires the caller to hold &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;. The privilege is granted by default to LocalSystem, LocalService, NetworkService, and to processes that hold the privilege in their token through policy. The named-pipe-Potato attack pattern is &quot;a service running with &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is tricked into connecting to a named pipe the attacker controls, and the attacker calls &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; to inherit the service&apos;s token.&quot;&lt;/p&gt;

The Windows user-right that permits a thread to impersonate another security principal -- specifically by calling APIs such as `ImpersonateNamedPipeClient` [@msdocs-impnp] or `ImpersonateLoggedOnUser`. The privilege is granted by default to `LocalSystem`, `NetworkService`, `LocalService`, and processes started by the Service Control Manager. As Clement Labro summarised the practical implication: *&quot;if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM&quot;* [@itm4n-printspoofer], because every interactive way to use either privilege ends in a SYSTEM token under the right circumstances. The named-pipe-Potato family exploits exactly this fact.

The DCOM lookup primitive that translates an object exporter identifier (OXID) to a string binding (a protocol sequence plus an endpoint) where the corresponding COM server is listening. By default the OXID resolver runs in `rpcss` on TCP port 135. RoguePotato [@roguepotato-blog] [@roguepotato-repo] -- the post-Windows-10-1809 evolution of the Potato family -- redirects an outbound OXID-resolver query to an attacker-controlled host, which lets the attacker substitute an arbitrary endpoint and, through that, an arbitrary impersonation token.
&lt;p&gt;&lt;strong&gt;Shared sections plus events&lt;/strong&gt; is the lowest-level local-IPC pattern. Two processes call &lt;code&gt;NtCreateSection&lt;/code&gt; to back the same shared memory, then synchronise with kernel events or semaphores. There is no framing, no caller-identity primitive, and no message boundary. The pattern is used in performance-sensitive contexts such as browser sandboxes and DirectX swapchain handoff; it is not a competitor with LRPC-on-ALPC for general request-reply use cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;COM local activation&lt;/strong&gt; [@forshaw-com-ppl-2018] [@roguepotato-blog] is not a competitor. It is a higher-level overlay. The DCOM activation service (&lt;code&gt;rpcss&lt;/code&gt;) takes a CoCreateInstance-style activation request and, for local activations, marshals into LRPC under the hood. This is why DCOM-activation attacks are &lt;em&gt;also&lt;/em&gt; LRPC attacks: the trigger transport is DCOM, but the impersonation primitive ends up being the LRPC &lt;code&gt;RpcImpersonateClient&lt;/code&gt; machinery that runs inside the activated server.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Filter Communication Ports&lt;/strong&gt; [@msdocs-minifilter-replacement] [@msdocs-fltsendmessage] are the minifilter-specific IPC channel for talking between a kernel-mode file-system filter driver and a user-mode service. A minifilter calls &lt;code&gt;FltCreateCommunicationPort&lt;/code&gt; to set up the server side; a user-mode application calls &lt;code&gt;FilterConnectCommunicationPort&lt;/code&gt; to attach to it; the kernel-side &lt;code&gt;FltSendMessage&lt;/code&gt; and the user-side &lt;code&gt;FilterReplyMessage&lt;/code&gt; carry payloads in either direction. Filter Communication Ports are a separate primitive from ALPC and live in their own namespace; the only reason to mention them in this section is that defenders sometimes conflate &quot;any named local IPC endpoint&quot; with ALPC, and they should not.&lt;/p&gt;
&lt;p&gt;Now the Potato disambiguation. The &lt;a href=&quot;https://paragmali.com/blog/windows-access-control-25-years-of-attacks/&quot; rel=&quot;noopener&quot;&gt;Potato family&lt;/a&gt; is the loudest local-EoP cluster of the last decade, and the family contains two structurally different sub-families that share the surname for historical reasons.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Axis&lt;/th&gt;
&lt;th&gt;DCOM-activation Potato&lt;/th&gt;
&lt;th&gt;Named-pipe Potato&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Triggering protocol&lt;/td&gt;
&lt;td&gt;DCOM &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; activation against &lt;code&gt;127.0.0.1&lt;/code&gt; plus the local OXID resolver&lt;/td&gt;
&lt;td&gt;Service connects out to a named pipe controlled by the attacker (often via UNC or by tricking a print or EFS hook)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Impersonation primitive&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RpcImpersonateClient&lt;/code&gt; invoked by the activated COM server during the LRPC dispatch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; invoked by the attacker on the receiving end of the pipe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Required attacker privilege&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; plus the ability to direct the service to connect to the attacker&apos;s pipe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical exemplars&lt;/td&gt;
&lt;td&gt;RoguePotato (May 2020) [@roguepotato-blog] [@roguepotato-repo], JuicyPotato, RottenPotato&lt;/td&gt;
&lt;td&gt;PrintSpoofer (2020) [@itm4n-printspoofer], EfsPotato, PetitPotam&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-KB5004442 status&lt;/td&gt;
&lt;td&gt;OXID redirection to remote hosts blocked by &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; enforcement, March 2023 [@mssupport-kb5004442]&lt;/td&gt;
&lt;td&gt;Unchanged at the OS level; mitigation is &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; hygiene&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Underlying IPC fabric&lt;/td&gt;
&lt;td&gt;LRPC on ALPC&lt;/td&gt;
&lt;td&gt;Named pipes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The HITB Amsterdam 2021 talk &lt;em&gt;The Rise of Potatoes: Privilege Escalation in Windows Services&lt;/em&gt; by Andrea Pierini and Antonio Cocomazzi [@hitb-potatoes] is the canonical end-to-end family classification. Pierini and Cocomazzi are also the disclosers of RoguePotato [@roguepotato-blog] -- the variant that broke the post-Windows-10-1809 mitigation by redirecting the OXID resolver to an attacker-controlled host on a port other than 135. The disclosure was May 11, 2020, building on their December 6, 2019 &quot;RogueWinRM&quot; precursor work [@roguewinrm-blog] in which they obtained a SYSTEM identification token but not yet a usable impersonation token.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Does the writeup say &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; or &lt;code&gt;RpcImpersonateClient&lt;/code&gt;? The first is a named-pipe primitive. The second is an LRPC-on-ALPC primitive. The trigger transport may be shared (DCOM activation, RPRN, EFSR), but the impersonation primitive is what tells you which IPC surface the attack actually exercises -- and which mitigation closes it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The KB5004442 DCOM hardening rollout [@mssupport-kb5004442], which addresses CVE-2021-26414, completed phase 3 on March 14, 2023. Phase 3 enabled the hardening with no override path: DCOM activations are subject to &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; as a mandatory minimum, and the previously available registry overrides were removed. The OS-default configuration since March 2023 closes the JuicyPotato variant that depended on outbound DCOM to TCP/135 with downgraded authentication. RoguePotato and its descendants survived the rollout because they did not depend on the downgrade -- they depend on the OXID redirect itself, which the hardening did not block at the OS-default configuration.&lt;/p&gt;

Two adjacent kernel-IPC primitives deserve a footnote. The Windows Notification Facility (WNF) is a kernel-mode publish-subscribe channel for one-way state notifications [@tob-wnf]; processes register interest in named &quot;state names&quot; and the kernel delivers updates. Event Tracing for Windows (ETW) is the kernel&apos;s one-way event-streaming substrate [@tob-etw]; providers emit structured events, controllers configure sessions, and consumers read the events back. Yarden Shafir&apos;s Trail of Bits posts on both are the canonical practitioner references for the architectural-cousin framing. Neither WNF nor ETW competes with LRPC for the request-reply use case, because neither is request-reply. They are family of ALPC -- kernel-mediated message buses -- but they solve different problems.
&lt;p&gt;The comparison matrix gives us the surface area of competing primitives. The next section asks: given this surface area, what can the OS structurally not guarantee?&lt;/p&gt;
&lt;h2&gt;9. The Limits -- Three Things ALPC and LRPC Structurally Cannot Enforce&lt;/h2&gt;
&lt;p&gt;The Vista redesign closed half the structural problem of LPC. It left three other things permanently open, and no future ALPC version can close them without a new ABI. Each of the three is a property of the trust model, not a bug in any specific server. Each has a CVE-history footprint that confirms the structural framing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The interface-callback gate cannot be enforced by the OS.&lt;/strong&gt; The &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; contract [@msdocs-rpcregisterif2] accepts a function pointer into the application&apos;s address space; the runtime trusts whatever the callback returns. The OS-side enforcement available without an ABI change is at most &quot;invoke the callback&quot; (which &lt;code&gt;RPC_IF_SEC_NO_CACHE&lt;/code&gt; [@msdocs-ifflags] already enforces on every call). The OS cannot read the callback&apos;s source, cannot infer its policy, and cannot decide whether the callback&apos;s verdict matches what the application&apos;s specification says it should be. Every interface-callback EoP -- CVE-2019-1162 MSCTF [@ormandy-ctf-2019], the PPL-COM class [@forshaw-com-ppl-2018], CVE-2018-8440 [@nvd-cve-2018-8440] -- is a structural instance of this bound. Closing it requires either inventing a declarative authorization ABI the OS can validate, or sandboxing callback execution. Neither has been proposed as a stable Microsoft direction in any public artefact through 2026.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no transitive caller identity.&lt;/strong&gt; ALPC&apos;s Security message attribute captures the caller&apos;s token at handshake or on demand; it does not carry a chain of trust across multiple hops. A proxy server in the middle of a call chain has to impersonate explicitly or marshal identity in band, and the receiving party at the far end has no kernel primitive that tells it &quot;the message came from caller A, was forwarded by proxy B, and the original token is still attached.&quot; Confused-deputy attacks in the LRPC fabric are not bugs; they are an inherent property of the trust model. The DCOM-activation Potato class [@roguepotato-blog] [@roguepotato-repo] exploits exactly this property: the DCOM activator passes a token into a privileged COM server, and the server cannot reliably tell whether the token chain on the way in matches what the activator&apos;s specification said it should be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The kernel routing path is in the trusted computing base.&lt;/strong&gt; The ALPC dispatcher runs in Ring 0. Any bug in &lt;code&gt;_ALPC_PORT&lt;/code&gt; object lifecycle, in &lt;code&gt;_ALPC_HANDLE_DATA&lt;/code&gt; reference counting, in message-attribute marshalling, or in any of the dozens of structures Geoff Chappell&apos;s site [@chappell-alpc] [@chappell-alpcp] documents but Microsoft does not, is a direct kernel-elevation primitive. The CVE history demonstrates the assumption is wishful: CVE-2018-8440 [@nvd-cve-2018-8440] has a kernel reference-counting flavour in addition to the well-known interface-callback flavour, and several of the Patch-Tuesday ALPC EoP advisories of 2020-2024 carry NVD descriptions that say &quot;improperly handles calls to Advanced Local Procedure Call (ALPC)&quot; with no further detail because the underlying bug is a kernel bookkeeping issue Microsoft does not enumerate. The kernel routing path is settled engineering by any reasonable standard, but settled engineering is not zero-bug engineering. A new ALPC CVE in any given Patch Tuesday is consistent with the structural model.&lt;/p&gt;

flowchart TD
    A[The interface-callback gate -- the OS cannot validate the callback body] --&amp;gt; D[Patch-Tuesday treadmill -- interface callback CVEs, integrity-level CVEs, kernel ALPC CVEs]
    B[No transitive caller identity -- ALPC has no chain-of-trust primitive across hops] --&amp;gt; D
    C[The kernel routing path is in the TCB -- any _ALPC_PORT or attribute bug is a direct kernel EoP] --&amp;gt; D
&lt;p&gt;There is a fourth observation that is not an impossibility result but is worth stating in the same breath: &lt;strong&gt;the practical upper bound on local authentication strength&lt;/strong&gt;. &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; is the practical ceiling for local LRPC; the &lt;code&gt;ncalrpc&lt;/code&gt; transport supports only &lt;code&gt;RPC_C_AUTHN_WINNT&lt;/code&gt; authentication [@msdocs-protseq], and the strongest integrity check the runtime offers under that authentication service is packet integrity. The KB5004442 DCOM rollout [@mssupport-kb5004442] raised the &lt;em&gt;minimum&lt;/em&gt; for DCOM activations to &lt;code&gt;PKT_INTEGRITY&lt;/code&gt; in March 2023; it did not change the &lt;em&gt;ceiling&lt;/em&gt;. The gap between upper and lower bounds is substantial and structural: raising mandatory authentication closes the unauthenticated vector and leaves the authenticated-but-unauthorized vector -- the interface-callback class -- wide open.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The OS can require that the callback runs. It cannot require that the callback returns the right answer. The Patch-Tuesday treadmill is the consequence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; CVE-2017-11783, CVE-2018-8440, and CVE-2019-1162 were the canonical exemplars of the interface-callback class. They were not unlucky outliers from an otherwise sound engineering effort. They are instances of a class the design of &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; cannot exclude. Almost every subsequent year of Patch Tuesdays has shipped further instances of the same class, and 2026&apos;s count is on track to be no smaller than 2018&apos;s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Closing the interface-callback gap would look like one of two architectural shifts. Either Microsoft would introduce a declarative authorization language for RPC interfaces -- a manifest the application ships alongside the IDL that the runtime can parse and the OS can validate -- and then forbid the imperative callback. Or the runtime would execute the callback inside a sandbox that constrains what the callback can do (no arbitrary memory reads of the service&apos;s address space, no ability to issue privileged syscalls, no ability to side-channel through global state). Neither is on a publicly-named Microsoft roadmap; the closest public artefact is Forshaw&apos;s ongoing tooling work on parsing the interface inventory [@forshaw-saatools] [@forshaw-rpc-2019] [@forshaw-poc2023], which equips defenders to audit the callbacks they have rather than to replace the model.&lt;/p&gt;
&lt;p&gt;The limits are honest. They are also not the whole story. Research has not stopped trying to close the gap, and the next section names what is still active.&lt;/p&gt;
&lt;p&gt;The Patch-Tuesday treadmill is the &lt;em&gt;expected&lt;/em&gt; steady state, not a transitional embarrassment. Closing the class requires reworking the contract -- a different ABI, or a sandboxed execution model -- and no public Microsoft roadmap commits to either.&lt;/p&gt;
&lt;h2&gt;10. Open Problems and a Practical Field Guide (2024-2026)&lt;/h2&gt;
&lt;p&gt;The 2024-2026 conference cycle is still arguing about how to make the interface-callback class scalable to defend. This section enumerates the open problems and then closes with the practical workflow a defender or an in-house RPC author can run today. The practical recipe is in part an answer to the open problems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 1: public RPC fuzzing at Microsoft-internal scale.&lt;/strong&gt; The public ceiling is RPCForge [@rpcforge] for NDR-aware fuzzing, Forshaw&apos;s &lt;code&gt;NtObjectManager&lt;/code&gt; for interface inventory and client generation [@forshaw-saatools] [@forshaw-rpc-2019], and the November 2023 PoC talk &lt;em&gt;Building More Windows RPC Tooling for Security Research&lt;/em&gt; [@forshaw-poc2023] for the latest research-tooling continuation. Microsoft&apos;s internal pipeline is not public; whether a coverage-guided NDR64 fuzzer can become a small-team repeatable Patch-Tuesday tool is open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 2: auditing the interface-registration model for structural permissiveness.&lt;/strong&gt; A defender using &lt;code&gt;Get-RpcServer&lt;/code&gt; can enumerate every LRPC interface on a Windows install and dump each interface&apos;s procedures and security descriptor. The defender cannot tell, without per-interface manual review, whether a registered callback is correct. Heuristic detection of NULL &lt;code&gt;IfCallbackFn&lt;/code&gt; is mechanical; detection of &lt;em&gt;semantically&lt;/em&gt; permissive callbacks -- callbacks whose body trusts a field the caller controls -- is open and probably AI-shaped.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 3: &lt;code&gt;RPC_IF_SEC_NO_CACHE&lt;/code&gt; adoption and cost.&lt;/strong&gt; No public catalogue of which Microsoft services use the flag exists. No per-call cost benchmark is published. Defender heuristics that recommend the flag for high-risk interfaces cannot quantify the performance trade-off they are recommending.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 4: the local-COM-over-LRPC bypass class.&lt;/strong&gt; Forshaw&apos;s 2018 PPL-COM post [@forshaw-com-ppl-2018] articulated a class of attack against Protected Process Light that continues to surface in CVE reports. The structural class is unaddressed at the OS level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 5: ALPC as covert channel.&lt;/strong&gt; The CVE-2019-1162 MSCTF fix [@ormandy-ctf-2019] narrowed the MSCTF subsystem&apos;s exposure. The general class of &quot;shared system ALPC ports that ignore caller integrity&quot; is structural; identifying others requires the kind of systematic audit Open Problem 2 names.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 6: defender SOC integration of the &lt;code&gt;Microsoft-Windows-Kernel-ALPC&lt;/code&gt; &lt;a href=&quot;https://paragmali.com/blog/etw-how-windows-2000s-performance-hack-became-the-edr-substr/&quot; rel=&quot;noopener&quot;&gt;ETW provider&lt;/a&gt;&lt;/strong&gt; [@msdocs-etwsys]. The provider is high-volume; production SOC pipelines rarely subscribe to it because the event rate overwhelms commodity collection. Per-call ALPC visibility today is concentrated inside &lt;a href=&quot;https://paragmali.com/blog/from-cmdexe-to-a-kusto-row-in-90-seconds-how-sysmon-and-defe/&quot; rel=&quot;noopener&quot;&gt;EDR vendors&lt;/a&gt; that gate it behind antimalware-PPL processes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Open problem 7: AppContainer-aware RPC capability checking.&lt;/strong&gt; &lt;code&gt;RpcServerRegisterIf3&lt;/code&gt; [@msdocs-rpcregisterif3] introduces an AppContainer default-deny, but there is no standard pattern for in-house service authors who want to express &quot;this procedure requires capability X.&quot; Service authors roll their own; some get it right.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Author / Org&lt;/th&gt;
&lt;th&gt;Reference&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NtObjectManager&lt;/code&gt; / &lt;code&gt;NtCoreLib&lt;/code&gt; (formerly &lt;code&gt;NtApiDotNet&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;LRPC interface enumeration, decompilation, and client generation from PowerShell or .NET&lt;/td&gt;
&lt;td&gt;James Forshaw, Project Zero&lt;/td&gt;
&lt;td&gt;[@forshaw-saatools] [@forshaw-rpc-2019]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RpcView&lt;/td&gt;
&lt;td&gt;Qt5/C++ GUI for browsing RPC servers and decompiled interface metadata across Windows versions&lt;/td&gt;
&lt;td&gt;silverf0x&lt;/td&gt;
&lt;td&gt;[@rpcview-repo]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPC Investigator&lt;/td&gt;
&lt;td&gt;.NET Forms UI built on &lt;code&gt;NtApiDotNet&lt;/code&gt; for enumeration, client workbench, and an &quot;RPC Sniffer&quot; ETW-backed live view&lt;/td&gt;
&lt;td&gt;Trail of Bits, January 2023&lt;/td&gt;
&lt;td&gt;[@tob-rpcinv-blog] [@rpcinv-repo]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPCMon&lt;/td&gt;
&lt;td&gt;ETW-based GUI for scanning RPC communication, built like Sysinternals Procmon, depending on Forshaw&apos;s library&lt;/td&gt;
&lt;td&gt;CyberArk Labs&lt;/td&gt;
&lt;td&gt;[@rpcmon-repo]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPCForge&lt;/td&gt;
&lt;td&gt;NDR-aware local Python fuzzer for ALPC-exposed RPC interfaces&lt;/td&gt;
&lt;td&gt;Clement Rouault and Thomas Imbert, Sogeti ESEC&lt;/td&gt;
&lt;td&gt;[@rpcforge]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forshaw NDR64 / RPC research pipeline (2023)&lt;/td&gt;
&lt;td&gt;Continued research tooling and conference materials&lt;/td&gt;
&lt;td&gt;James Forshaw&lt;/td&gt;
&lt;td&gt;[@forshaw-poc2023]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The practical field guide.&lt;/strong&gt; Eight numbered actions for the defender or in-house RPC service author. Each cites a verified source the reader can re-read in full.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 1. &lt;strong&gt;Enumerate registered LRPC interfaces&lt;/strong&gt; with &lt;code&gt;Install-Module NtObjectManager; Get-RpcServer ... | Where-Object { $_.Endpoints.ProtocolSequence -eq &apos;ncalrpc&apos; }&lt;/code&gt; [@forshaw-saatools] [@forshaw-rpc-2019]. Snapshot before and after Patch Tuesday and diff on (UUID, procedure list, security descriptor). 2. &lt;strong&gt;Enumerate live ALPC server ports&lt;/strong&gt; with &lt;code&gt;Get-NtAlpcServer&lt;/code&gt;. The cmdlet returns the named connection ports; the unnamed per-connection ports are not enumerable by design (see Section 4) [@forshaw-saatools]. 3. &lt;strong&gt;Reach a local RPC server from PowerShell&lt;/strong&gt; with Forshaw&apos;s &lt;code&gt;New-RpcClient&lt;/code&gt; cmdlet, which generates a &lt;code&gt;[NtCoreLib.Win32.Rpc.Client]&lt;/code&gt;-derived class from the parsed server metadata [@forshaw-rpc-2019]. This is the primitive that lets a Patch-Tuesday differential become an actual interaction. 4. &lt;strong&gt;Audit your own RPC service&lt;/strong&gt; for the canonical mistake: any &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt; or &lt;code&gt;RpcServerRegisterIf3&lt;/code&gt; call with a NULL &lt;code&gt;IfCallbackFn&lt;/code&gt; argument is &quot;anyone who can open the port can call any procedure on the interface&quot; [@msdocs-rpcregisterif2] [@msdocs-rpcregisterif3]. Treat NULL callbacks as a finding, not a default. 5. &lt;strong&gt;Harden an exposed LRPC interface&lt;/strong&gt; with the flag combination &lt;code&gt;RPC_IF_ALLOW_SECURE_ONLY | RPC_IF_SEC_NO_CACHE&lt;/code&gt; plus an explicit callback that validates &lt;code&gt;I_RpcBindingInqLocalClientPID&lt;/code&gt; and the caller&apos;s token integrity level [@msdocs-ifflags]. The Microsoft Learn note that &quot;Using the RPC_IF_ALLOW_SECURE_ONLY flag does not imply or guarantee a high level of privilege on the part of the calling user&quot; [@msdocs-ifflags] makes the explicit callback non-optional. 6. &lt;strong&gt;For DCOM-activated services&lt;/strong&gt;, accept the KB5004442 default (&lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; minimum) and do not invoke registry overrides. The override path was removed in the March 14, 2023 phase 3 rollout [@mssupport-kb5004442]. 7. &lt;strong&gt;For runtime visibility&lt;/strong&gt;, enable the Microsoft-Windows-RPC ETW provider via RPCMon [@rpcmon-repo] or RPC Investigator&apos;s RPC Sniffer [@tob-rpcinv-blog] [@rpcinv-repo]; correlate per-process per-procedure call rates against the service inventory from step 1. 8. &lt;strong&gt;For per-message kernel-level visibility&lt;/strong&gt;, enable the Microsoft-Windows-Kernel-ALPC system provider from an &lt;code&gt;EVENT_TRACE_SYSTEM_LOGGER_MODE&lt;/code&gt; session [@msdocs-etwsys]. Budget for the documented high-volume warning; consider an EDR vendor that runs the provider already if you do not want to host the collection yourself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// Real shell pipeline that produces the inputs:
//   Get-RpcServer | Export-Clixml -Path C:\\Snaps\\rpc-pre-patch.xml
//   
//   Get-RpcServer | Export-Clixml -Path C:\\Snaps\\rpc-post-patch.xml
//   Compare-Object (Import-Clixml C:\\Snaps\\rpc-pre-patch.xml) ...
// The diff logic below is what Compare-Object is doing under the hood, in plain JS.&lt;/p&gt;
&lt;p&gt;const pre = new Map([
  [&apos;201ef99a-7fa0-444c-9399-19ba84f12a1a&apos;, [&apos;Activate&apos;,&apos;Cancel&apos;,&apos;Continue&apos;,&apos;GetElevationType&apos;]],
  [&apos;86d35949-83c9-4044-b424-db363231fd0c&apos;, [&apos;SchRpcRegisterTask&apos;,&apos;SchRpcRetrieveTask&apos;,&apos;SchRpcSetSecurity&apos;]],
  [&apos;e1af8308-5d1f-11c9-91a4-08002b14a0fa&apos;, [&apos;ept_lookup&apos;,&apos;ept_map&apos;,&apos;ept_insert&apos;]],
]);&lt;/p&gt;
&lt;p&gt;const post = new Map([
  [&apos;201ef99a-7fa0-444c-9399-19ba84f12a1a&apos;, [&apos;Activate&apos;,&apos;Cancel&apos;,&apos;Continue&apos;,&apos;GetElevationType&apos;,&apos;RequestElevation2&apos;]],
  [&apos;86d35949-83c9-4044-b424-db363231fd0c&apos;, [&apos;SchRpcRegisterTask&apos;,&apos;SchRpcRetrieveTask&apos;,&apos;SchRpcSetSecurityV2&apos;]],
  [&apos;e1af8308-5d1f-11c9-91a4-08002b14a0fa&apos;, [&apos;ept_lookup&apos;,&apos;ept_map&apos;,&apos;ept_insert&apos;]],
]);&lt;/p&gt;
&lt;p&gt;const interfaces = new Set([...pre.keys(), ...post.keys()]);
for (const uuid of interfaces) {
  const a = new Set(pre.get(uuid) || []);
  const b = new Set(post.get(uuid) || []);
  const added   = [...b].filter(p =&amp;gt; !a.has(p));
  const removed = [...a].filter(p =&amp;gt; !b.has(p));
  if (added.length || removed.length) {
    console.log(`Interface ${uuid}`);
    if (added.length)   console.log(&apos;  + added:   &apos; + added.join(&apos;, &apos;));
    if (removed.length) console.log(&apos;  - removed: &apos; + removed.join(&apos;, &apos;));
  }
}
`}&lt;/p&gt;
&lt;p&gt;RPCMon ships a hard-coded RPC interface dictionary named &lt;code&gt;RPC_UUID_Map_Windows10_1909_18363.1977.rpcdb.json&lt;/code&gt; [@rpcmon-repo] -- a snapshot of Windows 10 1909 build 18363.1977 -- as the baseline against which it labels traced interfaces. The choice to bake in a build-specific baseline is evidence of how often the inventory needs refreshing: a defender running RPCMon on Windows 11 23H2 in 2026 is looking up call sites against a six-year-old dictionary. The accompanying tooling Forshaw built makes the regeneration mechanical in principle; the burden of &lt;em&gt;running&lt;/em&gt; the regeneration is what stays on the defender.&lt;/p&gt;

Install Forshaw&apos;s module and dump every local-only RPC interface on the current Windows install, one row per interface, sorted by procedure count:&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Install-Module NtObjectManager -Scope CurrentUser
Get-RpcServer -DbgHelpPath &quot;$env:ProgramFiles\Debugging Tools for Windows\dbghelp.dll&quot; |
  Where-Object { $_.Endpoints.ProtocolSequence -eq &apos;ncalrpc&apos; } |
  Sort-Object { $_.Procedures.Count } -Descending |
  Select-Object Name, InterfaceId, @{N=&apos;Procs&apos;;E={$_.Procedures.Count}} |
  Format-Table -AutoSize
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expect dozens of named interfaces on a clean Windows 11 install. Save the output, install Patch Tuesday, run it again, and &lt;code&gt;Compare-Object&lt;/code&gt; the two snapshots. That diff is the canonical research workflow that the December 2019 Project Zero post [@forshaw-rpc-2019] introduced.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;

The single most effective change an in-house LRPC author can make tomorrow morning is to move from `RpcServerRegisterIf2` with `IfCallbackFn = NULL` to `RpcServerRegisterIf3` with both an explicit per-interface security descriptor and a callback that explicitly validates caller identity. The migration is mechanical -- the function signatures are upward-compatible -- and the runtime check the `If3` API adds gives the application a per-call enforcement gate that does not depend on the application&apos;s callback being correct. Pair it with `RPC_IF_SEC_NO_CACHE` if the callback inspects token state that can change during a session (group membership, integrity level, AppContainer SID).
&lt;p&gt;The practical recipe answers the everyday question: what do I do tomorrow morning? The misconceptions section answers a harder question: what should I stop believing?&lt;/p&gt;
&lt;h2&gt;11. FAQ -- Six Misconceptions, Removed&lt;/h2&gt;
&lt;p&gt;Half the operational confusion about ALPC and LRPC comes from premises that sound plausible and are wrong. This section names six of them. Each answer starts with the wrong answer, explicitly, before correcting it.&lt;/p&gt;

Wrong answer: yes. Right answer: every service that exposes an LRPC interface is. Services that expose only `ncacn_np` (named-pipe RPC) or `ncacn_ip_tcp` (TCP RPC) are not reachable over ALPC, even when the caller is on the same machine [@msdocs-protseq]. The print spooler, for example, exposes its primary interface over named pipes and is the trigger for several of the named-pipe-Potato attacks; AppInfo, Task Scheduler, and the endpoint mapper expose theirs over LRPC and are reachable through the kernel ALPC fabric. The right mental model is &quot;every Windows service that wants to be reachable locally with first-class kernel-mediated transport uses LRPC on ALPC&quot;, not &quot;every service uses ALPC.&quot;

Wrong answer: yes. Right answer: the DCOM-activation Potatoes (RoguePotato [@roguepotato-blog] [@roguepotato-repo], JuicyPotato, RottenPotato) exercise LRPC-on-ALPC because local DCOM activation rides that fabric; the impersonation primitive is `RpcImpersonateClient` inside the activated COM server. The named-pipe Potatoes (EfsPotato, PrintSpoofer [@itm4n-printspoofer], PetitPotam) use `ImpersonateNamedPipeClient` [@msdocs-impnp] as the impersonation primitive and exercise the named-pipe fabric. The trigger transport can be shared (DCOM, RPRN, EFSR), but the impersonation primitive is what tells you which IPC surface the attack actually exercises. See Section 8 for the 30-second classifier and the HITB 2021 Pierini and Cocomazzi talk [@hitb-potatoes] for the canonical end-to-end family classification.

Wrong answer: yes. Several secondary writeups (and the original input premise for this article) say so. Right answer: named connection ports have Object Manager names, typically under `\RPC Control` or per-session AppContainer subtrees. The per-connection communication ports created by `NtAlpcAcceptConnectPort` are unnamed and exist only as handles. This is the structural correction Section 4 walks in full and the load-bearing invariant the Vista redesign rests on: only the parties that completed the handshake can address the per-connection channel. The kernel does not let anyone else find it because there is no name to find.

Wrong answer: yes, it is in the SDK. Right answer: partially. Microsoft *does not* publish a Win32 or WDK API reference for the `Nt*Alpc*` and `Alpc*` surface; the de facto syscall reference is NtDoc [@ntdoc-ntalpc], and the de facto structure reference is Geoff Chappell&apos;s site [@chappell-alpc] [@chappell-alpcp]. Microsoft *does* document ALPC architecturally in *Windows Internals 7th Edition Part 2* [@wininternals-7e], Chapter 8 section &quot;Advanced local procedure call (ALPC)&quot;; through the `Microsoft-Windows-Kernel-ALPC` ETW provider [@msdocs-etwsys]; and indirectly through the user-mode RPC runtime documentation. The documentation gap is a deliberate choice -- Microsoft&apos;s position is that application authors should use the RPC runtime, not the kernel ALPC API -- and the gap is the reason the public knowledge of ALPC comes from a handful of named researchers reverse-engineering it.

Wrong answer: yes, the abbreviations collide so they must be related. Right answer: LPC was the original Windows NT 3.1-through-Server-2003 kernel IPC primitive, replaced by ALPC in Vista (November 2006) and removed from the kernel by Windows 7 [@csandker-alpc]. LRPC is the Microsoft RPC runtime&apos;s *transport* selected when `ncalrpc` is the protocol sequence [@msdocs-protseq]; it has always lived inside `rpcrt4.dll`, and it rides on top of kernel ALPC ports. The two entities are at different layers (kernel object vs user-mode transport) and were named a decade apart -- LRPC in 1994, ALPC in 2006. The abbreviation collision is real; the entities are not the same thing.

Wrong answer: on the Trail of Bits blog. Right answer: it does not exist under that title. The input premise for this article (and several AI-generated summaries circulating in 2024-2025) referenced a *Trail of Bits &quot;ALPC Internals&quot; series* by Shafir. The Trail of Bits author page for Yarden Shafir [@tob-shafir-author] lists her actual posts; the kernel-IPC posts are *Introducing Windows Notification Facility&apos;s WNF Code Integrity* (May 2023) [@tob-wnf] and *ETW Internals for Security Research and Forensics* (November 2023) [@tob-etw]. Her dedicated ALPC material lives in her conference training surface, indexed via the Winsider Seminars author page [@winsider-yarden]. The cousin posts (WNF and ETW) are the right Trail of Bits citations for the architectural-cousin framing.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Three sources are worth the rest of an afternoon. Christian Sandker&apos;s three-part &lt;em&gt;Offensive Windows IPC&lt;/em&gt; series [@csandker-alpc] [@csandker-rpc] [@csandker-np] is the highest-signal practitioner walkthrough of LPC, ALPC, LRPC, and named pipes available for free on the open web. &lt;em&gt;Windows Internals 7th Edition Part 2&lt;/em&gt; Chapter 8 section &lt;em&gt;Advanced local procedure call (ALPC)&lt;/em&gt; [@wininternals-7e] is the Microsoft-blessed architectural reference; cite by ISBN 978-0-13-546238-6. James Forshaw&apos;s December 17, 2019 Project Zero post &lt;em&gt;Calling Local Windows RPC Servers from .NET&lt;/em&gt; [@forshaw-rpc-2019] is the canonical introduction to the &lt;code&gt;NtObjectManager&lt;/code&gt; tooling and the methodology change it unlocked. For the sister-article context in this series: the Object Manager Namespace post explains the &lt;code&gt;\RPC Control&lt;/code&gt; parent that every named ALPC connection port lives under, and the upcoming Potato sister post walks the DCOM-activation and named-pipe sub-families through to a working PoC.&lt;/p&gt;
&lt;/blockquote&gt;

The kernel did its job at the port-DACL layer. The application disclaimed responsibility at the interface-callback layer. Almost every Patch-Tuesday LRPC fix since 2018 is some recombination of those two halves, and the half the kernel cannot fix is the half that keeps shipping.
&lt;p&gt;The named-researcher canon for ALPC -- Forshaw, Shafir, csandker, Cerrudo, Cocomazzi, Pierini, Rouault, Imbert, Ormandy, Chappell -- is what this article is an attempt to read in one place.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;alpc-and-lrpc-the-local-ipc-fabric-under-every-windows-service&quot; keyTerms={[
  { term: &quot;ALPC&quot;, definition: &quot;Advanced Local Procedure Call. The Vista-and-later kernel asynchronous message-and-attribute IPC primitive; replaces classic LPC. Microsoft does not publish a developer-facing reference for the kernel surface.&quot; },
  { term: &quot;LRPC&quot;, definition: &quot;The Microsoft RPC runtime&apos;s local-only transport, selected when the protocol sequence is &lt;code&gt;ncalrpc&lt;/code&gt;. Implemented in &lt;code&gt;rpcrt4.dll&lt;/code&gt;; rides on top of ALPC ports.&quot; },
  { term: &quot;LPC&quot;, definition: &quot;Local Procedure Call. The original NT 3.1 kernel IPC primitive, synchronous, three-port; replaced by ALPC in Vista and removed from the kernel by Windows 7.&quot; },
  { term: &quot;Connection port (ALPC)&quot;, definition: &quot;The named ALPC port a server creates so clients can find it. Lives in the Object Manager namespace, typically under &lt;code&gt;\\RPC Control&lt;/code&gt;.&quot; },
  { term: &quot;Communication port (ALPC)&quot;, definition: &quot;The unnamed per-connection ALPC port created by &lt;code&gt;NtAlpcAcceptConnectPort&lt;/code&gt;. Exists only as handles in the connecting and accepting processes; not reachable by name.&quot; },
  { term: &quot;Message attribute&quot;, definition: &quot;An optional in-message kernel service: Context, Handle, Security, or View. Each retires an awkward LPC pattern by moving the work into a single ALPC transaction.&quot; },
  { term: &quot;Interface security callback&quot;, definition: &quot;The application-supplied &lt;code&gt;IfCallbackFn&lt;/code&gt; passed to &lt;code&gt;RpcServerRegisterIf2&lt;/code&gt;/&lt;code&gt;RpcServerRegisterIf3&lt;/code&gt;. The kernel cannot inspect or constrain it. NULL is a legal value and means &apos;no callback&apos;.&quot; },
  { term: &quot;Endpoint mapper&quot;, definition: &quot;The well-known LRPC service at &lt;code&gt;\\RPC Control\\epmapper&lt;/code&gt; that translates an interface UUID into the endpoint name a service is listening on. Hosted by &lt;code&gt;rpcss&lt;/code&gt;.&quot; },
  { term: &quot;NDR / NDR64&quot;, definition: &quot;The (Network) Data Representation transfer syntax that MIDL-generated stubs use to marshal RPC arguments. Local LRPC and remote MSRPC use the same wire format.&quot; },
  { term: &quot;SeImpersonatePrivilege&quot;, definition: &quot;Windows user-right that permits a thread to impersonate another security principal via APIs such as &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt;. The privilege the named-pipe-Potato family abuses.&quot; }
]} questions={[
  { q: &quot;Why does the per-connection ALPC communication port have no Object Manager name?&quot;, a: &quot;So that no third party can address the channel. Only the parties that completed the handshake hold the paired handles; the kernel does not expose the unnamed port through any namespace operation. This is the half of Cerrudo&apos;s 2006 structural class the Vista redesign closed.&quot; },
  { q: &quot;Why can the OS not enforce the correctness of an interface security callback?&quot;, a: &quot;The callback is a function pointer into application code. The kernel cannot symbolically execute the function to determine whether its return value is correct, and even if it could, the kernel does not know what &apos;correct&apos; means for an arbitrary application&apos;s authorization policy. Closing the gap requires either a declarative authorization ABI or a sandbox; Microsoft has not publicly committed to either.&quot; },
  { q: &quot;What distinguishes a DCOM-activation Potato from a named-pipe Potato?&quot;, a: &quot;The impersonation primitive. DCOM-activation Potatoes (RoguePotato, JuicyPotato, RottenPotato) use &lt;code&gt;RpcImpersonateClient&lt;/code&gt; inside an LRPC-on-ALPC dispatch path. Named-pipe Potatoes (PrintSpoofer, EfsPotato, PetitPotam) use &lt;code&gt;ImpersonateNamedPipeClient&lt;/code&gt; on a named pipe. The trigger transport (DCOM, RPRN, EFSR) can be shared; the impersonation primitive is what determines which IPC surface the attack exercises.&quot; },
  { q: &quot;What changed in March 2023 for DCOM-activated services?&quot;, a: &quot;KB5004442 phase 3 enabled the DCOM hardening with no override path. &lt;code&gt;RPC_C_AUTHN_LEVEL_PKT_INTEGRITY&lt;/code&gt; is now a mandatory minimum for DCOM activations, and the previously available registry override is removed. The change closed the JuicyPotato variant at the OS-default configuration.&quot; },
  { q: &quot;Where can a defender see ALPC traffic at the per-message level?&quot;, a: &quot;From the &lt;code&gt;Microsoft-Windows-Kernel-ALPC&lt;/code&gt; system ETW provider, enabled in an &lt;code&gt;EVENT_TRACE_SYSTEM_LOGGER_MODE&lt;/code&gt; session. The provider is high-volume; production SOC pipelines rarely subscribe directly and instead rely on EDR vendors that gate the provider behind antimalware-PPL processes.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-internals</category><category>alpc</category><category>lrpc</category><category>ipc</category><category>privilege-escalation</category><category>rpc</category><category>reverse-engineering</category><category>security</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>Adminless: How Windows Finally Made Elevation a Security Boundary</title><link>https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/</link><guid isPermaLink="true">https://paragmali.com/blog/adminless-how-windows-finally-made-elevation-a-security-boun/</guid><description>Administrator Protection replaces UAC with a system-managed admin account created per elevation, gated by Windows Hello, and destroyed when the job is done.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Administrator Protection (informally &quot;Adminless&quot;) replaces Windows 11&apos;s split-token UAC with a separate, system-managed local user account.** The operating system creates this **System Managed Administrator Account (SMAA)** per local admin, links it to the primary admin via paired SAM attributes, and uses it to host elevated processes in a fresh logon session gated by Windows Hello. The kernel asks LSA to authenticate &quot;a new instance of the shadow administrator&quot; without any SMAA credential because the SMAA has none. The mechanism makes the elevation path a security boundary for the first time, with bulletin-grade fixes when it fails. Microsoft shipped it in KB5067036 on October 28, 2025, then reverted it on December 1, 2025 over an application-compatibility issue, not a security failure. This article walks the twenty-year argument that produced the design, the nine pre-GA bypasses Forshaw found and Microsoft fixed, and exactly where the new boundary still leaks.
&lt;h2&gt;1. Two tokens, one user, twenty years&lt;/h2&gt;
&lt;p&gt;Open an elevated console on a Windows 11 device with the registry value &lt;code&gt;TypeOfAdminApprovalMode = 2&lt;/code&gt; set, and run &lt;code&gt;whoami /all&lt;/code&gt;. The user name is no longer yours. It is &lt;code&gt;ADMIN_&amp;lt;sixteen random characters&amp;gt;&lt;/code&gt; -- a local account you never created, owned by an operating-system component you never ran, in a logon session that did not exist five seconds ago and will not exist five seconds after the console closes.&lt;/p&gt;
&lt;p&gt;For twenty years, an elevated Windows command prompt reported the same user name as the unelevated one. The integrity level changed. The token changed. The user did not. That single architectural fact is the load-bearing premise of every UAC bypass ever published. The Vista User Account Control design from 2006 issued two tokens at logon for a member of the local Administrators group: a filtered standard-user token for everyday work, and a full admin token linked to it via the &lt;code&gt;TokenLinkedToken&lt;/code&gt; field [@ms-uac-how-it-works]. When the user clicked Yes on a consent prompt, the Application Information service called &lt;code&gt;CreateProcessAsUser&lt;/code&gt; with the linked token. Same user. Same profile. Same &lt;code&gt;HKCU&lt;/code&gt;. Same logon session. Different integrity level.&lt;/p&gt;
&lt;p&gt;Four resources stayed shared between the filtered and full tokens, and four categories of attack grew out of them. Files dropped in a writable directory the elevated process trusts. Registry values planted under &lt;code&gt;HKEY_CURRENT_USER&lt;/code&gt; that an elevated binary reads before it consults &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt;. COM elevation monikers that hand the attacker an elevated &lt;code&gt;IFileOperation&lt;/code&gt; interface. Path-resolution overrides that redirect &lt;code&gt;%SystemRoot%&lt;/code&gt; for a single auto-elevating process. The UACMe project [@uacme] catalogues 81 such methods, each one a load against the shared-resource shape of Vista&apos;s split token.&lt;/p&gt;
&lt;p&gt;Administrator Protection inverts that shape. The elevated administrator becomes a &lt;em&gt;different account&lt;/em&gt; with a different security identifier, a different profile directory, a different &lt;code&gt;NTUSER.DAT&lt;/code&gt; hive, a different authentication-ID LUID, and a different DOS device object directory under &lt;code&gt;\Sessions\0\DosDevices\&lt;/code&gt;. The operating system manages the account itself. It is created on demand the first time the policy is enabled, linked to the primary admin via paired Security Account Manager attributes, used in a fresh logon session for every elevation, and the elevated token is destroyed when the process exits [@ms-developer-blog-2025, @call4cloud-osint].&lt;/p&gt;
&lt;p&gt;The feature ships under four names -- &lt;strong&gt;Administrator Protection&lt;/strong&gt; in Microsoft Learn, &lt;strong&gt;Adminless&lt;/strong&gt; as the community shorthand this article uses, &lt;strong&gt;ShadowAdmin&lt;/strong&gt; in the &lt;code&gt;samsrv.dll&lt;/code&gt; engineering symbols, &lt;strong&gt;System Managed Administrator Account (SMAA)&lt;/strong&gt; in the Windows Developer Blog [@ms-admin-protection, @ms-developer-blog-2025, @call4cloud-osint] -- and §6 walks each in turn. The launch arc was short: announced at Ignite 2024 by David Weston on November 19, 2024 [@bleepingcomputer-2024], surfaced earlier that fall in Insider Preview build 27718 on October 2, 2024 [@ms-insider-build-27718], shipped to stable Windows in KB5067036 on October 28, 2025 [@ms-kb5067036], and disabled on December 1, 2025 over a WebView2 application-compatibility regression [@forshaw-pz-jan2026, @ms-admin-protection].&lt;/p&gt;
&lt;p&gt;This article walks what changed and what did not. By the end you will know exactly which UAC bypass families are dead, exactly which survive, exactly what the December 2025 revert was about, and exactly where the new boundary still leaks. The path runs through twenty years of design tradeoffs and seven years of binary-level fixes that never converged on a real boundary. It runs through nine Project Zero bypasses Microsoft fixed before shipping. It ends at a question Microsoft&apos;s own design documents do not yet answer: when the prompt is a credential gate instead of a click-through, what is left for the attacker to do?&lt;/p&gt;
&lt;p&gt;The first thing to understand is what UAC was trying to do, and why Microsoft said for twenty years it was not a security boundary.&lt;/p&gt;
&lt;h2&gt;2. &quot;Convenience, not boundary&quot;: UAC as Microsoft conceived it&lt;/h2&gt;
&lt;p&gt;Why did Vista ship UAC at all? For most of Windows history, every interactive logon for a member of the local Administrators group produced one full-admin token. The desktop shell ran as a full administrator. Every child process inherited those rights. The worm era of 2003 to 2005 demonstrated, repeatedly, that one process running in user context owned the whole machine. By 2006 the cost of admin-by-default had become impossible to defend [@wikipedia-uac].The pre-Vista &lt;em&gt;Limited User Account&lt;/em&gt; (LUA) was Microsoft&apos;s first attempt at a fix. The conceptual ancestor of the filtered token failed in practice because roughly half of the third-party application base broke under it, and the documented workaround -- &lt;code&gt;RUNAS.EXE&lt;/code&gt; -- was operationally hostile enough that almost no one used it.&lt;/p&gt;
&lt;p&gt;The redesign that produced UAC pivoted on a single observation. Forcing administrators to run as standard users had failed because too much software assumed admin rights. So Vista would give each admin user &lt;em&gt;two&lt;/em&gt; identities. One would be standard-user enough to run the desktop, the browser, and the day-to-day applications without privilege. The other would carry the admin rights, and the operating system would arrange for the user to opt into it on a per-task basis.&lt;/p&gt;
&lt;p&gt;Mark Russinovich&apos;s June 2007 article &lt;em&gt;Inside Windows Vista User Account Control&lt;/em&gt; in TechNet Magazine [@russinovich-2007-vista] remains the canonical reference for the design. The mechanism is two tokens at logon; the integrity-level taxonomy (Low, Medium, High, System) gating object access; file-system and registry virtualisation rerouting writes by legacy apps; and Mandatory Integrity Control enforcing the no-write-up rule at the kernel-object boundary.&lt;/p&gt;

The mechanism by which Vista UAC assigns two distinct access tokens to a single interactive logon for a member of the local Administrators group. The Local Security Authority issues both at logon: a filtered standard-user token with most privileges removed and the Administrators group marked as deny-only, and a linked full administrator token referenced from the filtered token&apos;s `TokenLinkedToken` field [@ms-uac-how-it-works].
&lt;p&gt;The disclaimer that follows the design is the single most quoted sentence Russinovich ever published about UAC. The article will lift it verbatim once, because every Administrator Protection design decision falls out of its absence:&lt;/p&gt;

It&apos;s important to be aware that UAC elevations are conveniences and not security boundaries. -- Mark Russinovich, *Inside Windows Vista User Account Control*, TechNet Magazine, June 2007 [@russinovich-2007-vista]
&lt;p&gt;This is not an accidental disclaimer. It is the canonical Microsoft classification, preserved into the Microsoft Security Servicing Criteria document [@msrc-servicing-criteria]. James Forshaw of Google Project Zero, writing in January 2026, re-states the position verbatim: &quot;due to the way it was designed, it was quickly apparent it didn&apos;t represent a hard security boundary, and Microsoft downgraded it to a security feature&quot; [@forshaw-pz-jan2026]. The classification is what determined what Microsoft would and would not pay attention to. A &quot;security boundary&quot; gets a security bulletin when an attacker crosses it. A &quot;security feature&quot; does not. A bypass of a boundary is a vulnerability. A bypass of a feature is a quality bug. For twenty years, UAC bypasses were quality bugs.&lt;/p&gt;
&lt;p&gt;The two-tokens-at-logon mechanism is the shape from which the entire bypass canon grows. The twenty years of evolution that follow run along a single timeline.&lt;/p&gt;

timeline
    title Privilege separation in Windows, NT 3.1 to Administrator Protection
    1993 : NT 3.1 ships multi-user accounts and DACLs but admin-by-default desktop culture
    2006 : Vista UAC introduces the split-token model and Mandatory Integrity Control
    2009 : Davidson publishes the first UAC bypass; Windows 7 ships auto-elevation
    2014 : hfiref0x&apos;s UACMe catalogue collects the bypass canon
    2016 : enigma0x3 publishes the registry-hijack family (eventvwr, fodhelper, sdclt)
    2019 : CVE-2019-1388 (consent.exe certificate dialog) is the lone UAC LPE bulletin
    2024 : Insider Preview build 27718 surfaces Administrator Protection; Ignite 2024 announces it
    2025 : KB5067036 ships the SMAA on stable Windows, then reverts on December 1
    2026 : Forshaw&apos;s nine pre-GA bypasses all fixed; the elevation path is now a security boundary
&lt;p&gt;To see why the entire bypass canon grew out of the split-token shape, the next section walks the mechanic at function-name granularity. It is the load-bearing pre-history of everything that comes after.&lt;/p&gt;
&lt;h2&gt;3. The Vista UAC split-token in detail&lt;/h2&gt;
&lt;p&gt;The mechanics at logon. The Local Security Authority Subsystem Service (LSASS) validates credentials. For a user in the local Administrators group, it constructs two tokens. The filtered token has its dangerous privileges removed and the Administrators SID marked deny-only; the full token retains them. The Token Manager wires the filtered token&apos;s &lt;code&gt;TokenLinkedToken&lt;/code&gt; field to a handle on the full token. LSASS hands the filtered token to &lt;code&gt;winlogon.exe&lt;/code&gt;. Winlogon launches &lt;code&gt;userinit.exe&lt;/code&gt;. Userinit launches &lt;code&gt;explorer.exe&lt;/code&gt;. The shell, holding the filtered token, becomes the parent process from which every user-initiated process inherits [@ms-uac-how-it-works].&lt;/p&gt;

The kernel structure that connects the filtered standard-user token to the linked full administrator token in Vista&apos;s split-token model. A process holding the filtered token can read the `TokenLinkedToken` field via the `GetTokenInformation` API to discover the handle of the full token, and pass that handle to `CreateProcessAsUser` to launch an elevated child. The same link is the structural premise of token-stealing attacks: any code path that can read or impersonate the linked token bypasses the consent UI entirely [@ms-uac-how-it-works, @forshaw-pz-jan2026].
&lt;p&gt;The shell shares four resources with anything launched under the full token.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The same user security identifier.&lt;/strong&gt; Both tokens carry the same primary SID. Files, registry keys, and kernel objects that grant access to the user grant identical access to both processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The same &lt;code&gt;%USERPROFILE%&lt;/code&gt; directory tree.&lt;/strong&gt; &lt;code&gt;C:\Users\&amp;lt;user&amp;gt;\&lt;/code&gt; is the home of both. The Documents folder, the Downloads folder, the AppData hives, and any application-specific subdirectory belong to one user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The same &lt;code&gt;HKEY_CURRENT_USER&lt;/code&gt; hive.&lt;/strong&gt; Both tokens map &lt;code&gt;HKCU&lt;/code&gt; to the same &lt;code&gt;NTUSER.DAT&lt;/code&gt; file. An elevated process that reads a user setting reads the value the unelevated user wrote.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The same logon-session LUID.&lt;/strong&gt; The Locally Unique Identifier that identifies an interactive logon session is the same on both tokens. The kernel uses that LUID as a key for per-logon-session caching: the DOS device object directory at &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;LUID&amp;gt;&lt;/code&gt;, drive-letter mappings, mapped network drives, and the credential cache.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The elevation pipeline. A user clicks Yes on a UAC prompt. The mechanism beneath that click runs through a chain of named function calls.&lt;/p&gt;

sequenceDiagram
    participant User as User shell (filtered token)
    participant AppInfo as appinfo.dll (Application Information service)
    participant Consent as consent.exe (secure desktop)
    participant LSA as LSASS
    participant New as Elevated child process&lt;pre&gt;&lt;code&gt;User-&amp;gt;&amp;gt;AppInfo: ShellExecute / CreateProcess &quot;as admin&quot;
AppInfo-&amp;gt;&amp;gt;AppInfo: RAiLaunchAdminProcess RPC
AppInfo-&amp;gt;&amp;gt;AppInfo: Read manifest requestedExecutionLevel
AppInfo-&amp;gt;&amp;gt;AppInfo: Check ConsentPromptBehaviorAdmin
AppInfo-&amp;gt;&amp;gt;Consent: Launch consent.exe on Winlogon desktop
Consent-&amp;gt;&amp;gt;User: Show Yes / No prompt
User--&amp;gt;&amp;gt;Consent: Click Yes
Consent--&amp;gt;&amp;gt;AppInfo: Approved
AppInfo-&amp;gt;&amp;gt;LSA: Resolve TokenLinkedToken handle
AppInfo-&amp;gt;&amp;gt;New: CreateProcessAsUser(linked full token)
Note over New: Same SID and profile and HKCU and logon session
Note over New: Integrity level High
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The prompt runs on the &lt;em&gt;secure desktop&lt;/em&gt;, the same Winlogon-owned &lt;code&gt;Winsta0\Winlogon&lt;/code&gt; desktop where the credential-entry dialog appears at logon, not the user&apos;s interactive &lt;code&gt;Winsta0\Default&lt;/code&gt; desktop [@ms-uac-how-it-works]. User Interface Privilege Isolation (UIPI) blocks lower-integrity input from reaching higher-integrity windows; the secure-desktop switch is its first defence against synthetic-keystroke attacks against the prompt itself.The secure desktop is not invulnerable. It changes the integrity-isolation context, but a process holding the filtered token can still trigger the switch (that is the whole point of clicking Yes), and code running before the switch can in principle modify the surrounding UI state. CVE-2019-1388 in late 2019 turned out to exploit a different aspect entirely -- a UI-interaction path through the consent.exe certificate-viewer dialog -- and not the secure-desktop switch itself.&lt;/p&gt;
&lt;p&gt;Compare this to what comes next. Both tokens share four resources. Each of those resources is a category of attack waiting for a researcher to find it. The next section is the story of what happened when Microsoft tried to make UAC less annoying by silently elevating its own Microsoft-signed binaries -- and what the bypass canon did with the change.&lt;/p&gt;
&lt;h2&gt;4. Windows 7 auto-elevation and the birth of the bypass canon&lt;/h2&gt;
&lt;p&gt;A specific moment. December 2009. Leo Davidson publishes &lt;em&gt;Windows 7 UAC whitelist: Code-injection Issue / Anti-Competitive API / Security Theatre&lt;/em&gt; on pretentiousname.com [@davidson-2009]. The title is the argument. The page itself is sprawling, contentious, and on a few key technical points exactly right. Microsoft&apos;s response, in Davidson&apos;s own words: &quot;this is a non-issue, and ignored my offers to give them full details for several months.&quot; Microsoft Security Essentials eventually classified the &lt;em&gt;binary&lt;/em&gt; (not the technique) as &lt;code&gt;HackTool:Win32/Welevate.A&lt;/code&gt; and &lt;code&gt;HackTool:Win64/Welevate.A&lt;/code&gt;; in Davidson&apos;s pointed observation, &quot;recompiling the binaries in VS2010 means they are no longer detected&quot; [@davidson-2009].Davidson kept writing into his original page over the following decade. A marker buried inside the text reads &quot;As I was typing more words into this page, this appeared in my text editor at the 10,000th word!&quot; In March 2020 he removed the proof-of-concept binaries, noting &quot;I got sick of the page being marked as malware, even by Google (FFS).&quot; The prose remains the canonical first source on UAC bypasses [@davidson-2009].&lt;/p&gt;
&lt;p&gt;What Windows 7 added, in October 2009, to fix Vista&apos;s prompt-fatigue problem [@russinovich-2009-win7]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;autoElevate=true&lt;/code&gt; manifest attribute, embedded in selected Microsoft-signed Windows binaries.&lt;/li&gt;
&lt;li&gt;An internal whitelist of Microsoft-signed binaries living under &lt;code&gt;%SystemRoot%\System32&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;COM Elevation Moniker&lt;/strong&gt; -- already shipping in Vista (&lt;code&gt;BIND_OPTS3&lt;/code&gt;, syntax &lt;code&gt;Elevation:Administrator!new:&amp;lt;CLSID&amp;gt;&lt;/code&gt;) -- was the activation primitive. Windows 7 extended &lt;em&gt;implicit&lt;/em&gt; auto-elevation to qualifying COM servers whose registrations matched the new whitelist criteria, so callers such as &lt;code&gt;IFileOperation&lt;/code&gt;, &lt;code&gt;ICMLuaUtil&lt;/code&gt;, and &lt;code&gt;IColorDataProxy&lt;/code&gt; could be launched elevated without a consent prompt under the Win7 model [@russinovich-2009-win7, @uacme]. The dedicated registry-curation surface, the &lt;code&gt;COMAutoApprovalList&lt;/code&gt; (&lt;code&gt;HKLM\Software\Microsoft\Windows NT\CurrentVersion\UAC\COMAutoApprovalList&lt;/code&gt;) that UACMe Method 49 references verbatim, did &lt;em&gt;not&lt;/em&gt; ship in Windows 7; it was introduced seven years later in Windows 10 RS1 (build 14393, August 2016) as a Redstone-1 hardening that replaced implicit COM auto-elevation with explicit list curation [@uacme].&lt;/li&gt;
&lt;li&gt;The default consent-prompt behaviour &lt;code&gt;ConsentPromptBehaviorAdmin = 5&lt;/code&gt;: prompt for consent for non-Windows binaries [@russinovich-2009-win7].&lt;/li&gt;
&lt;/ol&gt;

The Windows 7 mechanism by which selected Microsoft-signed binaries elevate without showing the consent prompt to a user who is a member of the local Administrators group. The Application Information service consults a whitelist of signature, path, and manifest attributes; if the binary qualifies, `appinfo.dll` calls `CreateProcessAsUser` with the linked full token and no UI step at all [@russinovich-2009-win7].

A COM activation syntax introduced in Windows Vista that lets an unelevated caller request an elevated instance of a COM server class. The `IBindCtx` is augmented with a `BIND_OPTS3` structure carrying a window handle to attribute the prompt to. The bind moniker `Elevation:Administrator!new:&amp;lt;CLSID&amp;gt;` causes the COM Service Control Manager to launch the server elevated. UACMe methods that target `IFileOperation`, `ICMLuaUtil`, and `IColorDataProxy` all descend from this mechanism [@russinovich-2009-win7, @uacme].
&lt;p&gt;Davidson&apos;s technique against the new whitelist is one paragraph of detail. Use the &lt;code&gt;IFileOperation&lt;/code&gt; COM elevation moniker, which itself auto-elevates, to write a planted &lt;code&gt;CRYPTBASE.DLL&lt;/code&gt; into &lt;code&gt;%SystemRoot%\System32\sysprep\&lt;/code&gt;. The path is a writable destination from the limited token because &lt;code&gt;IFileOperation&lt;/code&gt; runs elevated. Then launch &lt;code&gt;sysprep.exe&lt;/code&gt;, which is auto-elevated as a Microsoft-signed binary in System32. Sysprep loads &lt;code&gt;CRYPTBASE.DLL&lt;/code&gt; from its own directory before the system path. The attacker&apos;s DLL runs at High integrity in the elevated sysprep process [@davidson-2009, @uacme]. No prompt. The whitelist did the work.&lt;/p&gt;
&lt;p&gt;The bypass canon. Davidson&apos;s technique was the start, not the totality. The successors walked the same shape across families.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The DLL side-load family.&lt;/strong&gt; Sysprep was the canonical instance. Subsequent variants targeted &lt;code&gt;cliconfg.exe&lt;/code&gt;, &lt;code&gt;mcx2prov.exe&lt;/code&gt;, &lt;code&gt;migwiz.exe&lt;/code&gt;, and &lt;code&gt;setupsqm.exe&lt;/code&gt; -- each an auto-elevating Microsoft binary that loaded a DLL from a writable directory before consulting the system path. Microsoft removed the auto-elevation attribute from many of these binaries over the Windows 10 1709 cycle, but did so one binary at a time [@uacme].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The registry-hijack family.&lt;/strong&gt; Matt Nelson&apos;s August 2016 disclosure of an &lt;code&gt;eventvwr.exe&lt;/code&gt; plus &lt;code&gt;HKCU\Software\Classes\mscfile\shell\open\command&lt;/code&gt; bypass [@enigma0x3-2016-eventvwr] established the pattern. An auto-elevating binary consults &lt;code&gt;HKEY_CURRENT_USER&lt;/code&gt; before &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; for a value the binary trusts to dispatch a child process. The limited user, who owns &lt;code&gt;HKCU&lt;/code&gt;, writes whatever they want into the value. The elevated binary executes the attacker&apos;s command line. March 2017 produced &lt;code&gt;sdclt.exe&lt;/code&gt; plus App Paths [@enigma0x3-2017-app-paths] and &lt;code&gt;sdclt.exe&lt;/code&gt; plus &lt;code&gt;IsolatedCommand&lt;/code&gt; [@enigma0x3-2017-sdclt]; May 2017 produced the &lt;code&gt;fodhelper.exe&lt;/code&gt; plus &lt;code&gt;ms-settings&lt;/code&gt; variant [@uacme]. All fileless. All generalising to any auto-elevating binary that walks &lt;code&gt;HKCU&lt;/code&gt; before &lt;code&gt;HKCR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The COM-elevation-moniker abuse family.&lt;/strong&gt; UACMe&apos;s Method 1 (Davidson&apos;s original &lt;code&gt;IFileOperation&lt;/code&gt;) ages into Methods 41 (&lt;code&gt;ICMLuaUtil&lt;/code&gt;, Oddvar Moe, via &lt;code&gt;ucmCMLuaUtilShellExecMethod&lt;/code&gt;) and 43 (&lt;code&gt;IColorDataProxy&lt;/code&gt; paired with &lt;code&gt;ICMLuaUtil&lt;/code&gt;, Oddvar Moe derivative, via &lt;code&gt;ucmDccwCOMMethod&lt;/code&gt;), each one a different COM interface that auto-elevates and exposes a method useful for arbitrary file or registry write [@uacme].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The environment-variable and path-poisoning family.&lt;/strong&gt; Per-process &lt;code&gt;%windir%&lt;/code&gt; or &lt;code&gt;%SystemRoot%&lt;/code&gt; redirection via registry shims and Image File Execution Options, redirecting auto-elevating binaries to load resources from attacker-controlled directories.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The Windows 7 auto-elevation whitelist &lt;em&gt;was&lt;/em&gt; the bypass. The day Microsoft shipped a class of binaries that could elevate silently based on signing and path, the entire problem of UAC bypass reduced to &quot;make one of those binaries do something the attacker wants it to do.&quot; Every UACMe method that targets a Microsoft-signed binary in &lt;code&gt;System32&lt;/code&gt; descends from this design choice. The 81-method catalogue is not a list of separate vulnerabilities; it is one architectural mistake spreading through the binary inventory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Enter &lt;strong&gt;hfiref0x&apos;s UACMe&lt;/strong&gt; [@uacme]. The project has been on GitHub since 2014. It currently lists 81 named methods. Each entry pairs the method number with the author credit, the target binary, the technique class, and the &quot;Fixed in&quot; build number. The README, taken together, is the institutional memory of UAC&apos;s failure as a boundary. Forshaw&apos;s January 2026 framing is the operational summary: &quot;A good repository of known bypasses is the UACMe tool which currently lists 81 separate techniques for gaining administrator privileges&quot; [@forshaw-pz-jan2026].&lt;/p&gt;
&lt;p&gt;Microsoft chose to fix individual bypasses rather than redesign the model. The next section asks whether seven years of fixes ever caught up.&lt;/p&gt;
&lt;h2&gt;5. 2017-2024: incremental hardening, no convergence&lt;/h2&gt;
&lt;p&gt;The middle Windows 10 era was the moment Microsoft treated UAC bypasses as a quality problem and shipped fixes at quality-fix cadence, not security-bulletin cadence. The work was real, but it was always one binary or one interface at a time.&lt;/p&gt;
&lt;p&gt;The named milestones, kept short.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows 10 1709 (October 2017).&lt;/strong&gt; Beginning with this build, &lt;code&gt;IFileOperation&lt;/code&gt; auto-elevation for callers other than Explorer was restricted [@uacme]. The originating Davidson 2009 family of bypasses, against the sysprep + planted-CRYPTBASE shape, ceased to function for processes other than the shell itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tighter &lt;code&gt;appinfo.dll&lt;/code&gt; manifest parsing across multiple Windows 10 builds.&lt;/strong&gt; Stricter binary-signature checks. Stricter path checks. Stricter manifest checks. Each of these closed individual bypass methods; none of them closed a family.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-binary hardening recorded in UACMe&apos;s &quot;Fixed in&quot; column.&lt;/strong&gt; UACMe version 3.5.0 retired roughly eighty percent of the 2014-vintage catalogue as obsolete; the v3.2.x branch retains the full historical record. The project&apos;s README warns that &quot;since version 3.5.0, all previously &apos;fixed&apos; methods are considered obsolete and have been removed. If you need them, use v3.2.x branch&quot; [@uacme].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2019-1388 (November 2019; reporter: Eduardo Braun Prado via Trend Micro&apos;s Zero Day Initiative).&lt;/strong&gt; The lone departure from the &quot;UAC bypasses get no CVE&quot; rule. A UI-interaction path through &lt;code&gt;consent.exe&lt;/code&gt;&apos;s certificate-viewer dialog: an unsigned application could trigger consent.exe to display a certificate dialog whose &quot;View Certificate&quot; link launched Internet Explorer running as &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt;, and IE&apos;s File menu opened &lt;code&gt;cmd.exe&lt;/code&gt; at the same integrity level [@nvd-cve-2019-1388]. Microsoft fixed it on the November 2019 Patch Tuesday and gave it an LPE bulletin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CVE-2019-1388 was a &lt;em&gt;prompt-UI&lt;/em&gt; bug -- specifically, a crash-path that surfaced an IE process at SYSTEM integrity via the certificate viewer -- not a UAC-bypass bug in the categorical sense. The classification distinction matters: Microsoft did not change its position that UAC was not a boundary; the bulletin treated this as a separate UI defect that incidentally crossed the boundary. CISA later added the CVE to the Known Exploited Vulnerabilities Catalog [@nvd-cve-2019-1388].&lt;/p&gt;
&lt;p&gt;The accumulating evidence by 2024 was three observations.&lt;/p&gt;
&lt;p&gt;UACMe&apos;s catalogue has grown from its 2014 origins to 81 methods today [@uacme]. Each &lt;em&gt;family&lt;/em&gt; of attack survived the &lt;em&gt;individual&lt;/em&gt; fixes. As Davidson predicted in 2009, the auto-elevation whitelist was the structural problem; patching each whitelisted binary as a separate bug was a treadmill, not a convergence.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s own Security Servicing Criteria continued to classify UAC as a security feature, not a boundary, throughout the period [@msrc-servicing-criteria, @forshaw-pz-jan2026]. The decision was load-bearing. Fixing the elevation pipeline at &lt;em&gt;quality&lt;/em&gt; cadence meant accepting that bypasses would appear quarterly and would not appear in the Patch Tuesday bulletins until the day Microsoft changed its mind about the classification.&lt;/p&gt;
&lt;p&gt;The third piece of evidence is what the attackers were doing while the defenders were churning the binary list. Microsoft&apos;s own number, quoted by the Windows Developer Blog from the Microsoft Digital Defense Report 2024, is &lt;em&gt;39,000 token-theft incidents per day&lt;/em&gt; [@ms-developer-blog-2025]. A token, once stolen from an elevated process, requires no further bypass: it is a bearer credential good for the lifetime of the logon session. The same logon session is the one the unelevated user and the elevated process share under the split-token model. The &quot;one logon session&quot; property of UAC&apos;s design is the structural premise that token theft depends on.&lt;/p&gt;
&lt;p&gt;There is one further thread worth naming here. Forshaw&apos;s broader 2022 Kerberos work in the user-credential-delegation space is a thread that survives the elevation-redesign question entirely. The May 2022 &lt;em&gt;Exploiting RBCD using a normal user account&lt;/em&gt; post [@forshaw-2022-rbcd] is the representative artifact. Network-credential delegation primitives -- Resource-Based Constrained Delegation, User-to-User Kerberos, S4U2Self -- operate at a layer beneath token-level elevation, and survive even a perfect SMAA design because they do not run through the elevation path at all.&lt;/p&gt;
&lt;p&gt;Piecewise fixes never converged on a boundary. The question that drove the next five years of Microsoft work was the obvious one: if the issue is the shared-resource model itself, what is the smallest plausible change that fixes it?&lt;/p&gt;
&lt;h2&gt;6. The breakthrough: the System Managed Administrator Account&lt;/h2&gt;
&lt;p&gt;The load-bearing design decision is one sentence. Stop trying to make one user account play both roles. The elevated administrator should be a different account with a different SID, a different profile, a different &lt;code&gt;HKCU&lt;/code&gt;, a different logon session, and a different DOS device object directory -- and the operating system should manage that account itself.&lt;/p&gt;
&lt;p&gt;What is striking about the design is how prosaic the underlying mechanism is. Multi-user accounts have shipped with Windows NT since version 3.1 in 1993. The architecture for running an elevated process under a separate local user has been present in NT for thirty-three years. What changed is that Microsoft finally chose to &lt;em&gt;enforce&lt;/em&gt; the multi-user model for privilege separation, by making the operating system itself create and manage the second account, link it to the primary admin via paired Security Account Manager attributes, and use it for every elevation. The sophistication is in linkage, in lifecycle, and in &lt;em&gt;removing auto-elevation&lt;/em&gt;, not in any single new primitive.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The thing that changes between UAC and Administrator Protection is not the elevation &lt;em&gt;mechanism&lt;/em&gt; (a manifest, a prompt, a &lt;code&gt;CreateProcessAsUser&lt;/code&gt; call) but the elevation &lt;em&gt;classification&lt;/em&gt;. An elevation bypass used to be a quality bug. It is now a security-bulletin vulnerability. Every Administrator Protection design decision -- separate account, fresh logon session, removed auto-elevation, Hello-gated consent -- is a consequence of the classification change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The names. Microsoft Learn&apos;s term is &lt;strong&gt;Administrator Protection&lt;/strong&gt; [@ms-admin-protection]. Microsoft&apos;s announcement material at Ignite 2024 and in the Insider Preview build 27718 post uses the same &quot;Administrator Protection&quot; label [@ms-insider-build-27718]; &lt;strong&gt;Adminless&lt;/strong&gt; is the community shorthand that stuck. The internal engineering term in &lt;code&gt;samsrv.dll&lt;/code&gt; (the Security Account Manager service DLL) is &lt;strong&gt;ShadowAdmin&lt;/strong&gt; [@call4cloud-osint]. The Windows Developer Blog&apos;s canonical term for the underlying entity is the &lt;strong&gt;System Managed Administrator Account (SMAA)&lt;/strong&gt; [@ms-developer-blog-2025].&lt;/p&gt;

The hidden local user account that Windows creates per primary administrator when the `TypeOfAdminApprovalMode` policy is set to 2. The SMAA has its own random user name (typically `ADMIN_`), its own SID, its own profile directory under `C:\Users\ADMIN_\`, its own `NTUSER.DAT` and therefore its own `HKCU`, and its own membership in the local Administrators group. The operating system uses it to host elevated processes; the user never logs into it directly [@ms-developer-blog-2025, @call4cloud-osint].
&lt;p&gt;The SMAA lifecycle. Four beats. Each anchored to a verified source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Provisioning.&lt;/strong&gt; When &lt;code&gt;TypeOfAdminApprovalMode = 2&lt;/code&gt; is set under &lt;code&gt;HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System&lt;/code&gt; (either by Group Policy or by the Intune Settings Catalog), &lt;code&gt;samsrv.dll&lt;/code&gt;&apos;s &lt;code&gt;ShadowAdminAccount::CreateShadowAdminAccount&lt;/code&gt; runs once per existing local-administrator account. &lt;code&gt;CreateRandomShadowAdminAccountName&lt;/code&gt; produces an &lt;code&gt;ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt; name. &lt;code&gt;AddAccountToLocalAdministratorsGroup&lt;/code&gt; adds the new account to the Administrators group. Accounts managed by Windows LAPS (Local Administrator Password Solution) are skipped; their lifecycle is owned by a different subsystem and Microsoft did not want the SMAA mechanism to fight LAPS rotation [@call4cloud-osint].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linking.&lt;/strong&gt; Two paired SAM attributes encode the trust relationship between the two accounts. The primary admin&apos;s user record gets a &lt;code&gt;ShadowAccountForwardLinkSid&lt;/code&gt; attribute pointing at the SMAA&apos;s SID. The SMAA&apos;s user record gets a &lt;code&gt;ShadowAccountBackLinkSid&lt;/code&gt; attribute pointing back at the primary admin. These two attributes are the only structural relationship between the two accounts; everything else -- profile, HKCU, group memberships -- is independent [@call4cloud-osint].&lt;/p&gt;

Two paired SAM-database attributes that encode the trust relationship between a primary admin user and its System Managed Administrator Account. The forward link sits on the primary admin&apos;s record and points at the SMAA&apos;s SID. The back link sits on the SMAA&apos;s record and points back at the primary admin. The Application Information service uses the forward link at elevation time to resolve which SMAA to launch the elevated process under [@call4cloud-osint].

The registry value under `HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System` that selects the elevation policy. Value 0 disables UAC. Value 1 selects classic Admin Approval Mode (the Vista / Win7 / Win10 split-token behaviour). Value 2 selects Admin Approval Mode with Administrator Protection: every elevation routes through the SMAA path. The value is set by Group Policy (&quot;User Account Control: Configure type of Admin Approval Mode&quot;) or by an Intune Settings Catalog policy and requires a reboot to take effect [@ms-admin-protection, @call4cloud-osint].
&lt;p&gt;&lt;strong&gt;Per-elevation use.&lt;/strong&gt; &lt;code&gt;appinfo.dll&lt;/code&gt;&apos;s &lt;code&gt;RAiLaunchAdminProcess&lt;/code&gt; RPC endpoint reads &lt;code&gt;TypeOfAdminApprovalMode&lt;/code&gt;. When the value is 2, it walks the forward link to find the calling user&apos;s SMAA, launches &lt;code&gt;consent.exe&lt;/code&gt; on the secure desktop in &lt;em&gt;credential&lt;/em&gt; prompt mode (not Yes/No), authenticates the primary user via Windows Hello (PIN, fingerprint, face, or password fallback), asks the kernel to ask LSA for a fresh primary token for the SMAA in a brand-new logon session, and calls &lt;code&gt;CreateProcessAsUser&lt;/code&gt; with that token, the user&apos;s requested executable, and the SMAA&apos;s profile environment [@ms-developer-blog-2025, @ms-admin-protection, @forshaw-pz-jan2026]. The credential-less LSA logon at the heart of step three of this beat is walked in §7.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Teardown.&lt;/strong&gt; When the elevated process exits, the SMAA&apos;s token handle goes out of scope. The logon session is reaped. The elevated profile directory remains on disk at &lt;code&gt;C:\Users\ADMIN_&amp;lt;random&amp;gt;\&lt;/code&gt; -- it has to, to preserve per-elevation user state across reboots -- but the live admin token does not. There is no persistent High-integrity process running between elevations [@ms-developer-blog-2025].&lt;/p&gt;

flowchart TD
    Start[Policy enabled: TypeOfAdminApprovalMode = 2] --&amp;gt; Provision
    Provision[samsrv.dll: CreateShadowAdminAccount per local admin] --&amp;gt; Naming
    Naming[CreateRandomShadowAdminAccountName -&amp;gt; ADMIN_random] --&amp;gt; AddGroup
    AddGroup[AddAccountToLocalAdministratorsGroup] --&amp;gt; Link
    Link[SAM linkage: ShadowAccountForwardLinkSid /&lt;br /&gt;ShadowAccountBackLinkSid] --&amp;gt; Idle[SMAA exists, no token live]
    Idle --&amp;gt;|Each elevation| RPC[appinfo.dll: RAiLaunchAdminProcess]
    RPC --&amp;gt; Prompt[consent.exe: Hello credential prompt]
    Prompt --&amp;gt; LSA[Kernel asks LSA: credential-less logon for SMAA]
    LSA --&amp;gt; Run[CreateProcessAsUser with SMAA token]
    Run --&amp;gt;|Process exits| Teardown[Token handle released;&lt;br /&gt;logon session reaped]
    Teardown --&amp;gt; Idle

Windows creates a temporary isolated admin token to get the job done. This temporary token is immediately destroyed once the task is complete, ensuring that admin privileges do not persist. -- David Weston, Microsoft Ignite 2024 keynote, November 19, 2024 [@bleepingcomputer-2024]
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The single design decision behind Administrator Protection: the elevated and unelevated halves of an administrator must be different accounts. Different SID, different profile, different &lt;code&gt;HKCU&lt;/code&gt;, different logon session, different DOS device object directory. The shared-resource attacks of the UAC bypass canon cannot persist if there are no shared resources.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The mechanism is now described. The next section walks it at function-name granularity for a single elevation, end to end -- and in particular, the credential-less LSA logon at step six that does the load-bearing work of minting the SMAA token without any SMAA credential.&lt;/p&gt;
&lt;h2&gt;7. The elevation pipeline end to end&lt;/h2&gt;
&lt;p&gt;Walk a single elevation. Nine steps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The caller invokes &lt;code&gt;ShellExecute&lt;/code&gt; or &lt;code&gt;CreateProcess&lt;/code&gt; with an elevation request. For the shell-launched case the user right-clicks an executable and selects &quot;Run as administrator&quot;; the same RPC endpoint serves manifest-declared &lt;code&gt;requestedExecutionLevel = &quot;requireAdministrator&quot;&lt;/code&gt; callers and &lt;code&gt;Elevation:Administrator!new:&amp;lt;CLSID&amp;gt;&lt;/code&gt; COM moniker requests.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appinfo.dll&lt;/code&gt;&apos;s &lt;code&gt;RAiLaunchAdminProcess&lt;/code&gt; RPC endpoint, hosted inside the Application Information service in &lt;code&gt;svchost.exe&lt;/code&gt;, receives the call [@ms-uac-how-it-works].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appinfo&lt;/code&gt; reads &lt;code&gt;HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\TypeOfAdminApprovalMode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the value is 2 (Admin Approval Mode with Administrator Protection), &lt;code&gt;appinfo&lt;/code&gt; reads the calling user&apos;s SAM record, locates the &lt;code&gt;ShadowAccountForwardLinkSid&lt;/code&gt; attribute, and validates the corresponding &lt;code&gt;ShadowAccountBackLinkSid&lt;/code&gt; on the SMAA&apos;s SAM record. The linkage check is what binds a given elevated process to a given primary user; without both attributes pointing at each other, the elevation is refused [@call4cloud-osint].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appinfo&lt;/code&gt; launches &lt;code&gt;consent.exe&lt;/code&gt; on the secure desktop in &lt;em&gt;credential&lt;/em&gt; prompt mode rather than the classic Yes/No mode. The prompt asks the primary user to authenticate via Windows Hello (PIN, fingerprint, face, or password fallback), not the SMAA. The SMAA &lt;em&gt;has no human credentials&lt;/em&gt;. The Windows Developer Blog states the property explicitly [@ms-developer-blog-2025], and Forshaw&apos;s January 2026 post restates it in operational terms: &quot;The user does not need to know the credentials for the shadow administrator as there aren&apos;t any. Instead UAC can be configured to prompt for the limited user&apos;s credentials, including using biometrics if desired&quot; [@forshaw-pz-jan2026].&lt;/li&gt;
&lt;li&gt;On a positive Hello result, &lt;code&gt;appinfo.dll&lt;/code&gt; -- running as &lt;code&gt;NT AUTHORITY\SYSTEM&lt;/code&gt; inside the Application Information service -- asks the kernel to ask LSA for a fresh primary access token for the SMAA&apos;s SID in a brand-new logon session. The LSA logon is &lt;em&gt;credential-less&lt;/em&gt;. The kernel asks LSA to authenticate &quot;a new instance of the shadow administrator,&quot; and LSA fulfils the request without any SMAA credential because the SMAA has no credential to verify. The trust architecture mirrors the way the Service Control Manager asks LSA for service-account tokens: SCM is trusted to ask for the token; LSA mints it on the strength of the &lt;em&gt;request&lt;/em&gt; rather than on the strength of any credential. In Administrator Protection, &lt;code&gt;appinfo.dll&lt;/code&gt; is the trusted requester, and its request is gated on the user-side Hello result it received in step 5. The Forshaw verbatim that anchors the mechanism is below this section [@forshaw-pz-jan2026, @ms-developer-blog-2025].&lt;/li&gt;
&lt;li&gt;&lt;code&gt;appinfo&lt;/code&gt; calls &lt;code&gt;CreateProcessAsUser&lt;/code&gt; with the SMAA token, the user&apos;s requested executable, and the SMAA&apos;s profile environment block (&lt;code&gt;USERPROFILE=C:\Users\ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt;, &lt;code&gt;USERNAME=ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt;, the SMAA&apos;s &lt;code&gt;NTUSER.DAT&lt;/code&gt; mapped as &lt;code&gt;HKCU&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The new process loads at High integrity, holding the SMAA&apos;s primary token, in a fresh logon session with a freshly minted authentication-ID LUID. The DOS device directory at &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;LUID&amp;gt;&lt;/code&gt; does not yet exist; the kernel will create it on first reference.&lt;/li&gt;
&lt;li&gt;Subsequent &lt;code&gt;SeAccessCheck&lt;/code&gt; calls on system objects evaluate against the SMAA&apos;s local Administrators group membership and succeed. The elevated process can write to &lt;code&gt;HKLM&lt;/code&gt;, modify program files, install services, load WHQL-signed drivers (subject to App Control for Business and HVCI), and otherwise behave as a member of the Administrators group [@ms-developer-blog-2025].&lt;/li&gt;
&lt;/ol&gt;

The mechanism by which the Local Security Authority mints a primary access token for the SMAA without verifying any SMAA credential. `appinfo.dll`, running as `NT AUTHORITY\SYSTEM` inside the Application Information service, requests the logon on the SMAA&apos;s behalf after the primary user has succeeded against the Hello credential gate. LSA fulfils the request because the *requester* is trusted; the architecture mirrors the way the Service Control Manager requests service-account tokens. The &quot;credential-less&quot; label is descriptive of the SMAA side of the exchange: the SMAA never has a human credential to verify, so LSA cannot and does not ask for one [@forshaw-pz-jan2026, @ms-developer-blog-2025].
&lt;p&gt;The trust architecture is not new in Administrator Protection. The Service Control Manager has asked LSA for service-account tokens since Windows NT 3.1 in 1993; LSA accepts the request because SCM is the trusted requester, not because the service account presented a credential. Administrator Protection generalises the same pattern to elevation: &lt;code&gt;appinfo.dll&lt;/code&gt; is the trusted requester, and the SMAA is its functional analogue of a service account. What is new is the user-side gate -- the trusted requester only makes the request after a positive Hello result on the &lt;em&gt;primary user&apos;s&lt;/em&gt; credential.&lt;/p&gt;

in Administrator Protection the kernel calls into the LSA and authenticates a new instance of the shadow administrator. This results in every token returned from `TokenLinkedToken` having a unique logon session, and thus does not currently have the DOS device object directory created. -- James Forshaw, *Bypassing Windows Administrator Protection*, Google Project Zero, January 26, 2026 [@forshaw-pz-jan2026]
&lt;p&gt;The &quot;unique logon session&quot; property in Forshaw&apos;s quote is exactly the structural property the lazy-DOS-device-directory bypass exploits, and §12 walks that exploit in full. For now, the load-bearing observation is the credential-less logon itself: the SMAA token is real, the logon session is real, the integrity level is real, but no SMAA credential ever changes hands. The trust is in the requester, gated by a Hello gesture from the primary user.&lt;/p&gt;

sequenceDiagram
    participant User as User shell (primary admin filtered token)
    participant AppInfo as appinfo.dll (NT AUTHORITY\SYSTEM)
    participant SAM as samsrv.dll / SAM database
    participant Consent as consent.exe (secure desktop)
    participant Hello as Windows Hello / TPM
    participant LSA as LSASS
    participant Elev as Elevated SMAA process&lt;pre&gt;&lt;code&gt;User-&amp;gt;&amp;gt;AppInfo: ShellExecute &quot;as admin&quot;
AppInfo-&amp;gt;&amp;gt;AppInfo: RAiLaunchAdminProcess RPC
AppInfo-&amp;gt;&amp;gt;AppInfo: Read TypeOfAdminApprovalMode = 2
AppInfo-&amp;gt;&amp;gt;SAM: Resolve ShadowAccountForwardLinkSid
SAM--&amp;gt;&amp;gt;AppInfo: SMAA SID + backlink check OK
AppInfo-&amp;gt;&amp;gt;Consent: Launch consent.exe (credential mode)
Consent-&amp;gt;&amp;gt;Hello: Request Hello gesture for primary user
Hello--&amp;gt;&amp;gt;Consent: PIN / biometric / password verified
Consent--&amp;gt;&amp;gt;AppInfo: Approved
AppInfo-&amp;gt;&amp;gt;LSA: Credential-less logon for SMAA (trusted-requester pattern)
LSA--&amp;gt;&amp;gt;AppInfo: Fresh SMAA primary token and fresh LUID
AppInfo-&amp;gt;&amp;gt;Elev: CreateProcessAsUser with SMAA token and profile
Note over Elev: Different SID and USERPROFILE and HKCU and LUID
Note over Elev: Integrity level High -- DOS device dir not yet created
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A practical illustration of the shift, displayed as the diff between the pre-AP and post-AP elevated console session.&lt;/p&gt;
&lt;p&gt;{`
// Modelled output of &apos;whoami /all&apos; run from an elevated console.
// Before: TypeOfAdminApprovalMode = 1 (classic UAC).
// After:  TypeOfAdminApprovalMode = 2 (Administrator Protection).&lt;/p&gt;
&lt;p&gt;const before = {
  user: &apos;CONTOSO\\alice&apos;,
  sid: &apos;S-1-5-21-123456789-987654321-1122334455-1001&apos;,
  profile: &apos;C:\\Users\\alice&apos;,
  authId: &apos;0x3e7:0x000abcde&apos;,
  integrity: &apos;S-1-16-12288 (High)&apos;,
  groups: [&apos;BUILTIN\\Administrators (Enabled)&apos;]
};&lt;/p&gt;
&lt;p&gt;const after = {
  user: &apos;WIN11-PC\\ADMIN_9f2c7e1bdc4a8033&apos;,
  sid: &apos;S-1-5-21-123456789-987654321-1122334455-1051&apos;,
  profile: &apos;C:\\Users\\ADMIN_9f2c7e1bdc4a8033&apos;,
  authId: &apos;0x3e7:0x000abf42&apos;,
  integrity: &apos;S-1-16-12288 (High)&apos;,
  groups: [&apos;BUILTIN\\Administrators (Enabled)&apos;],
  shadowBacklink: &apos;CONTOSO\\alice&apos;
};&lt;/p&gt;
&lt;p&gt;console.log(&apos;Different user name:&apos;, before.user !== after.user);
console.log(&apos;Different SID:&apos;,       before.sid !== after.sid);
console.log(&apos;Different profile:&apos;,   before.profile !== after.profile);
console.log(&apos;Different LUID:&apos;,      before.authId !== after.authId);
console.log(&apos;Same integrity:&apos;,      before.integrity === after.integrity);
`}&lt;/p&gt;
&lt;p&gt;The pipeline is now a single chain of named function calls. The next section asks what &lt;em&gt;changed&lt;/em&gt; about the four shared-resource properties from §3, and which UAC-bypass family each fix forecloses.&lt;/p&gt;
&lt;h2&gt;8. The four shared-resources fixes, precisely&lt;/h2&gt;
&lt;p&gt;Each of the four shared resources from §3 maps to a precise Administrator Protection fix, and each fix maps to a named UAC-era attack class it forecloses.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shared resource (UAC)&lt;/th&gt;
&lt;th&gt;Administrator Protection fix&lt;/th&gt;
&lt;th&gt;UAC-era attack class foreclosed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Same SID across both tokens&lt;/td&gt;
&lt;td&gt;SMAA has its own SID; no shared user identity&lt;/td&gt;
&lt;td&gt;Same-user file and registry ACE confusion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same &lt;code&gt;%USERPROFILE%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SMAA has &lt;code&gt;C:\Users\ADMIN_&amp;lt;random&amp;gt;\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DLL side-load family (sysprep / CRYPTBASE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same &lt;code&gt;HKCU&lt;/code&gt; hive&lt;/td&gt;
&lt;td&gt;SMAA has its own &lt;code&gt;NTUSER.DAT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Registry-hijack family (eventvwr, fodhelper, sdclt)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same logon-session LUID&lt;/td&gt;
&lt;td&gt;SMAA gets a fresh LUID per elevation&lt;/td&gt;
&lt;td&gt;Token-theft via &lt;code&gt;TokenLinkedToken&lt;/code&gt;; logon-session DOS device hijack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Profile separation.&lt;/strong&gt; The SMAA owns its own &lt;code&gt;%USERPROFILE%&lt;/code&gt; directory tree under &lt;code&gt;C:\Users\ADMIN_&amp;lt;random&amp;gt;\&lt;/code&gt;. Files created by elevated processes land there by default. Library folder divergence is the most visible consequence: an elevated Notepad&apos;s File &amp;gt; Save dialog opens at the SMAA&apos;s &lt;code&gt;Documents&lt;/code&gt;, not the primary user&apos;s. The primary user cannot see those files in their own Explorer without explicit cross-profile navigation. The structural property that closes is the writable-shared-directory premise of the Davidson 2009 DLL side-load family. Sysprep + CRYPTBASE was a profile-shared attack; without a shared profile, the elevated binary searches a different directory tree from the one the limited user can write to [@ms-developer-blog-2025].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Registry separation.&lt;/strong&gt; The SMAA&apos;s &lt;code&gt;HKCU&lt;/code&gt; maps to the SMAA&apos;s &lt;code&gt;NTUSER.DAT&lt;/code&gt;, not the primary user&apos;s. When &lt;code&gt;eventvwr.exe&lt;/code&gt;, running in an SMAA process, queries &lt;code&gt;HKCU\Software\Classes\mscfile\shell\open\command&lt;/code&gt;, it reads the SMAA&apos;s hive, not the primary user&apos;s. The primary user has no write access to the SMAA&apos;s &lt;code&gt;NTUSER.DAT&lt;/code&gt;. The entire registry-hijack family -- eventvwr / mscfile [@enigma0x3-2016-eventvwr], fodhelper / ms-settings, sdclt / IsolatedCommand [@enigma0x3-2017-sdclt], sdclt / App Paths [@enigma0x3-2017-app-paths] -- forecloses on the same property: the elevated binary&apos;s &lt;code&gt;HKCU&lt;/code&gt; lookup walks a hive the attacker does not control [@ms-developer-blog-2025].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Logon-session separation.&lt;/strong&gt; Every SMAA elevation gets a fresh authentication-ID LUID. The Local Security Authority allocates a new logon session for each elevation; when the elevated process exits, the session is reaped. Per-logon-session kernel resource caches, including the DOS device object directory at &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;LUID&amp;gt;&lt;/code&gt; and the credential cache, do not flow across the boundary. Token handles cannot be reused. Drive-letter overrides under the limited user&apos;s logon session do not appear in the SMAA&apos;s session [@forshaw-pz-jan2026].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No auto-elevation.&lt;/strong&gt; The &lt;code&gt;autoElevate=true&lt;/code&gt; manifest attribute is no longer honoured by &lt;code&gt;appinfo.dll&lt;/code&gt; under &lt;code&gt;TypeOfAdminApprovalMode = 2&lt;/code&gt;. Every elevation that previously went silent now prompts. The Windows Developer Blog states the change directly: &quot;With administrator protection, all auto-elevations in Windows are removed and users need to interactively authorize every admin operation&quot; [@ms-developer-blog-2025]. Forshaw&apos;s January 2026 framing of the consequence: &quot;as auto-elevation is no longer permitted they will always show a prompt, therefore these are not considered bypasses&quot; [@forshaw-pz-jan2026]. This is the single most consequential fix in the design. The auto-elevation whitelist &lt;em&gt;was&lt;/em&gt; the bypass; removing the whitelist eliminates the class at the source, including the entire silent-elevation primitive class that Forshaw&apos;s older &lt;code&gt;RAiProcessRunOnce&lt;/code&gt; research relied on.&lt;/p&gt;

Multi-user separation is the original UNIX privilege model. The `root` user holds privilege; ordinary users do not; the boundary between them is the file-permission system enforced by the kernel. Windows NT shipped the same primitives in 1993 -- discretionary access control lists on every securable object, per-user profiles, multi-user logon sessions -- but the surrounding culture treated Administrator-as-default as the path of least resistance. The architectural sophistication in Administrator Protection is in *linkage* (the SAM forward / back attributes), *lifecycle* (provisioning on policy enable, teardown on process exit), and *enforcement* (removal of auto-elevation as a mechanism). The primitives themselves are old.
&lt;p&gt;The four fixes share a property. Each one breaks a shared resource that an attacker depends on. But there is one more piece of the redesign that has not yet been described: the prompt itself is no longer a Yes/No click-through. The next section asks what happens when the consent UI becomes a credential.&lt;/p&gt;
&lt;h2&gt;9. Windows Hello as the consent gate&lt;/h2&gt;
&lt;p&gt;The classic UAC prompt is a Yes / No on the secure desktop. Administrator Protection turns the prompt into a &lt;em&gt;credential&lt;/em&gt; prompt for the &lt;em&gt;primary user&apos;s&lt;/em&gt; Windows Hello: a PIN, a fingerprint, a face match, or a password fallback. The credential is for the primary user, not the SMAA, because the SMAA has no human credentials; the Hello verification is what &lt;em&gt;authorises&lt;/em&gt; the cross-profile elevation [@ms-admin-protection, @ms-developer-blog-2025, @forshaw-pz-jan2026].&lt;/p&gt;
&lt;p&gt;To talk precisely about what the gate does, name the primitive it closes. Under classic UAC, the consent prompt treated a click on the secure desktop as sufficient evidence of consent; physical presence was the entire evidence requirement. That primitive shows up in three sub-cases that the UAC literature has documented for two decades.&lt;/p&gt;

The primitive by which the legacy UAC consent dialog accepted a click on the secure desktop as sufficient evidence of consent, without verifying *who* clicked. Three operational sub-cases follow. *Unattended-session click-through* -- an attacker (or co-located third party) with brief physical access to an unlocked screen showing a UAC prompt clicks Yes on the presumption that whoever is at the keyboard is the legitimate user. *Habituated-click click-through* -- the legitimate user has clicked Yes on hundreds of UAC prompts and clicks one more without conscious attention. *Pretext click-through* -- a malicious application argues a legitimate-looking case to the user and elicits the Yes click. Administrator Protection&apos;s credential gate cost-raises all three sub-cases without fully eliminating any [@forshaw-pz-jan2026, @ms-admin-protection].
&lt;p&gt;&lt;strong&gt;Unattended-session click-through.&lt;/strong&gt; An attacker who walks up to an unlocked screen showing a UAC prompt can click Yes and elevate. The legitimate user has authenticated; the prompt assumes the person at the keyboard is the legitimate user. Post-AP, the click is not sufficient. The Hello biometric or PIN is required, and the attacker (who does not know either) cannot complete the gesture. Microsoft&apos;s Ignite 2024 framing addresses this primitive implicitly with &quot;elevation rights only when needed&quot; and &quot;interactively authorize every admin operation&quot; [@bleepingcomputer-2024].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Habituated-click click-through.&lt;/strong&gt; A user who has clicked Yes on hundreds of UAC prompts over the course of a year clicks Yes on a malicious one as reflex. The classic UAC prompt requires no attentional engagement beyond physical presence and a click. Hello&apos;s gesture (a four-digit PIN entry, a fingerprint press, a face-recognition glance) is higher-friction and harder to perform inattentively. The Windows Developer Blog frames the property as &quot;just-in-time administrator privileges, incorporating Windows Hello to enhance both security and user convenience&quot; [@ms-developer-blog-2025].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pretext click-through.&lt;/strong&gt; A malicious application that argues its case to the user -- a fake installer, a re-skinned setup utility, a Trojan masquerading as a legitimate update -- can elicit a Yes click pre-AP. Post-AP, the user is also asked for a credential, which is a stronger user-side check. The user is more likely to interrogate &quot;why am I being asked for my PIN &lt;em&gt;again&lt;/em&gt;?&quot; than &quot;why is a prompt appearing?&quot; Microsoft Learn captures the intent as &quot;users are aware of potentially harmful actions before they occur, providing an extra layer of defense against threats&quot; [@ms-admin-protection].&lt;/p&gt;
&lt;p&gt;None of the three sub-cases is &lt;em&gt;fully&lt;/em&gt; eliminated. Forshaw is explicit that visible-prompt bypasses are not classified as security vulnerabilities by Microsoft&apos;s design-document position: bypasses that result in a visible prompt are not security bulletins, because the user could equivalently have launched the prompt themselves [@forshaw-pz-jan2026]. What the gate does is &lt;em&gt;cost-raise&lt;/em&gt; each sub-case. The unattended-screen attack requires a stolen PIN or coerced biometric. The habituated user must perform a gesture they cannot perform inattentively. The pretext attack must justify the second authentication, not just the first.&lt;/p&gt;
&lt;p&gt;What it does &lt;em&gt;not&lt;/em&gt; close is worth naming, because three primitives that look like they belong on the credential gate&apos;s account sheet were already closed by independent mechanisms, and the article should say so to avoid the common over-attribution mistake.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Synthetic-keystroke &lt;code&gt;SendInput&lt;/code&gt; against &lt;code&gt;consent.exe&lt;/code&gt;.&lt;/strong&gt; Already closed by UIPI in Vista 2006, and doubly closed by the secure-desktop switch to &lt;code&gt;Winsta0\Winlogon&lt;/code&gt;. Even UI Access processes -- whose purpose is to bypass UIPI for accessibility -- cannot reach into the secure desktop [@forshaw-pz-feb2026].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless UI Automation against the prompt.&lt;/strong&gt; Same UIPI / secure-desktop boundary closes it. Redundant with respect to the credential gate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2019-1388-class UI-interaction paths surfaced through the prompt&apos;s own UI.&lt;/strong&gt; Closed by Microsoft&apos;s November 2019 HHCtrl patch and the cert-viewer UI redesign, prior to any Administrator Protection development [@nvd-cve-2019-1388].&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The credential is hardware-rooted via &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM&lt;/a&gt; or &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Pluton&lt;/a&gt; on capable hardware. The PIN is unsealed only under the user&apos;s gesture; the biometric flows through Enhanced Sign-in Security (ESS) on capable hardware; the credential itself never leaves the Trusted Platform Module or Pluton enclave when ESS is engaged [@ms-windows-hello-ess]. The detail of the Hello architecture itself -- FIDO2 attestation, the &lt;code&gt;ngc&lt;/code&gt; protector, the ESS isolation path through the Secure Kernel -- belongs to the &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Windows Hello article&lt;/a&gt; in this series, and is not re-derived here.&lt;/p&gt;
&lt;p&gt;The new risk the gate does &lt;em&gt;not&lt;/em&gt; close is the obvious one. Phishing the prompt now phishes a &lt;em&gt;real credential&lt;/em&gt;, not just consent. A malicious application that can convince the user to authenticate on its behalf gets the elevation the user would otherwise have given to a legitimate request. The credential remains hardware-rooted and is not exfiltrated to the malware, but the elevation produces a working SMAA token in the attacker&apos;s process. This is the surface §15 carries forward to open problems.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The credential gate closes one specific primitive: &lt;em&gt;consent-without-identity-verification&lt;/em&gt;. It cost-raises three sub-cases (unattended-session, habituated-click, pretext click-through) without eliminating any. The structural boundary is profile separation plus fresh logon session plus auto-elevation removal; the credential gate is the fourth, defence-in-depth, property that ensures the boundary cannot be silently crossed by anyone holding only the limited user&apos;s physical access.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The prompt is a credential gate, but it remains a UI element. The next section asks how this elevation model compares to what other operating systems do.&lt;/p&gt;
&lt;h2&gt;10. Competing approaches: what other operating systems do&lt;/h2&gt;
&lt;p&gt;Three one-paragraph treatments. The article does not re-derive each system; it positions Administrator Protection against the field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux: &lt;code&gt;sudo&lt;/code&gt; plus PolKit &lt;code&gt;pkexec&lt;/code&gt; plus PAM modules.&lt;/strong&gt; The authority model on Linux is file-based. &lt;code&gt;/etc/sudoers&lt;/code&gt; (or its LDAP equivalent) is the policy table; the &lt;code&gt;sudoers&lt;/code&gt; plugin reads it and decides whether to permit a given user to run a given command [@sudo-ws-sudoers]. PolKit -- &lt;code&gt;polkitd&lt;/code&gt; and its authentication-agent helpers -- is the parallel mechanism for GUI privileged-service requests, with actions and mechanisms separated in the polkit configuration files [@polkit-docs]. Biometric integration arrives through the PAM stack: &lt;code&gt;pam_fprintd&lt;/code&gt; for fingerprint, &lt;code&gt;pam_u2f&lt;/code&gt; for FIDO2 tokens, &lt;code&gt;pam_yubico&lt;/code&gt; for Yubikeys. There is no profile separation by default; &lt;code&gt;sudo -i&lt;/code&gt; switches &lt;code&gt;HOME&lt;/code&gt; to root&apos;s home directory but does not separate per-elevation. The model is per-command authorisation, not per-account isolation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;macOS: Authorization Services plus Touch ID via &lt;code&gt;pam_tid&lt;/code&gt;.&lt;/strong&gt; GUI elevation prompts are gated by &lt;code&gt;authorizationdb&lt;/code&gt;, a property-list-format policy database whose rules name which credentials (admin password, Touch ID, system-wide entitlements) authorise which actions [@apple-auth-services]. Touch ID is verified by the Secure Enclave Processor; the credential never leaves the SEP, and Authorization Services integrates with &lt;code&gt;pam_tid&lt;/code&gt; to allow &lt;code&gt;sudo&lt;/code&gt; invocations to use the gesture [@apple-pam-tid]. There is no separate admin profile; Transparency, Consent, and Control (TCC) guards privileged resource access at the per-action level, not the per-profile level. The Mac architecture privileges hardware-rooted consent (Touch ID, Secure Enclave) over account separation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft&apos;s own &lt;code&gt;sudo.exe&lt;/code&gt; (Windows 11 24H2).&lt;/strong&gt; An inbox terminal transport that triggers the &lt;em&gt;existing&lt;/em&gt; UAC or Administrator Protection pipeline; not an alternative to either [@ms-sudo-docs]. The &lt;code&gt;forceNewWindow&lt;/code&gt; mode opens an elevated console in a new window. The &lt;code&gt;disableInput&lt;/code&gt; mode keeps the elevated console in the current window but blocks keyboard input to it from the unelevated terminal. The &lt;code&gt;normal&lt;/code&gt; (inline) mode preserves POSIX-style pipes between the unelevated and elevated processes. Microsoft Learn warns explicitly about the inline mode: &quot;Sudo for Windows can be used as a potential escalation of privilege vector when enabled in certain configurations&quot; [@ms-sudo-docs]. The mechanism is RPC between the unelevated and elevated &lt;code&gt;sudo.exe&lt;/code&gt; processes; the elevation itself still goes through &lt;code&gt;appinfo.dll&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Intune Endpoint Privilege Management (EPM).&lt;/strong&gt; Cloud-policy-driven virtual-account elevation [@ms-epm-overview]. EPM performs elevation via a &lt;em&gt;virtual&lt;/em&gt; account that is not a member of the local Administrators group; the elevation rights are conferred only for the duration of the policy-permitted action. Three elevation modes are available: Automatic (no user interaction), User-confirmed (a prompt), and Elevate as Current User (the action runs as the user&apos;s elevated identity rather than the virtual account). EPM is architecturally complementary to Administrator Protection: EPM is the &lt;em&gt;enterprise policy&lt;/em&gt; story, Administrator Protection is the &lt;em&gt;per-device architecture&lt;/em&gt; story. The two can coexist on the same device.&lt;/p&gt;
&lt;p&gt;The distinguishing property of Administrator Protection in this comparison is whole-profile separation: the SMAA&apos;s own profile, the SMAA&apos;s own &lt;code&gt;HKCU&lt;/code&gt;, the SMAA&apos;s own library folders, plus a fresh logon session per elevation. Neither Linux &lt;code&gt;sudo&lt;/code&gt; nor macOS Authorization Services provides that property as a default desktop primitive. EPM provides per-elevation isolation via the virtual account but does not give the elevated process a persistent profile, which is what makes Administrator Protection&apos;s compatibility story so different from EPM&apos;s.&lt;/p&gt;
&lt;p&gt;Administrator Protection is the architecturally tightest desktop elevation model now in production. The next section asks where the boundary still leaks.&lt;/p&gt;
&lt;h2&gt;11. Theoretical limits: what Administrator Protection cannot fix&lt;/h2&gt;
&lt;p&gt;Four structural ceilings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Showing a prompt is not crossing the boundary.&lt;/strong&gt; Microsoft&apos;s design position is explicit: bypasses that result in a &lt;em&gt;visible&lt;/em&gt; elevation prompt are not security bulletins, because the user could equivalently have right-clicked &quot;Run as administrator.&quot; Forshaw&apos;s January 2026 post states the position verbatim: &quot;I expect that malware will still be able to get administrator privileges even if that&apos;s just by forcing a user to accept the elevation prompt&quot; [@forshaw-pz-jan2026]. The operational consequence is that social-engineering the consent dialog remains a structural attack surface. The prompt is a UI element. The boundary is the credential gate. The gate is only as strong as the user&apos;s resistance to whatever pretext induces them to authenticate.&lt;/p&gt;

The MSRC servicing-criteria definition of a security boundary: a logical separation between code or data of different trust levels, intended to be enforced by the operating system and accompanied by a Microsoft commitment to issue a security update when an unauthorised crossing is found. UAC under the classic split-token model is classified as a *security feature*, not a boundary; bypasses receive quality-fix attention but not security-bulletin attention. Administrator Protection is the first elevation mechanism classified as a security boundary, with bulletin-grade fixes when it fails [@msrc-servicing-criteria, @forshaw-pz-jan2026].
&lt;p&gt;&lt;strong&gt;Admin equals kernel.&lt;/strong&gt; Once code is running inside an SMAA elevated process, it has the local Administrators group; it can write to &lt;code&gt;HKLM&lt;/code&gt;; it can install services; it can load WHQL-signed drivers; it can call into kernel-mode interfaces gated by &lt;code&gt;SeLoadDriverPrivilege&lt;/code&gt; and the App Control for Business policy. The MSRC servicing-criteria position that &quot;admin-to-kernel is not a security boundary&quot; continues to apply inside the SMAA [@msrc-servicing-criteria]. Administrator Protection makes the path &lt;em&gt;to&lt;/em&gt; admin into a boundary; it does not change the relationship between admin and kernel. Driver-loading controls remain the domain of WHQL signing, the Microsoft Vulnerable Driver Blocklist (default-on in Windows 11 since the 2022 update), App Control for Business policies, and Hypervisor-protected Code Integrity (HVCI) [@ms-vuln-driver-blocklist]. The &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;App Identity article&lt;/a&gt; in this series covers the App Control mechanism in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The SMAA is in the local Administrators group.&lt;/strong&gt; Discretionary access control list-based exposures of admin-only resources -- &lt;code&gt;CREATOR OWNER&lt;/code&gt; ACEs on persistent objects, world-writable DACLs on certain &lt;code&gt;\Sessions\0\DosDevices&lt;/code&gt; entries, default-permissive ACLs on a handful of legacy registry trees -- still grant the SMAA full access. The boundary is between &lt;em&gt;standard user&lt;/em&gt; and &lt;em&gt;SMAA&lt;/em&gt;, not between &lt;em&gt;SMAA&lt;/em&gt; and &lt;em&gt;SYSTEM&lt;/em&gt;. The SMAA is a high-privilege actor inside the operating system; the relationship between it and the rest of the privileged surface is unchanged.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Out of scope per Microsoft Learn.&lt;/strong&gt; Remote logon, roaming profiles, backup-admin accounts, Managed Service Accounts and group Managed Service Accounts (MSAs and gMSAs), virtual accounts for services, and domain-admin scenarios are explicitly outside the Administrator Protection model in its current form [@ms-admin-protection]. The feature is local-machine-only, interactive-admin-only. Domain administrators who log into a workstation will not see the SMAA path; service accounts under &lt;code&gt;LOCAL SERVICE&lt;/code&gt;, &lt;code&gt;NETWORK SERVICE&lt;/code&gt;, or &lt;code&gt;IIS_IUSRS&lt;/code&gt; are unaffected.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; A genuine architectural ceiling on consent-prompt elevation: the prompt is a UI element; the boundary is the credential gate; the gate is only as strong as the user&apos;s resistance to social engineering. Closing the gap requires out-of-band consent (smartcard, phone push) or per-action policy without human consent in the loop (EPM&apos;s automatic mode). Neither is the default.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Four limits, four sentences. The next section walks the concrete evidence of what actually leaked in the pre-GA Insider Preview builds, and what Microsoft did about it.&lt;/p&gt;
&lt;h2&gt;12. Forshaw&apos;s nine bypasses, classified&lt;/h2&gt;
&lt;p&gt;Between October 2024, when Administrator Protection first appeared in Insider Preview build 27718, and October 2025, when KB5067036 made the feature available on stable Windows, James Forshaw of Google Project Zero audited the mechanism and found nine separate silent-bypass paths. Microsoft fixed all nine -- either in the KB5067036 ship or in subsequent security bulletins [@forshaw-pz-jan2026]. The fact pattern is the structural confirmation that Administrator Protection is now treated as a security boundary. Under the UAC classification, none of those nine would have received CVEs. Each one would have been a quality bug. The bypass canon ran for twenty years without bulletins. The fact that the first cohort of Administrator Protection bypasses produced nine bulletin-eligible fixes is exactly the change in posture the classification change implies.&lt;/p&gt;

All the issues that I reported to Microsoft have been fixed, either prior to the feature being officially released (in optional update KB5067036) or as subsequent security bulletins. -- James Forshaw, *Bypassing Windows Administrator Protection*, Google Project Zero, January 26, 2026 [@forshaw-pz-jan2026]
&lt;p&gt;Walk the nine as three classes.&lt;/p&gt;
&lt;h3&gt;The lazy DOS device directory hijack&lt;/h3&gt;
&lt;p&gt;The single most interesting vulnerability in the feature&apos;s history; Forshaw&apos;s January 26, 2026 deep analysis [@forshaw-pz-jan2026]; Project Zero issue 432313668 [@pz-issue-432313668]. The mechanism turns on a behaviour change Administrator Protection itself introduced. Every SMAA elevation gets a &lt;em&gt;fresh&lt;/em&gt; logon session, which means the per-logon-session DOS device object directory at &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;LUID&amp;gt;&lt;/code&gt; is not created at SMAA logon time. The kernel routine &lt;code&gt;SeGetTokenDeviceMap&lt;/code&gt; creates the directory &lt;em&gt;lazily&lt;/em&gt;, on the first reference. The owner of the new directory is the owner of the access token that triggered the creation [@forshaw-pz-jan2026, @theregister-2026].&lt;/p&gt;

The impersonation level (`SecurityIdentification`) at which an impersonating thread can read security information about the impersonated token -- the SID set, the privilege set -- but cannot perform privileged operations or open kernel objects as the impersonated user. The kernel allows access checks to consult an identification-level token for *reading* the security information; certain code paths inadvertently use that information for *granting* operations, which is the structural primitive Forshaw&apos;s lazy DOS device directory exploit depends on [@forshaw-pz-jan2026].
&lt;p&gt;The &lt;code&gt;SECURITY_IMPERSONATION_LEVEL&lt;/code&gt; enumeration in &lt;code&gt;winnt.h&lt;/code&gt; defines four levels in ascending order: &lt;code&gt;SecurityAnonymous&lt;/code&gt; (value 0), &lt;code&gt;SecurityIdentification&lt;/code&gt; (1), &lt;code&gt;SecurityImpersonation&lt;/code&gt; (2), &lt;code&gt;SecurityDelegation&lt;/code&gt; (3). &lt;code&gt;SecurityIdentification&lt;/code&gt; is the second-lowest -- it sits one above &lt;code&gt;SecurityAnonymous&lt;/code&gt; -- and is the level Windows uses when it wants to ask the kernel &quot;what would this token be allowed to do?&quot; without actually doing the operation. The trap is when a code path that runs &lt;em&gt;as the caller&lt;/em&gt; uses an identification-level impersonation to read a token property -- here, the linked-token field -- and the resulting object inherits the caller&apos;s owner SID rather than the impersonated token&apos;s.&lt;/p&gt;
&lt;p&gt;The exploit chain. An attacker running as the primary user (filtered token, Medium integrity) starts an elevation. Before the SMAA process touches its DOS device directory, the attacker impersonates the SMAA&apos;s &lt;code&gt;TokenLinkedToken&lt;/code&gt; at identification level and triggers a code path that walks the directory. The kernel creates &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;SMAA_LUID&amp;gt;&lt;/code&gt; lazily; in the affected code path, the owner of the new directory becomes the attacker&apos;s primary token&apos;s owner SID rather than the SMAA&apos;s.&lt;/p&gt;
&lt;p&gt;The attacker plants a &lt;code&gt;C:&lt;/code&gt; symbolic link inside the directory pointing at an attacker-controlled location. When the elevated SMAA process loads its DLLs, the resolution walks &lt;code&gt;\Sessions\0\DosDevices\&amp;lt;SMAA_LUID&amp;gt;\C:&lt;/code&gt; first; the symlink redirects the load to the attacker&apos;s directory; the attacker&apos;s DLL runs in the High-integrity SMAA process [@forshaw-pz-jan2026].&lt;/p&gt;

sequenceDiagram
    participant Att as Attacker (limited user)
    participant Kern as &quot;Kernel (SeGetTokenDeviceMap)&quot;
    participant SMAA as SMAA elevated process&lt;pre&gt;&lt;code&gt;Note over SMAA: Fresh logon session -- DOS device dir not yet created
Att-&amp;gt;&amp;gt;Att: Impersonate SMAA TokenLinkedToken at Identification level
Att-&amp;gt;&amp;gt;Kern: Reference \Sessions\0\DosDevices\&amp;lt;SMAA_LUID&amp;gt;
Kern-&amp;gt;&amp;gt;Kern: Lazy-create directory
Note over Kern: Owner SID inherited from impersonating token
Att-&amp;gt;&amp;gt;Kern: Create C: symlink under attacker control
SMAA-&amp;gt;&amp;gt;Kern: Resolve C: at first DLL load
Kern--&amp;gt;&amp;gt;SMAA: Returns attacker symlink target
SMAA-&amp;gt;&amp;gt;SMAA: Load attacker DLL at High integrity
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What makes this bypass extraordinary is that it is &lt;em&gt;caused by&lt;/em&gt; the feature&apos;s design. Pre-Administrator-Protection, the user&apos;s primary logon session was created at desktop logon and the DOS device directory existed before any elevation. Lazy directory creation never came up. The SMAA design&apos;s &quot;fresh logon session per elevation&quot; property -- the same property Forshaw&apos;s January 2026 pull-quote in §7 establishes via the credential-less LSA logon -- is exactly the precondition the lazy-creation path exploits.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s pre-GA fix has two parts. First, the manifest-parsing access check uses the SYSTEM-impersonating-the-low-user identity rather than the user&apos;s primary token. Second, the DOS device directory is materialised with the correct owner before any user-controlled code path can trigger the lazy-creation path [@forshaw-pz-jan2026]. The Register&apos;s coverage of the disclosure noted &quot;the most notable of the nine bugs he reported was a Logon Sessions flaw that relied upon five different Windows behaviors. He added that he likely only found it because he was previously familiar with the OS&apos;s &apos;weird behavior when creating the DOS device object directory&apos;&quot; [@theregister-2026].&lt;/p&gt;
&lt;h3&gt;The five UI Access bypasses&lt;/h3&gt;
&lt;p&gt;Forshaw&apos;s February 2026 post details the second class, comprising five of the nine bypasses [@forshaw-pz-feb2026]. UI Access is a token flag retrofitted in Vista to let accessibility applications cross UIPI. To qualify, an executable needs three things: a manifest declaring &lt;code&gt;uiAccess=&quot;true&quot;&lt;/code&gt;, a trusted code-signing certificate, and an installation location under an administrator-only directory (typically &lt;code&gt;%ProgramFiles%&lt;/code&gt;). The Application Information service&apos;s &lt;code&gt;RAiLaunchAdminProcess&lt;/code&gt; endpoint launches qualifying UI Access processes &lt;em&gt;without showing the consent prompt&lt;/em&gt;, on the theory that the three-criteria check is itself sufficient evidence of administrator approval [@forshaw-pz-feb2026].&lt;/p&gt;

The token flag (`TOKEN_UIACCESS`) that allows a process to interact with windows of higher integrity level than its own, bypassing User Interface Privilege Isolation. UI Access is meant for accessibility software (screen readers, on-screen keyboards) that needs to interact with elevated UI. To qualify, an executable must carry a `uiAccess=&quot;true&quot;` manifest, a trusted code-signing certificate, and an administrator-only installation directory; qualifying processes run without showing the consent prompt and at integrity level High [@forshaw-pz-feb2026].
&lt;p&gt;Under classic UAC, a UI Access process ran with the filtered standard-user token bumped from Medium to High integrity -- not with the full admin token. Forshaw&apos;s February 2026 post states the mechanism verbatim: &quot;the service will take a copy of the caller&apos;s access token, enable the UI Access flag and increase the integrity level... If the caller is a limited user of an UAC administrator it will set the integrity level to High&quot; [@forshaw-pz-feb2026].&lt;/p&gt;
&lt;p&gt;Under Administrator Protection, the pre-GA design preserved that behaviour unchanged: the UI Access process inherited the limited user&apos;s primary token (not the SMAA&apos;s), bumped to High integrity. That decision was the structural flaw. A High-integrity process under the limited user can interact with the SMAA&apos;s windows whenever a High-integrity SMAA process exists on the same desktop, send messages to them, read clipboard data, and -- through &lt;code&gt;GetProcessHandleFromHwnd&lt;/code&gt; -- obtain a process handle on the SMAA process that lets the limited-user process inject code into it.&lt;/p&gt;
&lt;p&gt;The five UI Access variants exploit different sub-categories of the same structural property. The Quick Assist binary, a remote assistance application on Windows 10 and 11 that carries the uiAccess flag, is one such variant; R41N3RZUF477 published a public proof-of-concept that exploits the &lt;code&gt;BrowserExecutableFolder&lt;/code&gt; group policy to make Quick Assist load WebView2 from an attacker-controlled directory [@quickassist-bypass]. The remaining four exploit, respectively, weaknesses in the secure-application-directory check, the manifest parsing routine, COM marshalling in UI Access contexts, and message-only window handling [@forshaw-pz-feb2026].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s pre-GA fix is structural: UI Access processes no longer run as the limited user. They are created with a &lt;em&gt;filtered copy of the SMAA&apos;s token&lt;/em&gt; (the SMAA&apos;s SID, the SMAA&apos;s profile, but with &lt;code&gt;SeLoadDriverPrivilege&lt;/code&gt; and similar removed). Profile separation is restored at the cost of a more complex token-creation path [@forshaw-pz-feb2026].&lt;/p&gt;
&lt;h3&gt;The remaining three: implementation flaws&lt;/h3&gt;
&lt;p&gt;The third class -- three bypasses described by Forshaw only as &quot;implementation flaws and long-standing UAC issues&quot; -- is not detailed publicly [@forshaw-pz-jan2026]. The article does not invent details. Forshaw names the category and cites the framing; the engineering specifics are presumably in Microsoft Security Response Center advisories or are still under disclosure. What can be said is that two of the three appear from Forshaw&apos;s framing to be UAC-era bugs that Administrator Protection inherited rather than introduced, and one is an Administrator-Protection-specific implementation flaw.&lt;/p&gt;
&lt;p&gt;The bypass canon ran for twenty years without bulletins. The fact that all nine pre-GA Administrator Protection bypasses received fixes -- including a deep one rooted in the feature itself -- is the structural confirmation that the elevation path is now a boundary. The next section asks why Microsoft pulled the feature in December 2025.&lt;/p&gt;
&lt;h2&gt;13. The compatibility surface and the December 2025 revert&lt;/h2&gt;
&lt;p&gt;About one month after KB5067036 made Administrator Protection available, Microsoft pulled it. Forshaw, writing in January 2026, gives the canonical attribution: &quot;As of 1st December 2025 the Administrator Protection feature has been disabled by Microsoft while an application compatibility issue is dealt with. The issue is unlikely to be related to anything described in this blog post so the analysis doesn&apos;t change&quot; [@forshaw-pz-jan2026]. Microsoft Learn confirms: &quot;The feature previously listed in the October 2025 non-security update (KB5067036) has been reverted and will roll out at a later date&quot; [@ms-admin-protection, @ms-kb5067036].The November 2025 KB5067036 amendment is worth knowing. Microsoft included an unrelated fix for an AutoCAD MSI-repair UAC-prompt regression in the same cumulative; that fix shipped and was not reverted. The WebView2 installer regression is what caused the Administrator Protection revert specifically [@ms-kb5067036].&lt;/p&gt;
&lt;p&gt;The structural causes. The Windows Developer Blog (May 2025) [@ms-developer-blog-2025] enumerates the surface where applications break under the SMAA model.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Single sign-on does not cross.&lt;/strong&gt; Domain and Microsoft Entra credentials cached for the primary user&apos;s session are not available inside the SMAA&apos;s session. Any elevated process touching Microsoft Graph, Entra ID, or Kerberos-protected resources must re-authenticate. The login dialogs an elevated installer triggers are not failures of the application; they are consequences of the separated logon session.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network drives do not carry.&lt;/strong&gt; Drive-mapping in the primary user&apos;s session is not inherited by the SMAA. Installers that mount network shares to install per-machine components break. The workaround for affected installers is to use UNC paths directly rather than drive letters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Library folders diverge.&lt;/strong&gt; Files saved to &lt;code&gt;Documents&lt;/code&gt;, &lt;code&gt;Desktop&lt;/code&gt;, &lt;code&gt;Downloads&lt;/code&gt;, or &lt;code&gt;Pictures&lt;/code&gt; from an elevated app land in &lt;code&gt;C:\Users\ADMIN_&amp;lt;random&amp;gt;\&lt;/code&gt; rather than the primary user&apos;s home. A user clicks Save in an elevated text editor and saves to &quot;Documents&quot;; from their own Explorer, the file is invisible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HKCU diverges.&lt;/strong&gt; Application settings -- theme, recent-files lists, per-user COM registrations, last-opened paths -- live in the SMAA&apos;s &lt;code&gt;HKCU&lt;/code&gt;, not the primary user&apos;s. The canonical example in Microsoft&apos;s documentation is Notepad&apos;s dark-mode theme [@ms-developer-blog-2025]: the primary user sets the theme; an elevated Notepad opens in the default theme; the two sessions never agree.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebView2 installers fail.&lt;/strong&gt; The error message &quot;Microsoft Edge can&apos;t read and write to its data directory&quot; is the recognisable symptom of an installer that assumes one shared profile. The WebView2 runtime stores per-user state in &lt;code&gt;AppData\Local\Microsoft\EdgeWebView\&lt;/code&gt; under whichever profile is active at install time; if the runtime is installed under the SMAA&apos;s profile and then used by an unelevated application running as the primary user, the data-directory write fails. This is the regression that triggered the December 2025 revert.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hyper-V and WSL incompatibilities.&lt;/strong&gt; Microsoft Learn explicitly tells IT administrators not to enable Administrator Protection on devices that require Hyper-V or WSL [@ms-admin-protection].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio.&lt;/strong&gt; Microsoft&apos;s own development environment is &quot;not supported in such a configuration&quot; when run elevated. Extensions don&apos;t carry; settings don&apos;t carry; project-dialog paths point at the SMAA&apos;s profile rather than the developer&apos;s actual workspace.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft Learn explicitly excludes Hyper-V and WSL devices from the recommended enablement set [@ms-admin-protection]. Symptoms of incorrect enablement include WSL distribution startup failures (the WSL service runs under a different account from the launching user, and the SMAA&apos;s logon-session-isolation properties interact badly with WSL&apos;s named-pipe communication) and Hyper-V Manager connection errors that are difficult to attribute to the elevation model.&lt;/p&gt;
&lt;/blockquote&gt;

I guess app compatibility is ultimately the problem here, Windows isn&apos;t designed for such a radical change. I&apos;d have also liked to have seen this as a separate configurable mode rather than replacing admin-approval completely. -- James Forshaw, *Bypassing Windows Administrator Protection*, Google Project Zero, January 26, 2026 [@forshaw-pz-jan2026]

Administrator Protection is the right architecture, and the compatibility surface is the bill of materials for twenty years of admin-as-default assumption. Application developers have written installer logic, theme-persistence code, drive-letter assumptions, and HKCU-shared state into shipping software for two decades, on the structural premise that the elevated process and the unelevated user share a profile. The December 2025 revert is the first iteration&apos;s learning round, not a structural failure. The same revert pattern accompanied the Windows Vista UAC rollout in 2006-2007, the Windows 7 auto-elevation introduction in 2009 (which itself softened the Vista prompt fatigue at the cost of the bypass canon), and the Smart App Control rollout in Windows 11 22H2. Microsoft will re-enable Administrator Protection when the WebView2 regression and a handful of installer-pattern fixes have shipped.
&lt;p&gt;The architecture survives audit. The deployment is held back by twenty years of accumulated software assumptions. The next section asks what tools defenders now have that they did not have before.&lt;/p&gt;
&lt;h2&gt;14. The audit and detection surface&lt;/h2&gt;
&lt;p&gt;Every privileged operation on a device with Administrator Protection enabled now generates an ETW (Event Tracing for Windows) event in the &lt;code&gt;Microsoft-Windows-LUA&lt;/code&gt; provider [@ms-admin-protection]. This is the first time the elevation pipeline itself is the &lt;em&gt;source&lt;/em&gt; of a stable, operationally useful audit trail.&lt;/p&gt;
&lt;p&gt;The basics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provider: &lt;code&gt;Microsoft-Windows-LUA&lt;/code&gt;, GUID &lt;code&gt;{93c05d69-51a3-485e-877f-1806a8731346}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Event ID 15031: Elevation Approved.&lt;/li&gt;
&lt;li&gt;Event ID 15032: Elevation Denied or Failed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each event carries the caller user SID, the application name and path, the elevation outcome, the SMAA used to host the elevation, and the authentication method (Hello PIN, biometric, password) [@ms-admin-protection]. The authentication method field records the &lt;em&gt;primary user&apos;s&lt;/em&gt; Hello credential, not the SMAA&apos;s; the SMAA&apos;s authentication in step 6 of §7 is the credential-less LSA logon and has no method field of its own. The Microsoft Learn-documented &lt;code&gt;logman&lt;/code&gt; invocation to capture the trace is short:&lt;/p&gt;

The Event Tracing for Windows provider that surfaces Administrator Protection elevation events. Provider GUID `{93c05d69-51a3-485e-877f-1806a8731346}`. Event ID 15031 marks an elevation that succeeded; Event ID 15032 marks an elevation that was denied or failed. Each event carries fields for the caller&apos;s SID, the application path, the elevation outcome, the SMAA used, and the authentication method [@ms-admin-protection].
&lt;p&gt;{`
// Pseudocode for a detection pipeline that reads ETW Event 15031
// (Administrator Protection elevation approved) and flags unusual
// application paths per SMAA correlation key.&lt;/p&gt;
&lt;p&gt;const allowList = new Set([
  &apos;C:\\Windows\\System32\\mmc.exe&apos;,
  &apos;C:\\Windows\\System32\\regedit.exe&apos;,
  &apos;C:\\Windows\\System32\\cmd.exe&apos;,
  &apos;C:\\Program Files\\Microsoft VS Code\\Code.exe&apos;,
]);&lt;/p&gt;
&lt;p&gt;function onEtwEvent(event) {
  if (event.provider !== &apos;Microsoft-Windows-LUA&apos;) return;
  if (event.id !== 15031) return;&lt;/p&gt;
&lt;p&gt;  const smaa = event.fields.shadowAccountName;
  const app  = event.fields.applicationPath;
  const auth = event.fields.authenticationMethod;
  const user = event.fields.callerUserSid;&lt;/p&gt;
&lt;p&gt;  if (!allowList.has(app)) {
    emit({
      severity: &apos;high&apos;,
      title: &apos;Unexpected elevation under Administrator Protection&apos;,
      smaa, app, auth, user,
      hint: &apos;Was the Hello prompt phished?&apos;
    });
  }
}
`}&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For detection engineers, the &lt;code&gt;ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt; name is the highest-value correlation key on the device. It is stable per primary admin (the SMAA name is created once and persists across elevations), distinct from the limited-user SID (the SMAA has its own SID, so user-by-SID correlations and SMAA-by-name correlations are independent axes), and present in every ETW 15031 / 15032 event. A detection rule that groups elevations by SMAA name and flags unexpected application paths is the canonical &quot;someone phished a Hello prompt&quot; alert pattern.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Defenders now have the audit trail they did not have under UAC. The next section asks what residual attack surface survives the SMAA architecture, the Hello gate, and the new audit trail.&lt;/p&gt;
&lt;h2&gt;15. Open problems: what survives&lt;/h2&gt;
&lt;p&gt;Five residual attack surfaces, each acknowledged in Microsoft&apos;s own documentation, Forshaw&apos;s Project Zero posts, or the operational literature on Windows privilege escalation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The user is still the weak link.&lt;/strong&gt; Every elevation depends on a human accepting the prompt. The Hello credential gate makes that human&apos;s decision more costly to fake than the classic Yes/No, but the gate does not change the fact that a successful prompt is a successful elevation. The three sub-cases of consent-without-identity-verification from §9 -- unattended-session, habituated-click, pretext click-through -- are cost-raised, not closed. Phishing-the-prompt remains a live attack surface and Microsoft does not classify it as a vulnerability [@forshaw-pz-jan2026]. Out-of-band consent -- a phone-push approval channel, a smartcard tap, a separate hardware key tap -- would close the gap; none of these is the Administrator Protection default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Loopback authentication.&lt;/strong&gt; The structural property that Windows services authenticate to themselves over the local network stack is independent of the SMAA model. SMB to &lt;code&gt;localhost&lt;/code&gt;, Kerberos against the local machine account, NTLM challenge-response between processes on the same box -- these protocols predate UAC and are not changed by Administrator Protection. Forshaw&apos;s broader 2022 Kerberos research [@forshaw-2022-rbcd] catalogues the class. The &lt;a href=&quot;https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows/&quot; rel=&quot;noopener&quot;&gt;NTLMless article&lt;/a&gt; in this series covers SMB signing, Extended Protection for Authentication (EPA), and channel binding mitigations that defenders should pair with Administrator Protection to close the loopback path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service-account &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;.&lt;/strong&gt; The Potato lineage of attacks (cataloged in the &lt;a href=&quot;https://paragmali.com/blog/windows-access-control-25-years-of-attacks/&quot; rel=&quot;noopener&quot;&gt;Access Control article&lt;/a&gt; in this series) runs in service accounts (&lt;code&gt;IIS_IUSRS&lt;/code&gt;, &lt;code&gt;LOCAL SERVICE&lt;/code&gt;, &lt;code&gt;NETWORK SERVICE&lt;/code&gt;), not in interactive admin sessions. Administrator Protection scopes itself to interactive admin elevation; the Potato class is structurally out of scope.&lt;/p&gt;

Service-account Potato attacks run inside `IIS_IUSRS`, `LOCAL SERVICE`, and `NETWORK SERVICE` rather than in interactive admin sessions. The attacker has compromised a service that holds `SeImpersonatePrivilege`, then uses one of several primitives (the SSPI / NEGOEX dance, the EFS RPC interface, a printer-spooler endpoint) to coerce a higher-privileged service into authenticating against the attacker&apos;s local socket, and impersonates the resulting token. Administrator Protection&apos;s promise is around the *interactive elevation* path -- the flow from a logged-in user clicking an installer to an elevated process running. Potato is a separate problem class with its own mitigations: removing `SeImpersonatePrivilege` from service accounts that don&apos;t need it, applying EPA, and patching the named primitives one by one.
&lt;p&gt;&lt;strong&gt;Driver loading once inside an SMAA elevation.&lt;/strong&gt; Admin equals kernel applies once a process is running inside the SMAA. Vulnerable-driver loading, kernel-mode code execution, and rootkit installation fall under the §11 &quot;admin equals kernel&quot; ceiling -- WHQL signing, the Vulnerable Driver Blocklist, App Control for Business, and HVCI remain the four-mechanism mitigation surface, with the App Identity article in this series covering the App Control mechanism. Administrator Protection does not change the relationship between admin and kernel; it changes the relationship between standard user and admin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hello credential phishing surface.&lt;/strong&gt; The prompt now phishes a &lt;em&gt;real credential&lt;/em&gt; rather than a click-through approval. A malicious application that successfully argues its case to the user gets a Hello gesture against the primary user&apos;s PIN or biometric. The credential remains hardware-rooted; ESS-engaged biometrics never leave the TPM or Pluton enclave; the malware does not learn the PIN. But the malware does get the elevation. The Windows Hello article in this series covers FIDO2 / ESS / PIN architecture hardening. Defender-side mitigation is the ETW 15031 / 15032 detection rule set on unexpected application paths [@ms-admin-protection].&lt;/p&gt;
&lt;p&gt;The boundary is real, the audit trail is new, and the five-class residual surface is the next decade of work. The next section turns to operator-side practicalities.&lt;/p&gt;
&lt;h2&gt;16. Practical guide&lt;/h2&gt;
&lt;p&gt;Six tips, each tied to one Microsoft Learn or Windows Developer Blog primary source. Remember that, as of December 2025, Microsoft has reverted the rollout and the feature is currently disabled on stable Windows; the guidance below applies once Microsoft re-enables it. The Spoiler below contains the verbatim commands.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable.&lt;/strong&gt; Set &lt;code&gt;TypeOfAdminApprovalMode = 2&lt;/code&gt; via Group Policy (&quot;User Account Control: Configure type of Admin Approval Mode&quot; -&amp;gt; &quot;Admin Approval Mode with Administrator Protection&quot;) or via the Intune Settings Catalog OMA-URI. A reboot is required for the new policy to take effect [@ms-admin-protection, @ms-kb5067036].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Verify.&lt;/strong&gt; Run &lt;code&gt;whoami&lt;/code&gt; in an elevated console. The profile name shows &lt;code&gt;ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt;. Run &lt;code&gt;whoami /priv&lt;/code&gt; to confirm the SMAA has the Administrators group enabled [@ms-admin-protection, @call4cloud-osint].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Capture.&lt;/strong&gt; Start the ETW trace with the documented &lt;code&gt;logman&lt;/code&gt; invocation; filter for Event IDs 15031 and 15032 [@ms-admin-protection]. The provider GUID is stable across builds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do not enable&lt;/strong&gt; on devices that require Hyper-V or WSL. Re-evaluate when Microsoft re-enables the broad rollout [@ms-admin-protection, @forshaw-pz-jan2026].&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For application developers&lt;/strong&gt;, follow the Windows Developer Blog (May 19, 2025) guidance [@ms-developer-blog-2025]: install per-user packages unelevated; use &lt;code&gt;%ProgramFiles%&lt;/code&gt; (and accept the elevated install path); avoid context switching during install; avoid sharing files between elevated and unelevated profiles; remove auto-elevation dependencies. The auto-elevation manifest attribute is no longer honoured under Administrator Protection, so any installer that relied on silent elevation needs to be reworked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For IT admins&lt;/strong&gt; on already-enabled devices broken by an elevated install: disable Administrator Protection temporarily, reinstall the application unelevated, then re-enable [@ms-developer-blog-2025].&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enable via Group Policy registry value (administrator console, persists across reboots):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# Set TypeOfAdminApprovalMode to 2 (Admin Approval Mode with Administrator Protection)
reg add &quot;HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System&quot; /v TypeOfAdminApprovalMode /t REG_DWORD /d 2 /f
# Reboot required:
shutdown /r /t 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Capture the elevation event trace:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cmd&quot;&gt;logman start AdminProtectionTrace -p {93c05d69-51a3-485e-877f-1806a8731346} -ets
:: After some elevations:
logman stop AdminProtectionTrace -ets
:: Process the .etl with PerfView, Message Analyzer, or:
wevtutil qe Microsoft-Windows-LUA/Operational /q:&quot;*[System[(EventID=15031 or EventID=15032)]]&quot; /f:text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Verify the SMAA presence after enablement:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;Get-LocalUser | Where-Object Name -like &apos;ADMIN_*&apos;
# After an elevation, run from the elevated console:
whoami
# Expect: WIN11-PC\ADMIN_&amp;lt;random16hex&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The single most common mistake in response to an Administrator Protection compatibility problem is to disable UAC globally by setting &lt;code&gt;EnableLUA = 0&lt;/code&gt;. This returns the device to the Windows XP single-token model, removes Mandatory Integrity Control enforcement on application processes, and effectively defeats every layer of UAC and Administrator Protection together. It is universally discouraged. The correct fix is per-application, via manifest, or per-device, via the documented Administrator Protection compatibility list.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Six tips, one boundary, one operational checklist. The next section answers the most common misconceptions.&lt;/p&gt;
&lt;h2&gt;17. Frequently asked questions&lt;/h2&gt;

No. Administrator Protection runs in `appinfo.dll` inside the Application Information service, which runs in `svchost.exe` in VTL0 (the normal Windows kernel context). The SMAA itself is a normal SAM-database account, not a Virtual Secure Mode trustlet. The cross-process protections of Virtualization-Based Security apply to LSASS Credential Guard and a handful of other VTL1 services; the elevation pipeline is not one of them. The Secure Kernel article in this series treats VTL0 / VTL1 separation in detail.

Partially. Administrator Protection replaces Admin Approval Mode UAC when `TypeOfAdminApprovalMode = 2`. The credential-prompt path (the over-the-shoulder elevation that asks a standard user to enter an administrator&apos;s credentials) and classic Admin Approval Mode (`TypeOfAdminApprovalMode = 1`) coexist with Administrator Protection across different configurations [@ms-admin-protection]. On a device with Administrator Protection enabled, only the interactive admin&apos;s elevation path goes through the SMAA; the standard-user-asking-for-admin-credentials path is unchanged.

No. There is absolutely an admin token; it lives in a different account, in a different logon session, for a bounded lifetime. The marketing language describes lifetime and isolation, not nonexistence [@ms-developer-blog-2025, @bleepingcomputer-2024]. The SMAA&apos;s token persists for the lifetime of the elevated process; when the process exits, the token handle is released and the logon session is reaped. Between elevations, no SMAA token exists in memory.

No. Malware can still elevate if the user accepts the Hello prompt. The boundary Administrator Protection creates is between *silent* elevation and *consented* elevation, not between any elevation and none. Microsoft&apos;s design position is explicit: &quot;I expect that malware will still be able to get administrator privileges even if that&apos;s just by forcing a user to accept the elevation prompt&quot; [@forshaw-pz-jan2026]. The three sub-cases of consent-without-identity-verification from §9 are cost-raised, not eliminated. What changes is that the elevation must be visible. Defenders gain the ETW 15031 audit trail as a result.

No. EPM uses a virtual elevated account on a per-request basis with cloud-side policy, and the virtual account is *not* a member of the local Administrators group [@ms-epm-overview]. Administrator Protection uses a persistent local SMAA per admin user, with on-box `appinfo.dll` policy, and the SMAA *is* a member of the local Administrators group [@call4cloud-osint]. EPM is centrally policy-driven and works on standard-user devices; Administrator Protection is per-device architecture and applies only to interactive admin users. The two can coexist on the same device.

No. Per Microsoft Learn, remote logon, roaming profiles, and backup admins are out of scope [@ms-admin-protection]. A domain administrator who logs into a workstation interactively will not see the SMAA path. Microsoft has stated that domain scenarios may be added in future iterations; the current GA-target form is local-machine-only, interactive-admin-only.

No. Mimikatz inside the elevated SMAA session still has `SeDebugPrivilege` and can call `OpenProcess` on `lsass.exe` to dump LSASS unless LSA Protection (Run As Protected Process Light) and Credential Guard are also enabled. Administrator Protection protects the *elevation path*; it does not protect the *resulting privileged session*. To protect the privileged session, pair Administrator Protection with LSA Protection (`RunAsPPL=1`), Credential Guard, App Control for Business, and HVCI. The Secure Kernel article in this series covers the LSA Protection mechanism.
&lt;p&gt;The misconceptions are cleared. The next section returns to the opening hook with the new vocabulary the article has built.&lt;/p&gt;
&lt;h2&gt;18. The user-elevation companion to Credential Guard&lt;/h2&gt;
&lt;p&gt;Return to the two &lt;code&gt;whoami /all&lt;/code&gt; outputs from §1, this time with the vocabulary the article has built.&lt;/p&gt;
&lt;p&gt;The first output shows the primary user under classic UAC. One SID, one profile, one &lt;code&gt;HKCU&lt;/code&gt;, one logon-session LUID; the elevated console is the same user as the unelevated console, distinguished only by the integrity level on the token.&lt;/p&gt;
&lt;p&gt;The second output shows the same login under Administrator Protection. A different user name -- &lt;code&gt;ADMIN_&amp;lt;random&amp;gt;&lt;/code&gt; -- with a different SID linked to the primary admin via &lt;code&gt;ShadowAccountForwardLinkSid&lt;/code&gt; and &lt;code&gt;ShadowAccountBackLinkSid&lt;/code&gt;. A different profile under &lt;code&gt;C:\Users\ADMIN_&amp;lt;random&amp;gt;\&lt;/code&gt;. A different &lt;code&gt;NTUSER.DAT&lt;/code&gt; mapped as &lt;code&gt;HKCU&lt;/code&gt;. A fresh authentication-ID LUID minted by LSASS through the credential-less logon path described in §7, on the strength of &lt;code&gt;appinfo.dll&lt;/code&gt;&apos;s trusted request and a Hello gesture the primary user just performed. An ETW Event 15031 in the &lt;code&gt;Microsoft-Windows-LUA&lt;/code&gt; provider, freshly emitted, recording the elevation as approved, the application path, and the authentication method.&lt;/p&gt;
&lt;p&gt;The thesis lands. The elevation path is now itself a security boundary, with bulletin-grade fixes when it fails. Administrator Protection is the user-elevation companion to Credential Guard. Where Credential Guard isolated LSA secrets from admin-equals-kernel &lt;em&gt;inside&lt;/em&gt; the machine -- the &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel article&lt;/a&gt; in this series covers the VBS-rooted isolation in detail -- Administrator Protection isolates the elevation path &lt;em&gt;from&lt;/em&gt; the standard-user session. The two answer the two halves of the question the foundational Access Control article in this series left open: if admin equals kernel and tokens are bearer credentials, what is left to harden? The answer is the path that gets you there (Administrator Protection) and the data that is there once you arrive (Credential Guard).&lt;/p&gt;
&lt;p&gt;The December 2025 revert is the first iteration&apos;s learning round. The architecture is the right one. The application base catches up next. Forshaw&apos;s framing in February 2026 -- that Microsoft might have shipped this as a configurable mode rather than replacing admin approval completely -- is a reasonable critique, and the re-enablement is likely to address it. Until then, the operational reality on most stable Windows devices is the classic split-token model, with all the bypass canon it implies, and the SMAA design remains an Insider-Preview-and-policy-opted-in posture.&lt;/p&gt;
&lt;p&gt;What stays unchanged is the structural insight. The mechanism Microsoft used to make the elevation path a boundary is not novel; multi-user accounts have shipped in Windows NT since 1993. What changed is the &lt;em&gt;classification&lt;/em&gt;. Microsoft accepted, after twenty years of evidence, that the elevation pipeline needed to be a security boundary, and accepted with it the engineering cost: separate accounts, separate profiles, separate logon sessions, removal of auto-elevation, a credential gate instead of a click-through, an audit-trail ETW provider, and a willingness to ship bulletin-grade fixes for every Forshaw finding. The classification was the engineering decision. Everything else followed.&lt;/p&gt;
&lt;p&gt;This is what it took, in mechanism and in time, to make the elevation path real [@forshaw-pz-jan2026].&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;adminless-administrator-protection-in-windows&quot; keyTerms={[
  { term: &quot;Split-token model&quot;, definition: &quot;The Vista UAC mechanism that issues two access tokens at logon for a member of the local Administrators group: a filtered standard-user token and a linked full administrator token referenced via the TokenLinkedToken field.&quot; },
  { term: &quot;System Managed Administrator Account (SMAA)&quot;, definition: &quot;The hidden local user account that Windows creates per primary administrator when TypeOfAdminApprovalMode = 2, used to host elevated processes in a fresh logon session.&quot; },
  { term: &quot;ShadowAccountForwardLinkSid / ShadowAccountBackLinkSid&quot;, definition: &quot;The paired SAM attributes that encode the trust relationship between a primary admin user and its SMAA.&quot; },
  { term: &quot;TypeOfAdminApprovalMode&quot;, definition: &quot;The registry value selecting the elevation policy: 0 disables UAC; 1 selects classic Admin Approval Mode; 2 selects Admin Approval Mode with Administrator Protection.&quot; },
  { term: &quot;Auto-elevation&quot;, definition: &quot;The Windows 7 mechanism by which selected Microsoft-signed binaries elevated without showing a consent prompt; removed under Administrator Protection.&quot; },
  { term: &quot;COM Elevation Moniker&quot;, definition: &quot;The COM activation syntax that lets an unelevated caller request an elevated instance of a COM server class; the structural primitive of many UACMe bypasses.&quot; },
  { term: &quot;Credential-less LSA logon&quot;, definition: &quot;The mechanism by which LSA mints a primary access token for the SMAA without verifying any SMAA credential, on the strength of appinfo.dll&apos;s trusted request and the primary user&apos;s Hello result.&quot; },
  { term: &quot;Consent-without-identity-verification&quot;, definition: &quot;The primitive by which the legacy UAC consent dialog accepted a click on the secure desktop as sufficient evidence of consent. Administrator Protection&apos;s credential gate cost-raises three sub-cases (unattended-session, habituated-click, pretext click-through) without eliminating any.&quot; },
  { term: &quot;UI Access flag&quot;, definition: &quot;The token flag (TOKEN_UIACCESS) that allows a process to interact with windows of higher integrity, bypassing UIPI; the basis of five of Forshaw&apos;s nine pre-GA Administrator Protection bypasses.&quot; },
  { term: &quot;ETW provider Microsoft-Windows-LUA&quot;, definition: &quot;The Event Tracing for Windows provider, GUID {93c05d69-51a3-485e-877f-1806a8731346}, that surfaces Administrator Protection elevation events. Event 15031 = approved; Event 15032 = denied/failed.&quot; },
  { term: &quot;Security boundary (MSRC servicing criteria)&quot;, definition: &quot;A logical separation between code or data of different trust levels accompanied by a Microsoft commitment to issue a security update when an unauthorised crossing is found. Administrator Protection is the first elevation mechanism to be classified as a security boundary.&quot; }
]} questions={[
  { q: &quot;What four shared resources of the Vista split-token model do the four Administrator Protection fixes attack?&quot;, a: &quot;Same SID across both tokens; same %USERPROFILE%; same HKCU hive; same logon-session LUID.&quot; },
  { q: &quot;Why is the auto-elevation whitelist &apos;the bypass&apos;, in Davidson&apos;s framing?&quot;, a: &quot;The day Microsoft shipped a class of binaries that elevated silently based on signing and path, the entire UAC-bypass problem reduced to making one of those binaries do something the attacker wanted it to do. The whitelist itself was the structural mistake.&quot; },
  { q: &quot;What does the SAM forward/back linkage do at elevation time?&quot;, a: &quot;appinfo.dll&apos;s RAiLaunchAdminProcess reads the calling user&apos;s ShadowAccountForwardLinkSid, walks to the SMAA, and validates the matching ShadowAccountBackLinkSid. Without both attributes pointing at each other, the elevation is refused.&quot; },
  { q: &quot;What is the credential-less LSA logon at step 6 of the Administrator Protection pipeline, and why is the SMAA mintable without a credential?&quot;, a: &quot;After a positive Hello result on the primary user&apos;s credential, appinfo.dll asks the kernel to ask LSA to authenticate a new instance of the shadow administrator. LSA fulfils the request because the requester (appinfo.dll as SYSTEM) is trusted -- the same trust-the-requester pattern SCM uses to obtain service-account tokens -- and the SMAA has no human credential to verify in any case.&quot; },
  { q: &quot;Which class of Forshaw&apos;s nine pre-GA bypasses is uniquely caused by Administrator Protection itself rather than inherited from UAC?&quot;, a: &quot;The lazy DOS device directory hijack. The &apos;fresh logon session per elevation&apos; design property means the per-session DOS device directory is created lazily on first reference; an identification-level impersonation of the SMAA&apos;s linked token could trick the kernel into creating it with the attacker&apos;s owner SID.&quot; },
  { q: &quot;Why did Microsoft revert Administrator Protection on December 1, 2025?&quot;, a: &quot;A WebView2 application-compatibility regression: installers that wrote per-user state into the elevated SMAA&apos;s profile broke under unelevated callers running as the primary user. Forshaw confirmed the revert was unrelated to security findings.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows</category><category>security</category><category>uac</category><category>administrator-protection</category><category>privilege-escalation</category><category>windows-hello</category><category>project-zero</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>&quot;Can This Code Do This?&quot; -- Twenty-Five Years of Attacks on the Windows Access-Control Model</title><link>https://paragmali.com/blog/windows-access-control-25-years-of-attacks/</link><guid isPermaLink="true">https://paragmali.com/blog/windows-access-control-25-years-of-attacks/</guid><description>How a single kernel function, SeAccessCheck, decides every Windows operation -- and how Mimikatz, the Potato lineage, and seventy UAC bypasses each attack one of its inputs.</description><pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate><content:encoded>
Windows answers the question *can this code do this?* with one kernel function, `SeAccessCheck`, evaluated against five inputs: a security descriptor, an access token, a desired-access mask, a generic-mapping table, and any previously-granted access. The function and its inputs have not structurally changed since July 27, 1993. Every famous Windows local-privilege-escalation tool of the last twenty-five years -- Mimikatz, JuicyPotato and seven other Potatoes, the seventy AutoElevate-redirect methods catalogued in UACMe -- attacks one of those inputs. This article tells that story as one system, names the five structural limits Microsoft has publicly conceded, and explains why Adminless, NTLMless, VBS Trustlets, and Credential Guard are the four non-overlapping ways to close them.
&lt;h2&gt;1. One Question, Billions of Times a Second&lt;/h2&gt;
&lt;p&gt;Open a Windows PowerShell window and run &lt;code&gt;whoami /priv&lt;/code&gt;. Read the column on the right. &lt;code&gt;SeShutdownPrivilege&lt;/code&gt;. &lt;code&gt;SeUndockPrivilege&lt;/code&gt;. &lt;code&gt;SeIncreaseWorkingSetPrivilege&lt;/code&gt;. &lt;code&gt;SeTimeZonePrivilege&lt;/code&gt;. About twenty rows of capabilities, almost all marked &lt;em&gt;Disabled&lt;/em&gt;, on a token that lives inside &lt;code&gt;explorer.exe&lt;/code&gt;&apos;s memory and that the kernel consults billions of times a second.&lt;/p&gt;
&lt;p&gt;Now run &lt;code&gt;icacls C:\Windows\System32\drivers\etc\hosts&lt;/code&gt;. The output reads &lt;code&gt;BUILTIN\Administrators:(F)&lt;/code&gt;, &lt;code&gt;NT AUTHORITY\SYSTEM:(F)&lt;/code&gt;, &lt;code&gt;BUILTIN\Users:(R)&lt;/code&gt;. Six characters per principal, decoded by something inside the kernel called &lt;code&gt;SeAccessCheck&lt;/code&gt;, applied to a data structure called a security descriptor, against a credential called an access token, every time any process anywhere on the machine asks for read access to that single file [@ms-learn-access-control].&lt;/p&gt;
&lt;p&gt;This article is about the model behind those two outputs. A model that has not structurally changed since July 27, 1993, when Windows NT 3.1 shipped from Redmond [@en-wiki-windows-nt-3-1]. A model that every famous Windows local-privilege-escalation tool of the last twenty-five years -- Mimikatz, JuicyPotato, fodhelper.exe, the seventy methods in the open-source UACMe catalogue -- exists to attack [@github-gentilkiwi-mimikatz, @github-ohpe-juicy-potato, @github-hfiref0x-uacme].&lt;/p&gt;
&lt;p&gt;The thesis comes in three convictions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SeAccessCheck&lt;/code&gt; is the answer.&lt;/strong&gt; Every securable Windows operation that touches a securable object resolves through one decision function with one set of inputs [@ms-learn-how-dacls-control-access].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every famous Windows escalation tool attacks one of those inputs.&lt;/strong&gt; JuicyPotato attacks the token. Mimikatz attacks the privilege list. Fodhelper attacks the elevation flow that produces the token. HiveNightmare attacks the DACL on a single file [@nvd-cve-2021-36934]. The vocabulary scales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The model has five structural limits its keepers have publicly conceded&lt;/strong&gt; [@msrc-servicing-criteria], and Adminless, NTLMless, VBS Trustlets, and Credential Guard are the four non-overlapping ways to close them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The forecast for the next 14,000 words: ten primitives (the Security Reference Monitor, security identifiers, tokens, security descriptors, DACLs, SACLs, ACEs, privileges, Mandatory Integrity Control, User Account Control), one canonical oracle (&lt;code&gt;SeAccessCheck&lt;/code&gt;), two attack families (the Potato lineage and the UACMe bypass tradition), and four successor architectures (Adminless, NTLMless, VBS Trustlets, Credential Guard).&lt;/p&gt;
&lt;p&gt;If the model has not structurally changed since 1993, why has it taken thirty-three years and seventy bypasses to map its failure modes -- and what does each generation tell us about the next?&lt;/p&gt;
&lt;h2&gt;2. Origins: From Lampson&apos;s Matrix to Cutler&apos;s Kernel (1971-1993)&lt;/h2&gt;
&lt;p&gt;The vocabulary starts in a paper Butler Lampson presented at Princeton in 1971 and the ACM republished in &lt;em&gt;Operating Systems Review&lt;/em&gt; in January 1974. Lampson framed protection as a 2-D matrix: rows index the &lt;em&gt;subjects&lt;/em&gt; (users, processes), columns index the &lt;em&gt;objects&lt;/em&gt; (files, devices, memory pages), and the cell at the intersection holds the &lt;em&gt;operations&lt;/em&gt; the subject is permitted on the object. The matrix is a sparse, mostly-empty table the size of every-process times every-file. No real system has ever stored it that way.&lt;/p&gt;
&lt;p&gt;Two implementation strategies fall out of the formalism. Slice the matrix by row and you get &lt;em&gt;capability lists&lt;/em&gt;: each subject carries a token that names the objects it can touch. Slice by column and you get &lt;em&gt;access-control lists&lt;/em&gt;: each object carries a list of subjects allowed to touch it. Lampson worked through both in the paper. Operating systems built on the second slice came to dominate, partly because hardware in 1971 made unforgeable capabilities expensive, partly because file systems could carry an ACL at the inode without changing every program. Decades later, the gap between the two implementations would still matter; we will reach Norm Hardy&apos;s &quot;Confused Deputy&quot; in a moment.&lt;/p&gt;
&lt;p&gt;The lever that turned theory into Windows came from procurement, not academia. On December 26, 1985, the U.S. Department of Defense published &lt;code&gt;DoD 5200.28-STD&lt;/code&gt;, the &lt;em&gt;Trusted Computer System Evaluation Criteria&lt;/em&gt;, known by the colour of its cover as the Orange Book [@nist-csrc-rainbow]. The Orange Book defined four divisions of trusted-system assurance, and its C2 class -- &quot;Controlled Access Protection&quot; -- made discretionary access control plus auditing a federal procurement floor. The September 30, 1987 Neon Orange Book (NCSC-TG-003) and the July 28, 1987 Tan Book (NCSC-TG-001) elaborated DAC and audit respectively [@nist-csrc-rainbow]. After 1985, no operating system that wanted U.S. federal customers could ship without per-user ACLs and an audit log.&lt;/p&gt;
&lt;p&gt;A year before the Orange Book ossified DAC into procurement, Norm Hardy of the Tymshare / KeyKOS lineage published a three-page paper in &lt;em&gt;Operating Systems Review&lt;/em&gt; that named the structural limit of the entire ACL-shaped class: &quot;The Confused Deputy (or why capabilities might have been invented)&quot; [@wayback-cap-lore-hardy]. Hardy described a privileged compiler that wrote billing records to a system file. A user could trick the compiler into writing the user&apos;s &lt;em&gt;output&lt;/em&gt; file over the billing file, because the compiler used &lt;em&gt;its own&lt;/em&gt; authority on every write and could not distinguish &quot;authority I have&quot; from &quot;authority the caller asked me to use.&quot;&lt;/p&gt;
&lt;p&gt;The Wikipedia summary of the field is exact: &quot;Capability systems protect against the confused deputy problem, whereas access-control list-based systems do not&quot; [@en-wiki-confused-deputy]. Hold this paper. It will come back in Section 10.&lt;/p&gt;

The team that built Windows NT was not assembled in Redmond. David Cutler arrived in October 1988 from Digital Equipment Corporation [@en-wiki-cutler], where he had led VMS and the cancelled Mica successor, and brought with him a fraction of his old DEC team.&lt;p&gt;The cultural import mattered: VAX/VMS, announced October 25, 1977 alongside the VAX-11/780 (V1.0 shipped August 1978) [@en-wiki-openvms], introduced UIC-based file protection and a kernel-mode security architecture, and by the mid-1980s the VAX/VMS line had been evaluated at TCSEC Class C2 [@en-wiki-openvms], by which time the system had been hardened with per-object ACLs, audit channels, and an explicit reference monitor. That C2-hardened VMS was the cultural reference Cutler brought with him to Microsoft. G. Pascal Zachary&apos;s &lt;em&gt;Showstopper!&lt;/em&gt; tells the story of the four-year build of NT 3.1 from that team [@showstopper-zachary].&lt;/p&gt;
&lt;p&gt;The point for this article is narrower. NT 3.1&apos;s nine access-control primitives -- Security Reference Monitor, security identifier, access token, security descriptor, DACL, SACL, ACE, privileges, audit channel -- did not arrive piecemeal. They were specified together, before the first line of &lt;code&gt;SeAccessCheck&lt;/code&gt; was written, against a procurement standard the team intended to clear.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;NT 3.1 released to manufacturing on July 27, 1993 [@en-wiki-windows-nt-3-1]. NT 3.5, released to manufacturing on September 21, 1994 [@en-wiki-nt-3-5], was hardened through Service Pack 3 (June 21, 1995) and was rated by the National Security Agency in July 1995 as complying with TCSEC C2 criteria against the standalone single-user configuration [@en-wiki-nt-3-5]; NT 4.0 Service Pack 6a was evaluated at TCSEC C2 in a standalone (non-networked) configuration, consistent with NT 3.5 SP3. The combination froze the model. Once C2 evaluation was on the books, structural changes to the access-control surface would have required re-evaluation. Federal procurement obligations have kept the structural shape intact for thirty-one years, even after the Department of Defense formally retired TCSEC in favour of the Common Criteria.&lt;/p&gt;
&lt;p&gt;Cutler shipped a model that has answered &quot;can this code do this?&quot; the same way for thirty-three years. What is the actual function -- and what are its inputs?&lt;/p&gt;
&lt;h2&gt;3. The Kernel Oracle: &lt;code&gt;SeAccessCheck&lt;/code&gt; and Its Inputs&lt;/h2&gt;
&lt;p&gt;The function has one signature, one return value, and one job. Microsoft&apos;s Win32 documentation exposes a user-mode mirror called &lt;code&gt;AccessCheck&lt;/code&gt; that lets userland code ask the question without holding a handle, and a kernel routine called &lt;code&gt;SeAccessCheck&lt;/code&gt; that the kernel invokes at every securable operation [@ms-learn-access-control, @ms-learn-access-tokens]. The shape is the same in both directions:&lt;/p&gt;
&lt;p&gt;$$
\textsf{SeAccessCheck}(\textit{SD}, \textit{Token}, \textit{DesiredAccess}) \to (\textit{GrantedAccess}, \textit{Status})
$$&lt;/p&gt;
&lt;p&gt;Three inputs in (a security descriptor, an access token, a requested-access mask), two outputs out (the access mask actually granted, and a &lt;code&gt;STATUS_ACCESS_DENIED&lt;/code&gt; flavour if any). Two more hidden inputs make the kernel signature precise: a &lt;em&gt;generic mapping&lt;/em&gt; table that translates the four generic rights (&lt;code&gt;GENERIC_READ&lt;/code&gt;, &lt;code&gt;GENERIC_WRITE&lt;/code&gt;, &lt;code&gt;GENERIC_EXECUTE&lt;/code&gt;, &lt;code&gt;GENERIC_ALL&lt;/code&gt;) into object-type-specific bits, and a &lt;em&gt;previously-granted-access&lt;/em&gt; mask that the kernel carries forward when an access check happens in two phases. Together: five inputs, one decision, one log entry (the documented kernel routine carries a few additional parameters of kernel-internal bookkeeping -- a synchronization flag, an &lt;code&gt;AccessMode&lt;/code&gt; discriminator that elides the check for kernel-mode callers, and a privileges out-parameter -- which the explanatory five-input model collapses; the user-mode &lt;code&gt;AccessCheck&lt;/code&gt; mirror is closer to the model the article uses).&lt;/p&gt;

The kernel-mode component of the Windows NT executive that performs all access checks against securable objects. It owns `SeAccessCheck` and the audit log generation routines. The SRM is a *subsystem*, not a feature: every other kernel component that needs to grant or deny access calls into it.

The Windows kernel routine that decides whether a thread may perform a requested set of operations on an object. It takes a security descriptor, an access token, a desired-access mask, a per-object-type generic-mapping table, and any previously-granted access. (The documented kernel signature also carries a synchronization flag, an `AccessMode` discriminator that elides the check for kernel-mode callers, and a privileges out-parameter; the five-input model used here is an explanatory simplification that the user-mode `AccessCheck` mirror tracks more closely.) It returns the subset of the desired-access mask that the kernel grants and a status code. Every call site that opens or modifies a securable object eventually reaches this function [@ms-learn-how-dacls-control-access].
&lt;p&gt;The five inputs are not equally exotic. The desired-access mask and the generic-mapping table are bookkeeping that an object type defines once at registration time. The previously-granted-access input is the kernel handing itself a pencil for two-phase access checks, mostly invisible to userland. The two inputs the rest of the article will keep returning to are the security descriptor and the access token.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;security descriptor&lt;/em&gt; is the data structure attached to the object. It carries an owner SID, a primary-group SID, a discretionary access-control list (DACL) of allow / deny / audit entries, and a system access-control list (SACL) holding audit and integrity-label entries [@ms-learn-mic]. The DACL is what &lt;code&gt;icacls&lt;/code&gt; prints. The SACL is what writes Event Log entries when something the descriptor&apos;s writer wanted to watch happens.&lt;/p&gt;
&lt;p&gt;An &lt;em&gt;access token&lt;/em&gt; is the data structure attached to the caller. It names the user (one SID), the user&apos;s groups (a list of SIDs), the privileges the user holds (a list of named superpowers), the integrity level the kernel will compare against the object&apos;s label, and a flag that says whether the token is a &lt;em&gt;primary&lt;/em&gt; token (one per process) or an &lt;em&gt;impersonation&lt;/em&gt; token (one per thread, used to act on a client&apos;s behalf) [@ms-learn-access-tokens].&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s documentation lists the token&apos;s contents almost as bullet points: &quot;The security identifier (SID) for the user&apos;s account; SIDs for the groups of which the user is a member; A logon SID that identifies the current logon session; A list of the privileges held by either the user or the user&apos;s groups; An owner SID; The SID for the primary group; The default DACL; ... Whether the token is a primary or impersonation token; An optional list of restricting SIDs; Current impersonation levels...&quot; [@ms-learn-access-tokens].&lt;/p&gt;
&lt;p&gt;The flow inside &lt;code&gt;SeAccessCheck&lt;/code&gt; is mechanical. The kernel maps &lt;code&gt;DesiredAccess&lt;/code&gt; from generic to specific bits using the type&apos;s mapping table. It checks the integrity label of the object against the integrity level on the token (Mandatory Integrity Control runs &lt;em&gt;before&lt;/em&gt; the DACL walk, a point Section 7 expands). It walks the DACL in order, deny-first, accumulating bits granted by allow ACEs whose SID is in the token&apos;s list. It applies a &lt;em&gt;privilege bypass&lt;/em&gt; short-circuit if the caller holds &lt;code&gt;SeBackupPrivilege&lt;/code&gt;, &lt;code&gt;SeRestorePrivilege&lt;/code&gt;, &lt;code&gt;SeDebugPrivilege&lt;/code&gt;, or one of the other privileges that grants access to whole classes of objects without consulting the DACL. It returns the accumulated &lt;code&gt;GrantedAccess&lt;/code&gt;, or &lt;code&gt;STATUS_ACCESS_DENIED&lt;/code&gt; if the requested bits were not all granted.&lt;/p&gt;

sequenceDiagram
    participant App as User-mode caller
    participant ObjMgr as Object Manager
    participant SRM as Security Reference Monitor
    participant Audit as Audit channel
    App-&amp;gt;&amp;gt;ObjMgr: OpenObject(name, DesiredAccess, ImpersonationToken)
    ObjMgr-&amp;gt;&amp;gt;ObjMgr: Resolve name (\BaseNamedObjects, \Device, \??)
    ObjMgr-&amp;gt;&amp;gt;ObjMgr: Fetch security descriptor from object header
    ObjMgr-&amp;gt;&amp;gt;SRM: SeAccessCheck(SD, Token, DesiredAccess)
    SRM-&amp;gt;&amp;gt;SRM: Map generic rights via type mapping
    SRM-&amp;gt;&amp;gt;SRM: Check mandatory integrity label
    SRM-&amp;gt;&amp;gt;SRM: Privilege-bypass short-circuit (SeBackup, SeRestore, SeDebug)
    SRM-&amp;gt;&amp;gt;SRM: Walk DACL in canonical order, deny-first
    SRM--&amp;gt;&amp;gt;ObjMgr: GrantedAccess + STATUS code
    ObjMgr-&amp;gt;&amp;gt;Audit: Emit SACL audit ACE if matched
    ObjMgr--&amp;gt;&amp;gt;App: HANDLE or STATUS_ACCESS_DENIED
&lt;p&gt;Five inputs. One function. One log entry on the way out. The thesis statement of this article is the consequence: every later section is an attack on one of those inputs. JuicyPotato attacks the token. Mimikatz attacks the privilege list. Fodhelper attacks the elevation flow that produces the token. HiveNightmare attacks the security descriptor on a single file. Conditional ACEs and Dynamic Access Control extend the matrix&apos;s &lt;em&gt;subject&lt;/em&gt; dimension by adding claims to the token. UAC tries to keep the token small by default and only inflate it on demand. Every primitive in the article maps cleanly onto one of &lt;code&gt;SeAccessCheck&lt;/code&gt;&apos;s five inputs, and every famous attack tool in the article maps cleanly onto one primitive.&lt;/p&gt;
&lt;p&gt;The function is fixed. The inputs are five. So how does the kernel actually walk a DACL -- and where does the wrong answer come from?&lt;/p&gt;
&lt;h2&gt;4. The DACL Algorithm and the SID Namespace&lt;/h2&gt;
&lt;p&gt;&quot;Walk the DACL in order.&quot; Six words that have generated hundreds of thousands of misconfigured ACLs since 1993. The Microsoft Learn page that ships the algorithm is short and exact. The system &quot;examines each ACE in sequence until... an access-denied ACE explicitly denies any of the requested access rights to one of the trustees listed in the thread&apos;s access token... one or more access-allowed ACEs for trustees listed in the thread&apos;s access token explicitly grant all the requested access rights... All ACEs have been checked and there is still at least one requested access right that has not been explicitly allowed, in which case, access is implicitly denied&quot; [@ms-learn-how-dacls-control-access].&lt;/p&gt;
&lt;p&gt;Three terminations. Deny terminates with denial. Enough allows terminates with grant. End-of-list with anything left ungranted terminates with denial. Note the asymmetry the algorithm encodes: a single deny anywhere in the DACL kills the request, but an allow has to be paired with explicit coverage of every desired bit. The default is denial.&lt;/p&gt;

The ordered list of access-control entries (ACEs) attached to a securable object&apos;s security descriptor that specifies which trustees are granted or denied which access rights. *Discretionary* means the object&apos;s owner controls the list, in contrast to a mandatory list whose entries the system enforces independent of owner intent.

A single grant, deny, audit, or mandatory-label record inside a DACL or SACL. Each ACE carries an SID identifying the trustee, a 32-bit access mask, a flags byte controlling inheritance, and a type discriminator. Windows defines four primary ACE types (`ACCESS_ALLOWED_ACE`, `ACCESS_DENIED_ACE`, `SYSTEM_AUDIT_ACE`, `SYSTEM_MANDATORY_LABEL_ACE`) plus callback variants for conditional ACEs [@ms-learn-ace-strings].
&lt;p&gt;{`
// Faithful implementation of the algorithm at
// learn.microsoft.com/en-us/windows/win32/secauthz/how-dacls-control-access-to-an-object
// Inputs: token (set of SIDs), DACL (ordered ACEs), desiredAccess mask.
// Output: granted mask + a per-ACE trace of why.&lt;/p&gt;
&lt;p&gt;function seAccessCheck(token, dacl, desiredAccess) {
  let remaining = desiredAccess;       // bits still needed
  let granted = 0;                     // bits accumulated so far
  const trace = [];&lt;/p&gt;
&lt;p&gt;  // NULL DACL grants everything; empty DACL grants nothing.
  if (dacl === null) {
    return { status: &apos;GRANTED (NULL DACL)&apos;, granted: desiredAccess, trace: [&apos;NULL DACL: full access&apos;] };
  }
  if (dacl.length === 0) {
    return { status: &apos;DENIED (empty DACL)&apos;, granted: 0, trace: [&apos;Empty DACL: no access&apos;] };
  }&lt;/p&gt;
&lt;p&gt;  for (let i = 0; i &amp;lt; dacl.length; i++) {
    const ace = dacl[i];
    const sidMatches = token.sids.includes(ace.sid);
    if (!sidMatches) {
      trace.push(`ACE ${i} (${ace.type} ${ace.sid}): SID not in token; skip`);
      continue;
    }
    if (ace.type === &apos;DENY&apos;) {
      const deniedBits = ace.mask &amp;amp; remaining;
      if (deniedBits !== 0) {
        trace.push(`ACE ${i}: DENY hits 0x${deniedBits.toString(16)} -&amp;gt; ACCESS_DENIED`);
        return { status: &apos;DENIED&apos;, granted: 0, trace };
      }
      trace.push(`ACE ${i}: DENY ${ace.sid} 0x${ace.mask.toString(16)} -- no requested bit hit; skip`);
    } else if (ace.type === &apos;ALLOW&apos;) {
      const newBits = ace.mask &amp;amp; remaining;
      granted |= newBits;
      remaining &amp;amp;= ~newBits;
      trace.push(`ACE ${i}: ALLOW grants 0x${newBits.toString(16)}, remaining 0x${remaining.toString(16)}`);
      if (remaining === 0) {
        return { status: &apos;GRANTED&apos;, granted, trace };
      }
    }
  }
  return { status: &apos;DENIED (end of DACL with bits unsatisfied)&apos;, granted: 0, trace };
}&lt;/p&gt;
&lt;p&gt;// Demo: a token with the user&apos;s SID and BUILTIN\Users; DACL with explicit deny + Everyone allow.
const token = { sids: [&apos;S-1-5-21-A-B-C-1001&apos;, &apos;S-1-5-32-545&apos;, &apos;S-1-1-0&apos;] };
const dacl = [
  { type: &apos;DENY&apos;,  sid: &apos;S-1-5-21-A-B-C-1001&apos;, mask: 0x00040000 },  // deny WRITE_DAC
  { type: &apos;ALLOW&apos;, sid: &apos;S-1-1-0&apos;,              mask: 0x00120089 }, // FILE_GENERIC_READ
  { type: &apos;ALLOW&apos;, sid: &apos;S-1-5-32-545&apos;,         mask: 0x001200A9 }, // GENERIC_READ + EXECUTE
];
console.log(seAccessCheck(token, dacl, 0x00040089));
`}&lt;/p&gt;
&lt;p&gt;The runnable above implements three subtleties the prose can flatten. First: the &lt;em&gt;NULL DACL&lt;/em&gt; versus &lt;em&gt;empty DACL&lt;/em&gt; distinction. A descriptor with no DACL at all -- a literal &lt;code&gt;NULL&lt;/code&gt; pointer where the list would be -- grants full access, on the theory that the writer expressed no policy and the kernel will not invent one. A descriptor with a DACL that exists but contains zero ACEs denies everything, because the writer expressed a policy and that policy has no allows. The single most common high-impact misconfiguration in the Windows codebase is code that meant to write the second and wrote the first, or vice versa.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Newly-written code that &quot;creates a file with no protection&quot; almost always wants an empty DACL but ends up with a NULL DACL because of how the SECURITY_DESCRIPTOR initialisation defaults work. Verify with &lt;code&gt;Get-Acl&lt;/code&gt; or &lt;code&gt;icacls&lt;/code&gt; after creation; a NULL DACL surface in &lt;code&gt;icacls&lt;/code&gt; looks like &lt;code&gt;Everyone:(F)&lt;/code&gt; and is almost always a bug, not a feature [@ms-learn-how-dacls-control-access].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Second: ACE &lt;em&gt;order&lt;/em&gt; is the caller&apos;s responsibility. The kernel walks the list in the order it finds it. The &quot;canonical&quot; order Windows expects is four-step, quoted verbatim from the Microsoft Learn reference [@ms-learn-order-of-aces]: &quot;1. All explicit ACEs are placed in a group before any inherited ACEs. 2. Within the group of explicit ACEs, access-denied ACEs are placed before access-allowed ACEs. 3. Inherited ACEs are placed in the order in which they are inherited... 4. For each level of inherited ACEs, access-denied ACEs are placed before access-allowed ACEs.&quot;&lt;/p&gt;
&lt;p&gt;The same page underlines who has to enforce the order: &quot;Functions such as &lt;code&gt;AddAccessAllowedAceEx&lt;/code&gt; and &lt;code&gt;AddAccessAllowedObjectAce&lt;/code&gt; add an ACE to the end of an ACL. It is the caller&apos;s responsibility to ensure that the ACEs are added in the proper order.&quot; If the writer of the DACL hands the kernel an out-of-order list with a deny ACE buried after a wide allow ACE, the deny will be unreachable and the descriptor will silently grant more than the writer intended.&lt;/p&gt;
&lt;p&gt;Third: there is no special case for &quot;Everyone.&quot; The well-known SID &lt;code&gt;S-1-1-0&lt;/code&gt; exists in every token of every process on the machine; an ACE against it applies to every caller. There is no extra logic that says &quot;if this is Everyone, treat it differently from any other group.&quot; James Forshaw made the point with characteristic bluntness in 2020: &quot;don&apos;t forget S-1-1-0, this is NOT A SECURITY BOUNDARY. Lah lah, I can&apos;t hear you!&quot; [@tiraniddo-sharing-logon-session]. The DACL evaluation algorithm does not know &quot;Everyone&quot; is special. It is a SID like any other.&lt;/p&gt;
&lt;p&gt;That makes the SID namespace itself worth a tour. Microsoft documents the structure as a revision number, an &lt;em&gt;identifier authority&lt;/em&gt; (a six-byte field that says which authority issued the SID), a list of sub-authorities, and a final &lt;em&gt;relative identifier&lt;/em&gt; (RID) [@ms-learn-security-identifiers]. Microsoft&apos;s own page on SIDs is precise: &quot;A security identifier (SID) is a unique value of variable length used to identify a trustee... When a SID has been used as the unique identifier for a user or group, it cannot ever be used again to identify another user or group.&quot;&lt;/p&gt;
&lt;p&gt;The well-known SIDs the kernel recognises by name include &lt;code&gt;SYSTEM&lt;/code&gt; (S-1-5-18), &lt;code&gt;LocalService&lt;/code&gt; (S-1-5-19), &lt;code&gt;NetworkService&lt;/code&gt; (S-1-5-20), &lt;code&gt;Everyone&lt;/code&gt; (S-1-1-0), &lt;code&gt;Authenticated Users&lt;/code&gt; (S-1-5-11), and the four Mandatory Integrity Control levels (S-1-16-4096 / 8192 / 12288 / 16384) [@en-wiki-mic, @ms-learn-mic]. Machine-issued SIDs encode the machine&apos;s domain identity in the sub-authorities; domain-issued SIDs encode the domain identity. RID 500 is, by convention, the local Administrator account; RID 501 is the Guest account.&lt;/p&gt;

A variable-length, never-reused identifier for a trustee (user, group, machine, service, or capability) inside the Windows security model. SIDs are encoded in canonical form `S-R-I-S1-S2-...-RID`, where R is a revision number, I is the identifier authority, the Sn are sub-authorities issued by that authority, and RID is the relative identifier. Every ACE references an SID; every token contains a list of them [@ms-learn-security-identifiers].
&lt;p&gt;James Forshaw documented in 2017 that Windows generates the per-service SID for &lt;code&gt;NT SERVICE\&amp;lt;ServiceName&amp;gt;&lt;/code&gt; deterministically: it is the SHA-1 hash of the uppercased service name, formatted into the SID&apos;s sub-authority fields. This is why Windows can refer to running services as security principals without an explicit registration step -- the kernel derives the SID on demand [@tiraniddo-trustedinstaller-blog].&lt;/p&gt;
&lt;p&gt;Two SID families this article will not derive: AppContainer &lt;em&gt;Package SIDs&lt;/em&gt; (S-1-15-2-...) and &lt;em&gt;capability SIDs&lt;/em&gt; (S-1-15-3-...). Both arrived with Windows 8 in 2012 and extend the matrix&apos;s subjects with code identity and capability tokens. The sibling &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;App Identity article&lt;/a&gt; in this series carries the canonical derivation, including the Crockford-Base32 PublisherId derivation that produces a Package SID from an MSIX package signature [@app-identity-sibling]. Section 5 of &lt;em&gt;this&lt;/em&gt; article will mention those SIDs in tokens; we will not redefine them here.&lt;/p&gt;
&lt;p&gt;The DACL is half the story. What does the &lt;em&gt;thread&lt;/em&gt; bring to the access check -- and why is the answer &quot;whoever happens to hold the handle&quot;?&lt;/p&gt;
&lt;h2&gt;5. Tokens as Bearer Credentials&lt;/h2&gt;
&lt;p&gt;A token is not a credential the way a password is. A token is a credential the way &lt;em&gt;cash&lt;/em&gt; is: whoever holds it gets the rights. This is the single most important property in the article.&lt;/p&gt;
&lt;p&gt;Microsoft splits tokens into two flavours by purpose [@ms-learn-access-tokens]. A &lt;em&gt;primary token&lt;/em&gt; hangs off a process and represents the security identity that process runs as. Every process has exactly one. An &lt;em&gt;impersonation token&lt;/em&gt; hangs off a thread and lets that thread temporarily act as someone else -- typically a network client whose request the thread is servicing. Tokens are kernel objects with handles, and like every other kernel object the kernel does not care how a process obtained the handle. If the handle resolves to a token in the kernel&apos;s table, the kernel grants the rights the token names.&lt;/p&gt;

A kernel object that names the security identity of a thread or process. It carries the user&apos;s SID, the SIDs of the user&apos;s groups, the privileges the user holds, an integrity level, an integrity-level mandatory policy, an optional list of *restricting* SIDs, a flag distinguishing primary from impersonation tokens, and the impersonation level (Anonymous / Identification / Impersonation / Delegation) [@ms-learn-access-tokens]. The kernel consults a token on every access check for the thread that holds it.

A *primary token* is owned by a process and represents the identity the process runs as; every process has exactly one primary token. An *impersonation token* is owned by a thread and represents an identity the thread is temporarily acting on behalf of -- typically a network client. The primary / impersonation distinction is a discriminator inside the token itself, set when the token is created or duplicated [@ms-learn-access-tokens].
&lt;p&gt;The impersonation flavour acquired its modern shape in Windows 2000. A token&apos;s &lt;em&gt;impersonation level&lt;/em&gt; takes one of four values, ordered from least to most privileged for the impersonator. &lt;em&gt;Anonymous&lt;/em&gt; lets the server know nothing about the client. &lt;em&gt;Identification&lt;/em&gt; lets the server learn the client&apos;s SIDs but not act as the client. &lt;em&gt;Impersonation&lt;/em&gt; lets the server perform local access checks as the client; this is the level a typical RPC server requests. &lt;em&gt;Delegation&lt;/em&gt; lets the server forward the client&apos;s identity onto another machine, useful for multi-hop scenarios but a frequent source of relay-style bugs. Almost every Potato lineage attack consumes an &lt;em&gt;Impersonation&lt;/em&gt;-level token; that is enough to call &lt;code&gt;ImpersonateLoggedOnUser&lt;/code&gt; and run as the client [@itm4n-printspoofer-blog].&lt;/p&gt;
&lt;p&gt;Microsoft documents a third token shape, the &lt;em&gt;restricted token&lt;/em&gt;, that is rare in practice but worth understanding because it is the only place in the model where an explicit deny-list lives on the token itself rather than the descriptor. A restricted token combines three knobs: a list of SIDs converted to &lt;em&gt;deny-only&lt;/em&gt; (their grants count for no allow ACE but their presence still triggers deny ACEs), a list of &lt;em&gt;restricting SIDs&lt;/em&gt; that the access check must independently permit, and a list of privileges removed from the token&apos;s privilege set [@ms-learn-restricted-tokens].&lt;/p&gt;
&lt;p&gt;The kernel runs &lt;code&gt;SeAccessCheck&lt;/code&gt; twice and grants only the intersection: &quot;When a restricted process or thread tries to access a securable object, the system performs two access checks: one using the token&apos;s enabled SIDs, and another using the list of restricting SIDs. Access is granted only if both access checks allow the requested access rights&quot; [@ms-learn-restricted-tokens]. Restricted tokens are operationally niche because the same documentation requires applications using them to &quot;run the restricted application on desktops other than the default desktop. This is necessary to prevent an attack by a restricted application, using &lt;code&gt;SendMessage&lt;/code&gt; or &lt;code&gt;PostMessage&lt;/code&gt;, to unrestricted applications on the default desktop&quot; [@ms-learn-restricted-tokens]. Few applications can spare the desktop overhead.&lt;code&gt;whoami /priv&lt;/code&gt; shows &lt;em&gt;available&lt;/em&gt; privileges, not &lt;em&gt;enabled&lt;/em&gt; privileges. The &lt;code&gt;Enabled&lt;/code&gt; column is the load-bearing one: an available-but-disabled privilege does not affect any access check until the process explicitly enables it via &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt;. The discipline of leaving privileges disabled by default is a defence in depth that depends on the application not having an exploitable bug between disable and use.&lt;/p&gt;
&lt;p&gt;A token also carries flags that drive specific runtime behaviours: a &lt;em&gt;split-token&lt;/em&gt; indicator points at a &lt;em&gt;linked&lt;/em&gt; full-administrator counterpart for the UAC scenario in Section 8; an &lt;em&gt;AppContainer&lt;/em&gt; flag plus a Package SID and capability SIDs name an AppContainer-bound process. In every case, the kernel consults the token by handle and trusts the contents. The kernel does not ask how a process obtained the handle. It asks only what the token says.&lt;/p&gt;
&lt;p&gt;This is the property that organises the rest of the article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &lt;strong&gt;The Windows access token is a bearer credential.&lt;/strong&gt; Whichever process holds the handle gets the rights. The kernel does not ask how the handle was obtained; it asks only what the token says. This single property explains the entire Potato lineage, Mimikatz &lt;code&gt;token::elevate&lt;/code&gt;, and most of the privilege-abuse canon. Once you see it, every later attack section in the article becomes the same bug repeated against a different token-acquisition primitive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the token is a bearer credential, anyone with a way to obtain a SYSTEM token&apos;s handle is SYSTEM. Every Potato in Section 10 will be a different way to provoke a SYSTEM-token handle into the attacker&apos;s process. But the access check has another input that bypasses the DACL entirely. What is it, and which attackers know about it?&lt;/p&gt;
&lt;h2&gt;6. Privileges as a Different Dimension&lt;/h2&gt;
&lt;p&gt;Privileges are not access rights. They are pre-checked superpowers. They live on the token, they bypass the DACL for specific operations, and they are baked into the kernel for those operations alone.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s framing on Learn is exact: &quot;Privileges differ from access rights in two ways: Privileges control access to system resources and system-related tasks, whereas access rights control access to securable objects&quot; [@ms-learn-privileges]. The same page makes the operational consequence clear: &quot;Most privileges are disabled by default&quot; [@ms-learn-privileges]. A process that holds a privilege but has not enabled it (via &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt;) cannot use it. The discipline is &quot;principle of least privilege at the millisecond level&quot; -- the privilege is on the token, but it does nothing until the program explicitly turns it on for the next system call.&lt;/p&gt;

A named, kernel-recognised authority on the access token that lets the holder perform a specific class of operations the DACL evaluation alone would not permit. Privileges include `SeDebugPrivilege` (read/write any process), `SeImpersonatePrivilege` (act on a client&apos;s token), `SeAssignPrimaryTokenPrivilege` (start a process under a token), `SeBackupPrivilege` (read any file regardless of DACL), `SeRestorePrivilege` (write any file regardless of DACL), `SeTcbPrivilege` (act as the operating system), and `SeLoadDriverPrivilege` (load a kernel driver). Most are disabled by default and must be enabled via `AdjustTokenPrivileges` before use [@ms-learn-privileges].
&lt;p&gt;The reason privileges deserve a section of their own is that &lt;em&gt;five of them are equivalent to &quot;I am SYSTEM&quot;&lt;/em&gt; and the other dozen are housekeeping. The five-versus-housekeeping split is the load-bearing audit decision in any Windows hardening review. Step through them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeDebugPrivilege&lt;/code&gt; lets the holder open any process for full read and write, including processes running as SYSTEM. The privilege exists so that &lt;code&gt;Visual Studio&lt;/code&gt; and &lt;code&gt;WinDbg&lt;/code&gt; can debug code other users have started. The first move in almost every Mimikatz session is &lt;code&gt;privilege::debug&lt;/code&gt;, which enables the privilege the local administrator already has on the token [@github-gentilkiwi-mimikatz, @en-wiki-mimikatz]. Once enabled, the next Mimikatz command opens &lt;code&gt;lsass.exe&lt;/code&gt; and reads the credentials.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; lets the holder accept any token offered by a client and act as that client. The privilege is held by every Windows service account by default -- IIS, SQL Server, the Print Spooler, scheduled tasks, Docker containers, Citrix, the entire population of background services that need to handle authenticated requests. &lt;em&gt;This is the load-bearing privilege for the Potato lineage&lt;/em&gt; [@itm4n-printspoofer-blog]. Section 10 will spend twenty paragraphs on what a service account holding &lt;code&gt;SeImpersonate&lt;/code&gt; can be tricked into doing; the privilege is the entry condition.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt; lets the holder launch a new process under any primary token. Combined with &lt;code&gt;SeImpersonate&lt;/code&gt;, the pair gives an attacker the entire token-replay attack: get an impersonation handle to a SYSTEM token, then call &lt;code&gt;CreateProcessAsUser&lt;/code&gt; to run a command as SYSTEM. itm4n quotes decoder_it on the operational consequence.&lt;/p&gt;

if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM. -- decoder_it, quoted by itm4n in the PrintSpoofer disclosure [@itm4n-printspoofer-blog]
&lt;p&gt;&lt;code&gt;SeBackupPrivilege&lt;/code&gt; lets the holder read any file regardless of DACL, on the theory that backup software has to. &lt;code&gt;SeRestorePrivilege&lt;/code&gt; is the symmetric write privilege. The two together mean that a process holding both can rewrite any file on the machine, including service binaries.&lt;/p&gt;
&lt;p&gt;The 2021 &lt;em&gt;HiveNightmare&lt;/em&gt; / &lt;em&gt;SeriousSAM&lt;/em&gt; vulnerability (CVE-2021-36934) is the worked example of what happens when the model assumes nobody but the backup process has read access to a sensitive file and the assumption breaks. The NVD description is exact: &quot;An elevation of privilege vulnerability exists because of overly permissive Access Control Lists (ACLs) on multiple system files, including the Security Accounts Manager (SAM) database&quot; [@nvd-cve-2021-36934]. The DACL on the live &lt;code&gt;\Windows\System32\config\SAM&lt;/code&gt; was correct; the DACL on the &lt;em&gt;Volume Shadow Copy&lt;/em&gt; mirror was overly permissive enough that any local user could read the SAM hashes through the shadow-copy device path.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s fix required not just a patch but a manual operator step: &quot;After installing this security update, you must manually delete all shadow copies of system files, including the SAM database, to fully mitigate this vulnerability&quot; [@nvd-cve-2021-36934]. A patch alone could not erase the historical shadow copies that already had the wrong DACL.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeTcbPrivilege&lt;/code&gt; lets the holder &quot;act as the operating system&quot; -- it is the privilege that grants identity to the kernel itself. Held only by &lt;code&gt;LocalSystem&lt;/code&gt; services in well-administered environments. A non-system process that somehow acquired &lt;code&gt;SeTcb&lt;/code&gt; is, in effect, indistinguishable from the kernel.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeLoadDriverPrivilege&lt;/code&gt; lets the holder load a kernel driver. By itself the privilege is harmless, because the loaded driver still has to be properly signed for HVCI / Driver Signature Enforcement to accept it. Combined with a known-vulnerable signed driver, however, the privilege becomes the entry point for &lt;em&gt;bring-your-own-vulnerable-driver&lt;/em&gt; (BYOVD) attacks: load a benign-looking but exploitable signed driver, then use its bug to execute arbitrary kernel code. Two worked examples bracket the class.&lt;/p&gt;
&lt;p&gt;The kernel-read/write half of the class is best illustrated by Micro-Star&apos;s &lt;code&gt;RTCore64.sys&lt;/code&gt; (CVE-2019-16098 [@nvd-cve-2019-16098]), the MSI Afterburner driver that &quot;allows any authenticated user to read and write to arbitrary memory, I/O ports, and MSRs&quot; [@nvd-cve-2019-16098]. In October 2022, the threat actors behind the BlackByte ransomware weaponised the primitive at scale [@sophos-blackbyte]: the dropper loaded &lt;code&gt;RTCore64.sys&lt;/code&gt;, then walked the kernel&apos;s &lt;code&gt;PspCreateProcessNotifyRoutine&lt;/code&gt; callback array and zeroed every entry, blinding every registered process-creation callback before the encryption stage ran.&lt;/p&gt;
&lt;p&gt;Sophos&apos;s October 4, 2022 disclosure named the technique exactly: &quot;We found a sophisticated technique to bypass security products by abusing a known vulnerability in the legitimate vulnerable driver RTCore64.sys. The evasion technique supports disabling a whopping list of over 1,000 drivers on which security products rely to provide protection&quot; [@sophos-blackbyte].&lt;/p&gt;
&lt;p&gt;The kernel-code-execution half of the class is GIGABYTE&apos;s &lt;code&gt;gdrv.sys&lt;/code&gt; (CVE-2018-19320 [@nvd-cve-2018-19320]). The NVD description states the primitive directly: &quot;The GDrv low-level driver in GIGABYTE APP Center v1.05.21 and earlier... exposes ring0 memcpy-like functionality that could allow a local attacker to take complete control of the affected system&quot; [@nvd-cve-2018-19320]. A signed &lt;code&gt;IOCTL&lt;/code&gt; accepts an attacker-supplied source pointer, destination pointer, and length, and copies kernel memory at ring 0 -- a write-what-where primitive that the attacker can compose with the read-anywhere primitive of &lt;code&gt;RTCore64.sys&lt;/code&gt; to mint arbitrary kernel code execution.&lt;/p&gt;
&lt;p&gt;CISA added GIGABYTE Multiple Products to the Known Exploited Vulnerabilities Catalog on October 24, 2022 with a remediation due date of November 14, 2022, citing in-the-wild exploitation [@nvd-cve-2018-19320]. The U.S. federal-civilian executive branch had two weeks to remediate; the rest of the install base did not.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s structural answer is the Microsoft-recommended driver blocklist, enabled by default on every device since the Windows 11 2022 update [@ms-learn-driver-blocklist]. The Learn page is exact about coverage: the blocklist targets drivers with &quot;known security vulnerabilities that an attacker could exploit to elevate privileges in the Windows kernel&quot;, and explicitly catches drivers whose behaviours &quot;circumvent the Windows Security Model&quot; [@ms-learn-driver-blocklist].&lt;/p&gt;
&lt;p&gt;Both &lt;code&gt;RTCore64.sys&lt;/code&gt; and &lt;code&gt;gdrv.sys&lt;/code&gt; appear on the blocklist; the ride from disclosure to default-on enforcement was four years for &lt;code&gt;RTCore64&lt;/code&gt;, four years for &lt;code&gt;gdrv&lt;/code&gt;, and the same arc applies to every member of the class. Honourable mention: &lt;code&gt;aswArPot.sys&lt;/code&gt; (CVE-2022-26522 / CVE-2022-26523 [@sentinelone-avast-avg]) shows the same pattern from a security-product driver, with SentinelLabs reporting &quot;two high severity flaws in Avast and AVG... that went undiscovered for years affecting dozens of millions of users&quot; before the silent fix [@sentinelone-avast-avg].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On a Windows machine, holding any of &lt;code&gt;SeDebugPrivilege&lt;/code&gt;, &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt;, &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt;, &lt;code&gt;SeBackupPrivilege&lt;/code&gt;, or &lt;code&gt;SeRestorePrivilege&lt;/code&gt; is operationally indistinguishable from being SYSTEM. The other privileges in the standard token (the long tail of &lt;code&gt;SeShutdown&lt;/code&gt;, &lt;code&gt;SeIncreaseWorkingSet&lt;/code&gt;, &lt;code&gt;SeTimeZone&lt;/code&gt;, &lt;code&gt;SeChangeNotify&lt;/code&gt;, &lt;code&gt;SeUndock&lt;/code&gt;, &lt;code&gt;SeIncreaseQuota&lt;/code&gt;...) are housekeeping. Audit the holders of the five accordingly: any non-LocalSystem-equivalent account that holds them is a target.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The DACL is the load-bearing thing for &lt;em&gt;file&lt;/em&gt; access, but exactly &lt;em&gt;one bad DACL&lt;/em&gt; on a sensitive file ends the model. HiveNightmare proved that the cost of getting a single security descriptor wrong on a single file is the entire credential database. The general rule the lesson encodes: every primitive in Section 3&apos;s input list has at least one production example where misuse of that primitive alone dropped the security model to zero.&lt;/p&gt;
&lt;p&gt;Discretionary access control assumes the principal -- the user -- is the right unit of authorisation. By 2006, exploitable user-mode code had proven the principal was wrong. What did Microsoft do?&lt;/p&gt;
&lt;h2&gt;7. Mandatory Integrity Control: Stapling No-Write-Up onto DAC&lt;/h2&gt;
&lt;p&gt;November 2006. Vista releases to manufacturing, and for the first time in Windows history, the kernel&apos;s access check fires &lt;em&gt;before&lt;/em&gt; the DACL walk -- on something other than the user&apos;s identity. The new layer is &lt;em&gt;Mandatory Integrity Control&lt;/em&gt; (MIC), and it adds a four-level lattice to every securable object in the system.&lt;/p&gt;
&lt;p&gt;Microsoft Learn frames MIC compactly. &quot;MIC uses integrity levels and mandatory policy to evaluate access. Security principals and securable objects are assigned integrity levels that determine their levels of protection or access. For example, a principal with a low integrity level cannot write to an object with a medium integrity level, even if that object&apos;s DACL allows write access to the principal&quot; [@ms-learn-mic]. The same page enumerates the levels: &quot;Windows defines four integrity levels: low, medium, high, and system&quot; [@ms-learn-mic]. The levels are encoded as four well-known SIDs: Low (S-1-16-4096), Medium (S-1-16-8192), High (S-1-16-12288), System (S-1-16-16384) [@en-wiki-mic].&lt;/p&gt;

A Windows kernel mechanism, introduced with Vista (released to manufacturing November 8, 2006; consumer general availability January 30, 2007 [@en-wiki-windows-vista]), that adds an integrity-level check to `SeAccessCheck`. Each securable object carries an integrity label inside its SACL; each access token carries an integrity level. An access whose direction violates the configured *mandatory policy* (typically *no-write-up*) is denied at the integrity check before the DACL walk runs. MIC is the mandatory layer the Windows DAC model historically lacked [@ms-learn-mic].

A linearly-ordered tag (Low / Medium / High / System) carried on every Windows process token and every securable object. The kernel uses the relative ordering to enforce mandatory policy independent of the object&apos;s DACL. The four well-known SIDs are S-1-16-4096 (Low), S-1-16-8192 (Medium), S-1-16-12288 (High), and S-1-16-16384 (System) [@en-wiki-mic].
&lt;p&gt;The default policy is &lt;em&gt;no-write-up&lt;/em&gt;. A process at integrity level $L$ cannot modify an object at integrity level greater than $L$, regardless of what the DACL says. Microsoft&apos;s example is the load-bearing one: a process running at Low IL cannot write to a Medium-IL object even if the DACL says Everyone has full control. The integrity check fires &lt;em&gt;before&lt;/em&gt; the DACL walk; if the integrity check denies, the DACL is not consulted [@ms-learn-mic].&lt;/p&gt;
&lt;p&gt;The integrity label is stored as a &lt;code&gt;SYSTEM_MANDATORY_LABEL_ACE&lt;/code&gt; inside the SACL, not the DACL [@ms-learn-system-mandatory-label-ace]. The mask field on the label ACE encodes which directions of access the policy forbids: &lt;code&gt;SYSTEM_MANDATORY_LABEL_NO_WRITE_UP (0x1)&lt;/code&gt;, &lt;code&gt;SYSTEM_MANDATORY_LABEL_NO_READ_UP (0x2)&lt;/code&gt;, and &lt;code&gt;SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP (0x4)&lt;/code&gt; [@ms-learn-system-mandatory-label-ace].&lt;/p&gt;
&lt;p&gt;Storing the label in the SACL is a deliberate choice with one operational consequence: tools that copy the DACL but not the SACL silently drop the integrity label. The most common consequence is a Low-IL file getting copied to a new location and emerging with no integrity label, which defaults to Medium and unintentionally raises the object&apos;s protection. The opposite mistake -- a Medium-IL file losing its label and dropping to Low -- is the more dangerous one.&lt;/p&gt;
&lt;p&gt;The no-write-up mask is the one to memorise, because it is the policy almost every label uses. When a Low-IL caller tries to act on a Medium-IL object, the kernel denies any access whose mapped result contains write-class bits, including the standard-rights &lt;code&gt;WRITE_DAC&lt;/code&gt; (bit 18 of the 32-bit ACCESS_MASK [@ms-learn-access-mask]) and &lt;code&gt;WRITE_OWNER&lt;/code&gt; (bit 19), the type-generic &lt;code&gt;DELETE&lt;/code&gt; (bit 16), and the file-specific &lt;code&gt;FILE_WRITE_DATA&lt;/code&gt; (0x2), &lt;code&gt;FILE_APPEND_DATA&lt;/code&gt; (0x4), &lt;code&gt;FILE_WRITE_EA&lt;/code&gt; (0x10), and &lt;code&gt;FILE_WRITE_ATTRIBUTES&lt;/code&gt; (0x100) [@ms-learn-file-access-rights].&lt;/p&gt;
&lt;p&gt;The presence of &lt;code&gt;FILE_APPEND_DATA&lt;/code&gt; in that list matters operationally: a careless reader of the spec might assume that &quot;append&quot; semantics escape the no-write-up rule because they do not modify existing bytes. They do not. MIC denies both write modes, so log-only append handlers cannot be used as a write-up channel into a higher-IL object.&lt;/p&gt;
&lt;p&gt;A second rule completes the model: &lt;em&gt;process integrity inheritance&lt;/em&gt;. When a process is created, the kernel assigns it the &lt;em&gt;minimum&lt;/em&gt; of the user&apos;s integrity level and the file&apos;s integrity level [@ms-learn-mic]. A medium-IL user running a low-IL executable gets a low-IL process. This is the rule that lets Internet Explorer 7 run at Low even when launched from a Medium user session.&lt;/p&gt;
&lt;p&gt;The first MIC consumer was IE7 &lt;em&gt;Protected Mode&lt;/em&gt;, which shipped with Windows Vista RTM (released to manufacturing November 8, 2006) [@wayback-skywing-uninformed-v8a6, @en-wiki-windows-vista]. (IE7 standalone for Windows XP, released October 18, 2006 [@en-wiki-ie7], runs without Protected Mode -- the feature depends on Vista&apos;s MIC kernel layer.) Skywing&apos;s &lt;em&gt;Uninformed&lt;/em&gt; Volume 8 Article 6, &quot;Getting Out of Jail: Escaping Internet Explorer Protected Mode,&quot; is the first public reverse-engineering of the implementation.&lt;/p&gt;
&lt;p&gt;Skywing&apos;s framing remains the most-cited primer on the subject: &quot;With the introduction of Windows Vista, Microsoft has added a new form of mandatory access control to the core operating system. Internally known as &apos;integrity levels&apos;, this new addition to the security manager allows security controls to be placed on a per-process basis. This is different from the traditional model of per-user security controls used in all prior versions of Windows NT&quot; [@wayback-skywing-uninformed-v8a6]. IE7&apos;s Protected Mode pattern -- a Low-IL worker that does the dangerous parsing, paired with a Medium-IL broker that performs the system-changing operations on the worker&apos;s behalf -- became the template Windows would later generalise into AppContainer.&lt;em&gt;User Interface Privilege Isolation&lt;/em&gt; (UIPI) is the window-message gate that uses MIC at the desktop. A Low-IL window cannot send &lt;code&gt;SendMessage&lt;/code&gt; or &lt;code&gt;PostMessage&lt;/code&gt; traffic to a Medium-IL or higher window. UIPI is the reason you cannot click-jack a UAC consent prompt from a normally-running browser process: the consent prompt runs at High IL, the browser runs at Medium [@en-wiki-mic].&lt;/p&gt;
&lt;p&gt;Windows 8 generalised the MIC pattern into &lt;em&gt;AppContainer&lt;/em&gt;. An AppContainer process gets a fresh Low-IL token plus an &lt;em&gt;AppContainer&lt;/em&gt; flag, a Package SID that identifies the app, and a list of capability SIDs the app declared in its manifest. Microsoft Learn states the resulting isolation directly: &quot;Windows ensures that processes running with a low integrity level cannot obtain access to a process which is associated with an app container&quot; [@ms-learn-mic]. The Package SID and capability SID derivations are the subject of the App Identity sibling article in this series; we will not redefine them here [@app-identity-sibling].&lt;/p&gt;
&lt;p&gt;MIC fixed the integrity boundary inside the kernel. But the same year shipped a separate retrofit for a different problem: why was the consumer admin running every clicked-on &lt;code&gt;.exe&lt;/code&gt; with full administrative authority? And why did Microsoft refuse to call its answer a security boundary?&lt;/p&gt;
&lt;h2&gt;8. UAC, the Split-Token, and the Bypass Tradition&lt;/h2&gt;
&lt;p&gt;Vista&apos;s &lt;em&gt;User Account Control&lt;/em&gt; is the most famous Windows security retrofit, and the only one whose own keepers explicitly published a document declaring it not a security boundary [@msrc-servicing-criteria]. The mechanism is precise. The bypass tradition is enormous. The classification is honest.&lt;/p&gt;
&lt;p&gt;The mechanism first. Microsoft&apos;s documentation on how UAC works gives the verbatim recipe [@ms-learn-uac]: &quot;When an administrator logs on, two separate access tokens are created for the user: a standard user access token and an administrator access token. The standard user access token... contains the same user-specific information as the administrator access token, but the administrative Windows privileges and SIDs are removed... is used to display the desktop by executing the process &lt;code&gt;explorer.exe&lt;/code&gt;. &lt;code&gt;Explorer.exe&lt;/code&gt; is the parent process from which all other user-initiated processes inherit their access token. As a result, all apps run as a standard user unless a user provides consent or credentials to approve an app to use a full administrative access token.&quot;&lt;/p&gt;

A Windows mechanism, introduced with Vista (released to manufacturing November 8, 2006 [@en-wiki-windows-vista]), in which an administrative user receives two linked tokens at logon: a *filtered* Medium-IL token without administrative privileges or SIDs, used by `explorer.exe` and every process descended from it, and a *full* High-IL administrative counterpart that the kernel hands out only after the user clicks through a consent prompt or supplies credentials. The two tokens reference each other through the `LinkedToken` field. UAC is a UX-and-default-behaviour mechanism, not an enforced security boundary [@ms-learn-uac, @msrc-servicing-criteria].
&lt;p&gt;The split-token mechanism produces three elevation triggers. First, an executable can declare its required level in its manifest via the &lt;code&gt;requestedExecutionLevel&lt;/code&gt; element (&lt;code&gt;asInvoker&lt;/code&gt;, &lt;code&gt;highestAvailable&lt;/code&gt;, or &lt;code&gt;requireAdministrator&lt;/code&gt;). Second, certain Microsoft-signed binaries appear on an &lt;em&gt;AutoElevate&lt;/em&gt; whitelist that the kernel consults; processes on the whitelist transparently get the full token without prompting. Third, COM components can be marked elevatable via the &lt;em&gt;COM Elevation Moniker&lt;/em&gt;, which lets code instantiate &lt;code&gt;Elevation:Administrator!new:{guid}&lt;/code&gt; (or &lt;code&gt;Elevation:Highest!new:{guid}&lt;/code&gt;) to obtain a High-IL administrator COM caller -- not a SYSTEM caller; the moniker&apos;s supported run levels are &lt;code&gt;Administrator&lt;/code&gt; and &lt;code&gt;Highest&lt;/code&gt; [@ms-learn-com-elevation-moniker]. Method 41 (Oddvar Moe&apos;s &lt;code&gt;ICMLuaUtil&lt;/code&gt; construction) is the canonical worked example.&lt;/p&gt;
&lt;p&gt;The classification next. Microsoft&apos;s &lt;em&gt;Security Servicing Criteria for Windows&lt;/em&gt; defines a security boundary as the logical separation between security domains with different trust levels, and gives the kernel-mode / user-mode separation as the canonical example [@msrc-servicing-criteria]. The criteria document then enumerates which boundaries Microsoft commits to servicing. UAC and admin-to-kernel are not on the enumerated list.&lt;/p&gt;

A security boundary provides a logical separation between the code and data of security domains with different levels of trust... the separation between kernel mode and user mode is a classic [...] security boundary. Microsoft software depends on multiple security boundaries to isolate devices on the network, virtual machines, and applications on a device. -- Microsoft Security Servicing Criteria for Windows [@msrc-servicing-criteria]
&lt;p&gt;The &quot;outside the enumerated list&quot; classification has a concrete consequence: bypasses of UAC are not eligible for the same security-update treatment a kernel-mode-to-user-mode bypass would get. Mitigations are issued per-redirect, when an attacker&apos;s specific path becomes operationally noisy enough to warrant attention. The seventy-plus methods catalogued in UACMe are the empirical consequence.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &lt;strong&gt;UAC was never a security boundary.&lt;/strong&gt; The seventy-plus methods catalogued in UACMe are not bugs in UAC. They are the formal consequence of UAC&apos;s classification. Once you recognise that UAC is a UX-and-default-behaviour mechanism rather than an enforced boundary, the bypass tradition is legible as a feature being used as designed and the structural arc to Adminless makes sense.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The bypass canon. Walk it generation by generation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Method 1 -- Leo Davidson, 2009.&lt;/strong&gt; Davidson&apos;s &lt;em&gt;Windows 7 UAC Whitelist&lt;/em&gt; writeup is the genealogical root of the UAC bypass tradition [@pretentiousname-davidson, @github-hfiref0x-uacme]. He noticed that &lt;code&gt;sysprep.exe&lt;/code&gt; is on the AutoElevate whitelist and that, when launched from &lt;code&gt;C:\Windows\System32\sysprep\&lt;/code&gt;, it loads several DLLs from the working directory. Use the &lt;code&gt;IFileOperation&lt;/code&gt; COM interface (which the elevator treats as AutoApprove, enabling the file copy without prompting) to drop a malicious &lt;code&gt;cryptbase.dll&lt;/code&gt; into &lt;code&gt;%SystemRoot%\System32\sysprep\&lt;/code&gt;. Then trigger &lt;code&gt;sysprep.exe&lt;/code&gt; -- which is on the AutoElevate whitelist -- and the auto-elevated process loads the attacker&apos;s DLL, and the attacker has a High-IL full administrative token.&lt;/p&gt;
&lt;p&gt;Davidson&apos;s writeup quotes himself bluntly: &quot;This works against the RTM (retail) and RC1 versions of Windows 7&quot; [@pretentiousname-davidson]. UACMe Method 1 records the technique with structured metadata: &quot;Author: Leo Davidson / Type: Dll Hijack / Method: IFileOperation / Target(s): \system32\sysprep\sysprep.exe / Component(s): cryptbase.dll / Implementation: ucmStandardAutoElevation / Works from: Windows 7 (7600) / Fixed in: Windows 8.1 (9600)&quot; [@github-hfiref0x-uacme].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Method 25 -- Matt Nelson (enigma0x3), August 15, 2016.&lt;/strong&gt; Seven years after Davidson, Nelson published &quot;Fileless UAC Bypass Using &lt;code&gt;eventvwr.exe&lt;/code&gt; and Registry Hijacking&quot; [@enigma0x3-eventvwr-blog]. The bypass replaces the file-system DLL hijack with a registry redirect. Nelson noticed that &lt;code&gt;eventvwr.exe&lt;/code&gt;, an AutoElevated binary, queries &lt;code&gt;HKCU\Software\Classes\mscfile\shell\open\command&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; &lt;code&gt;HKCR\mscfile\shell\open\command&lt;/code&gt; to find the command to run for the &lt;code&gt;mscfile&lt;/code&gt; ProgID. His verbatim observation: &quot;From the output, it appears that &apos;eventvwr.exe&apos;, as a high integrity process, queries both HKCU and HKCR registry hives to start mmc.exe&quot; [@enigma0x3-eventvwr-blog]. HKCU is writable by the standard user; the user writes a malicious command line under that key, runs &lt;code&gt;eventvwr.exe&lt;/code&gt;, and the auto-elevated process happily executes the user-supplied command line. The first &lt;em&gt;fileless&lt;/em&gt; UAC bypass.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Method 33 -- winscripting.blog, 2017.&lt;/strong&gt; Same primitive, different target. The &lt;code&gt;fodhelper.exe&lt;/code&gt; binary is on the AutoElevate whitelist and queries &lt;code&gt;HKCU\Software\Classes\ms-settings\shell\open\command&lt;/code&gt; to launch the Settings app. UACMe records the credit precisely: &quot;Author: winscripting.blog / Type: Shell API / Method: Registry key manipulation / Target(s): \system32\fodhelper.exe / Component(s): Attacker defined / Implementation: ucmShellRegModMethod / Works from: Windows 10 TH1 (10240) / Fixed in: unfixed&quot; [@github-hfiref0x-uacme]. &lt;em&gt;Fixed in: unfixed.&lt;/em&gt; This is what &quot;outside the enumerated list&quot; looks like in practice: nine years after Method 1 and a year after Method 25 demonstrated the underlying class, the registry-redirect template was still being applied to fresh AutoElevate targets and shipping unmitigated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Method 41 -- Oddvar Moe.&lt;/strong&gt; The COM elevation moniker route. UACMe records: &quot;Author: Oddvar Moe / Type: Elevated COM interface / Method: ICMLuaUtil&quot; [@github-hfiref0x-uacme]. Instantiate the &lt;code&gt;CMLuaUtil&lt;/code&gt; COM object via the elevation moniker from a Medium-IL process, get back a High-IL COM caller, and call its &lt;code&gt;ShellExec&lt;/code&gt; method to run an attacker command line at High IL. The seam is the COM moniker registry&apos;s &lt;code&gt;Elevation\Enabled&lt;/code&gt; key, which marks specific CLSIDs as elevation-capable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Method 31 (sdclt), 29, 34, ...&lt;/strong&gt; The pattern repeats. Matt Nelson&apos;s &lt;code&gt;sdclt.exe&lt;/code&gt; variants exploit the backup-restore UI&apos;s registry lookups. Forshaw&apos;s &lt;code&gt;schtasks&lt;/code&gt; variant exploits the scheduled-task COM interface. The UACMe README enumerates the lot with the laconic one-liner &quot;Defeating Windows User Account Control by abusing built-in Windows AutoElevate backdoor&quot; [@github-hfiref0x-uacme]. Most of the methods reduce to the same primitive: an AutoElevated Microsoft-signed binary performs a lookup that the standard user can redirect, the standard user supplies an attacker-controlled answer, and the auto-elevated binary executes attacker-controlled work.&lt;/p&gt;

flowchart TD
    A[User Medium-IL process] --&amp;gt; B[Write attacker command line into HKCU writable seam: registry key, file system path, scheduled-task XML]
    B --&amp;gt; C[Trigger AutoElevated Microsoft-signed binary: sysprep.exe / eventvwr.exe / fodhelper.exe / sdclt.exe / etc.]
    C --&amp;gt; D[AutoElevate flag honoured by kernel]
    D --&amp;gt; E[Binary launched at High IL with full administrative token]
    E --&amp;gt; F[Binary performs lookup: HKCU registry / DLL search path / scheduled-task definition]
    F --&amp;gt; G[Lookup returns attacker-supplied content]
    G --&amp;gt; H[High-IL process executes attacker work]

Mark Russinovich&apos;s June 2007 *TechNet Magazine* cover story, &quot;Inside Windows Vista User Account Control,&quot; is the canonical practitioner walkthrough of the split-token model and is preserved on the Wayback Machine [@wayback-russinovich-uac-technet]. Russinovich opens by naming the misunderstanding: &quot;User Account Control (UAC) is an often misunderstood feature in Windows Vista... In this article I discuss the problems UAC solves and describe the architecture and implementation of its component technologies.&quot; The framing throughout the article is that UAC&apos;s purpose is to create the *expectation* that consumer software would run as a standard user, and to push the developer community to refactor away from gratuitous administrator requirements. That framing -- UAC as a UX and migration mechanism -- is consistent with the eventual MSRC servicing-criteria position: not a defended boundary, but a behaviour gate.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Microsoft&apos;s servicing-criteria position means a UAC bypass that does not also cross a serviced security boundary is not, by policy, eligible for a security update. Mitigations land when the operational footprint of a particular bypass becomes large enough to justify one. Track UAC mitigations by KB number, not by feature description; consult the UACMe README&apos;s &lt;code&gt;Fixed in:&lt;/code&gt; field as the institutional memory [@github-hfiref0x-uacme, @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;UAC bypasses redirect the elevation flow that produces a token. A different attack family takes the result and steals tokens from already-elevated SYSTEM services. Where do those attacks come from, and why are they all the same bug?&lt;/p&gt;
&lt;h2&gt;9. The Object Manager and the Lookup Surface&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SeAccessCheck&lt;/code&gt; evaluates a security descriptor it has been handed. Who hands it the descriptor?&lt;/p&gt;
&lt;p&gt;The kernel&apos;s &lt;em&gt;Object Manager&lt;/em&gt; does, after walking a name. Every named kernel object lives somewhere in a hierarchical namespace rooted at &lt;code&gt;\&lt;/code&gt;. Devices live under &lt;code&gt;\Device&lt;/code&gt;. Synchronisation primitives live under &lt;code&gt;\BaseNamedObjects&lt;/code&gt;. Pre-resolved DLL names live under &lt;code&gt;\KnownDlls&lt;/code&gt;. Per-session subtrees live under &lt;code&gt;\Sessions&lt;/code&gt;. The DOS device prefix &lt;code&gt;\GLOBAL??&lt;/code&gt; (and its session-local sibling &lt;code&gt;\??&lt;/code&gt;) holds drive-letter symbolic links into the device tree. When a process calls &lt;code&gt;OpenObject&lt;/code&gt;, the Object Manager parses the name, walks the tree, and returns the object whose security descriptor &lt;code&gt;SeAccessCheck&lt;/code&gt; will then evaluate.&lt;/p&gt;
&lt;p&gt;The kernel performs &lt;em&gt;the lookup&lt;/em&gt; before &lt;em&gt;the access check&lt;/em&gt;. This sequencing creates a parallel attack surface that bypasses &lt;code&gt;SeAccessCheck&lt;/code&gt; entirely. If the attacker can influence the name resolution -- redirect a &lt;code&gt;\??\&lt;/code&gt; symbolic link, plant a junction in NTFS that re-targets a directory traversal, hardlink a low-privilege file at a path the kernel will trust because of the parent directory&apos;s descriptor -- then by the time &lt;code&gt;SeAccessCheck&lt;/code&gt; runs, it is being asked about a different object than the original code path intended to open.&lt;/p&gt;
&lt;p&gt;The HiveNightmare lookup path is the canonical worked example. The exploit reads the SAM database not via &lt;code&gt;\Windows\System32\config\SAM&lt;/code&gt; (which has a tight DACL) but via &lt;code&gt;\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy*\Windows\System32\config\SAM&lt;/code&gt;. That path resolves through the Object Manager&apos;s &lt;code&gt;\GLOBAL??&lt;/code&gt; symbolic link, into the device tree, into a Volume Shadow Copy mirror of the original volume, into a &lt;em&gt;copy&lt;/em&gt; of &lt;code&gt;SAM&lt;/code&gt; whose DACL was, until the August 2021 patch, readable by any authenticated local user (BUILTIN\Users) [@nvd-cve-2021-36934].&lt;/p&gt;
&lt;p&gt;The lookup-phase attack class is wider than file-system shadow copies. &lt;em&gt;Object Manager symbolic links&lt;/em&gt; and &lt;em&gt;NTFS hard links&lt;/em&gt; both produce the same primitive: the kernel resolves a name through an attacker-influenced redirect and ends up evaluating &lt;code&gt;SeAccessCheck&lt;/code&gt; against a different security descriptor than the calling code intended.&lt;/p&gt;
&lt;p&gt;CVE-2020-0668, the Service Tracing elevation-of-privilege bug Clément Labro disclosed in February 2020, is the textbook symbolic-link case [@itm4n-cve-2020-0668-blog]. The Service Tracing infrastructure under &lt;code&gt;HKLM\SOFTWARE\Microsoft\Tracing&lt;/code&gt; is user-writable, and several SYSTEM services -- &lt;code&gt;IKEEXT&lt;/code&gt;, &lt;code&gt;RasMan&lt;/code&gt;, the Update Session Orchestrator service -- consult those keys to find a tracing log path. When the log file exceeds the configured &lt;code&gt;MaxFileSize&lt;/code&gt;, the service renames it from &lt;code&gt;MODULE.LOG&lt;/code&gt; to &lt;code&gt;MODULE.OLD&lt;/code&gt;, deleting any existing &lt;code&gt;MODULE.OLD&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;itm4n&apos;s exploit is exactly the one his blog post names: &quot;All you need to do is set the target directory as a mountpoint to the &lt;code&gt;\RPC Control&lt;/code&gt; object directory and then create two symbolic links: A symbolic link from &lt;code&gt;MODULE.LOG&lt;/code&gt; to a file you own; A symbolic link from &lt;code&gt;MODULE.OLD&lt;/code&gt; to any file on the file system&quot; [@itm4n-cve-2020-0668-blog]. The mountpoint reroutes the kernel&apos;s name resolution into an Object Manager directory the attacker controls; the two symlinks reroute the rename operation; the SYSTEM service ends up performing an arbitrary file move with kernel authority. Forshaw&apos;s &lt;code&gt;googleprojectzero/symboliclink-testing-tools&lt;/code&gt; repository [@github-projectzero-symlink-tools] provides the primitive library the exploit consumes -- &lt;code&gt;CreateSymlink&lt;/code&gt;, &lt;code&gt;CreateMountPoint&lt;/code&gt;, &lt;code&gt;BaitAndSwitch&lt;/code&gt; -- and the repository is, in effect, the institutional library every Object Manager lookup-phase attack of the past decade has linked against.&lt;/p&gt;
&lt;p&gt;The NTFS hard-link case predates the symbolic-link case by half a decade. James Forshaw&apos;s December 2015 Project Zero post, &quot;Between a Rock and a Hard Link,&quot; is the canonical primary source [@projectzero-blog-rockandhardlink]. Forshaw observes that hard links have been a feature of NTFS &quot;since it was originally designed&quot;, and that their relevance to local privilege escalation is exactly the lookup-vs-access-check sequencing this section describes: &quot;Why are hard links useful for local privilege escalation? One type of vulnerability is exploited by a file planting attack, where a privilege service tries to write to a file in a known location&quot; [@projectzero-blog-rockandhardlink].&lt;/p&gt;
&lt;p&gt;The worked example Forshaw walks is CVE-2015-4481, a Mozilla Maintenance Service hard-link primitive: any user can write a status log to &lt;code&gt;C:\ProgramData\Mozilla\logs\maintenanceservice.log&lt;/code&gt;, and during the service&apos;s pre-write &lt;code&gt;BackupOldLogs&lt;/code&gt; rename a brief window opens in which the attacker can replace the about-to-be-written log path with a hard link to an arbitrary system file. The service&apos;s subsequent write -- which it performs with its own SYSTEM authority -- ends up overwriting the system file. The DACL on the source file (the Mozilla log directory) was correct; the DACL on the destination file (the system binary) was correct; the kernel arrived at the destination by resolving a hard-link name the attacker had planted, and &lt;code&gt;SeAccessCheck&lt;/code&gt; saw only the destination DACL, not the planted-link DACL [@projectzero-blog-rockandhardlink]. Microsoft&apos;s MS15-115 mitigation tightened the kernel&apos;s hard-link semantics for sandboxed callers (the kernel&apos;s &lt;code&gt;NtSetInformationFile&lt;/code&gt; now requires &lt;code&gt;FILE_WRITE_ATTRIBUTES&lt;/code&gt; on the target handle when the caller&apos;s token has the sandboxed-token flag, matching what the user-mode &lt;code&gt;CreateHardLink&lt;/code&gt; wrapper had always opened the target with). The fix closes the sandboxed-process branch of the bug class but, as Forshaw notes, does nothing for the Maintenance Service vulnerability itself, which is exploited by a non-sandboxed local user; the structural fix is to write the log to a directory the user cannot create files in, not to enforce a hard-link mask -- a structural fix to the lookup phase, not the access-check phase.&lt;/p&gt;
&lt;p&gt;The two examples generalise the rule. The kernel resolves names &lt;em&gt;before&lt;/em&gt; checking the requesting user&apos;s authority over the destination. The DACL at &lt;code&gt;target.path&lt;/code&gt; and the DACL at &lt;code&gt;attacker.planted.path&lt;/code&gt; after a junction or hard-link redirect can be different; &lt;code&gt;SeAccessCheck&lt;/code&gt; evaluates the descriptor it arrives at, not the descriptor the original caller intended. Capability systems would resolve names through unforgeable handles instead of strings, and the redirect class would not exist by construction [@en-wiki-capability-based-security]. Windows checks the descriptor on every &lt;code&gt;OpenObject&lt;/code&gt; because the name is a forgeable string. The Object Manager namespace is therefore an attack surface whose load-bearing fix is structural rather than per-bug.The Object Manager&apos;s namespace is not documented as policy in the same way &lt;code&gt;SeAccessCheck&lt;/code&gt;&apos;s algorithm is. The de facto modern documentation is empirical: practitioners enumerate the namespace with tools that read kernel structures directly. James Forshaw&apos;s NtObjectManager PowerShell module, part of the Project Zero &lt;code&gt;sandbox-attacksurface-analysis-tools&lt;/code&gt; repository, is the dominant such tool [@github-projectzero-sandbox-attacksurface]. The repository&apos;s banner is exact: &quot;NtObjectManager: A powershell module which uses NtApiDotNet to expose the NT object manager.&quot;&lt;/p&gt;
&lt;p&gt;The James Forshaw / Project Zero corpus is the systematic reference for the Object Manager attack surface. Forshaw&apos;s &quot;Sharing a Logon Session a Little Too Much&quot; (April 2020) names a primitive PrintSpoofer would later consume: when the LSA creates a token for a new logon session, it caches the token for later retrieval. Forshaw&apos;s verbatim explanation: &quot;when LSASS creates a Token for a new Logon session it stores that Token for later retrieval. For the most part this isn&apos;t that useful, however there is one case where the session Token is repurposed, network authentication&quot; [@tiraniddo-sharing-logon-session]. The cached token plus a named-pipe path-validation bug becomes a non-DCOM SYSTEM-token primitive that no DACL touches.&lt;/p&gt;
&lt;p&gt;The lookup surface is half the attack story. The other half is the token surface, and the canonical example of the token surface is a six-year, eight-tool lineage.&lt;/p&gt;
&lt;h2&gt;10. The Potato Lineage: Eight Tools, One Bug (2016-2021)&lt;/h2&gt;
&lt;p&gt;January 16, 2016. Stephen Breen of Foxglove Security publishes &quot;Hot Potato.&quot; The disclosure post opens with a sentence the article will earn the right to repeat: &quot;Microsoft is aware of all of these issues and has been for some time (circa 2000). These are unfortunately hard to fix without breaking backward compatibility and have been [used] by attackers for over 15 years&quot; [@foxglove-hot-potato-blog]. Six years and seven tools later, that admission still describes the situation.&lt;/p&gt;
&lt;p&gt;The single underlying primitive. A low-privileged service account holding &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; (which IIS, SQL Server, the Print Spooler, scheduled tasks, Docker, Citrix, and almost every managed-service account hold by default) tricks SYSTEM into authenticating to a TCP, RPC, or named-pipe endpoint the attacker controls. The attacker&apos;s endpoint accepts the authentication, ends up with an impersonation handle to a SYSTEM token, and calls &lt;code&gt;ImpersonateLoggedOnUser&lt;/code&gt; followed by &lt;code&gt;CreateProcessAsUser&lt;/code&gt; to run arbitrary code as SYSTEM. Same primitive, eight tools, six years.&lt;/p&gt;

sequenceDiagram
    participant Attacker as Attacker (service account, SeImpersonate)
    participant Coercer as Coercion primitive (NBNS / DCOM / EFSRPC / Spooler RPC)
    participant SYSTEM as SYSTEM service
    participant Endpoint as Attacker-controlled local endpoint
    Attacker-&amp;gt;&amp;gt;Coercer: Trigger coercion (e.g. EfsRpcOpenFileRaw, BITS CoGetInstanceFromIStorage)
    Coercer-&amp;gt;&amp;gt;SYSTEM: Tell SYSTEM to authenticate
    SYSTEM-&amp;gt;&amp;gt;Endpoint: NTLM authentication to attacker endpoint
    Endpoint-&amp;gt;&amp;gt;Endpoint: Accept NTLM, build impersonation token
    Attacker-&amp;gt;&amp;gt;Attacker: ImpersonateLoggedOnUser(SYSTEM token)
    Attacker-&amp;gt;&amp;gt;Attacker: CreateProcessAsUser(SYSTEM token, &quot;cmd.exe&quot;)
    Note over Attacker: SYSTEM shell
&lt;p&gt;Walk the lineage one paragraph at a time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hot Potato (Stephen Breen / Foxglove, January 2016)&lt;/strong&gt; [@foxglove-hot-potato-blog]. The original. Hot Potato chains three Windows defaults: NBT-NS (NetBIOS name service) spoofing on the local network, the Web Proxy Auto-Discovery (WPAD) protocol&apos;s automatic proxy lookup, and Windows Update&apos;s HTTP-to-SMB NTLM relay. The exploit poisons NBT-NS so that the SYSTEM-running Windows Update service resolves &lt;code&gt;WPAD&lt;/code&gt; to the attacker&apos;s local listener; the attacker&apos;s listener serves a proxy configuration that proxies SMB through localhost; the Windows Update service authenticates to the attacker&apos;s localhost SMB endpoint as SYSTEM. Foxglove&apos;s verbatim summary: &quot;Hot Potato (aka: Potato) takes advantage of known issues in Windows to gain local privilege escalation in default configurations, namely NTLM relay (specifically HTTP-&amp;gt;SMB relay) and NBNS spoofing&quot; [@foxglove-hot-potato-blog].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rotten Potato (Stephen Breen and Chris Mallz / Foxglove, September 2016)&lt;/strong&gt; [@foxglove-rotten-potato-blog]. The successor abandons the network-protocol fragility for a DCOM activation trick that James Forshaw had published as Project Zero issue 325. The attacker calls &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; with the BITS CLSID &lt;code&gt;{4991d34b-80a1-4291-83b6-3328366b9097}&lt;/code&gt; and a custom marshalled &lt;code&gt;IStorage&lt;/code&gt; pointer; the COM activation runs on the local DCOM server (which runs as SYSTEM) and authenticates back to a TCP listener the attacker controls.&lt;/p&gt;
&lt;p&gt;The Foxglove blog states the three steps verbatim: &quot;1. Trick the &apos;NT AUTHORITY\SYSTEM&apos; account into authenticating via NTLM to a TCP endpoint we control. 2. Man-in-the-middle this authentication attempt (NTLM relay) to locally negotiate a security token for the &apos;NT AUTHORITY\SYSTEM&apos; account. 3. Impersonate the token... This can only be done if the attackers current account has the privilege to impersonate security tokens&quot; [@foxglove-rotten-potato-blog]. The same post credits the Project Zero work directly: &quot;this work is derived directly from James Forshaw&apos;s BlackHat talk and Google Project Zero research&quot; [@foxglove-rotten-potato-blog].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Juicy Potato (decoder_it and ohpe, 2018)&lt;/strong&gt; [@github-ohpe-juicy-potato]. A weaponised, configurable Rotten Potato. The repository README is exact about lineage and entry conditions: &quot;RottenPotatoNG and its variants leverages the privilege escalation chain based on BITS service having the MiTM listener on 127.0.0.1:6666 and when you have SeImpersonate or SeAssignPrimaryToken privileges. ... We decided to weaponize RottenPotatoNG: Say hello to Juicy Potato&quot; [@github-ohpe-juicy-potato].&lt;/p&gt;
&lt;p&gt;Juicy Potato adds a CLSID brute-list (so the attacker can cycle through DCOM activations until one works on the target Windows version), a configurable listener port, and a configurable target binary. The repo&apos;s own framing of when it works is the article&apos;s PullQuote-worthy line: &quot;If the user has SeImpersonate or SeAssignPrimaryToken privileges then you are SYSTEM&quot; [@github-ohpe-juicy-potato]. Juicy Potato was killed by a Windows 10 1809 / Server 2019 mitigation that prevented the OXID resolver from being queried on a port other than 135. The mitigation was the first time Microsoft had touched the underlying primitive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rogue Potato (Antonio Cocomazzi and Andrea Pierini, May 2020)&lt;/strong&gt; [@decoder-rogue-potato-blog]. The bypass for the loopback-OXID mitigation. Decoder&apos;s blog states the engineering problem and the fix in two sentences: &quot;Starting from Windows 10 1809 &amp;amp; Windows Server 2019, its no more possible to query the OXID resolver on a port different than 135&quot; [@decoder-rogue-potato-blog]. Rogue Potato works around the constraint by routing the OXID resolution through an attacker-controlled &lt;em&gt;remote&lt;/em&gt; OXID resolver, typically reached via &lt;code&gt;socat tcp-listen:135,fork TCP:attacker:9999&lt;/code&gt;. The remote resolver returns a string binding pointing back at the attacker&apos;s local listener; the constraint is satisfied (the OXID resolver is on port 135) but the listener it ultimately reaches is the attacker&apos;s. The lineage extends.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PrintSpoofer (Clément Labro / itm4n, May 2020)&lt;/strong&gt; [@github-itm4n-printspoofer, @itm4n-printspoofer-blog]. The same week as Rogue Potato, a different no-DCOM, no-OXID variant lands. PrintSpoofer drops DCOM entirely. It uses the Print Spooler RPC method &lt;code&gt;RpcRemoteFindFirstPrinterChangeNotificationEx&lt;/code&gt; to coerce the spooler (running as SYSTEM) to call back to a named pipe whose path the attacker controls. A path-validation bypass on the named-pipe name lets the attacker capture the SYSTEM credential the spooler offers.&lt;/p&gt;
&lt;p&gt;itm4n&apos;s repository description summarises the entry condition: &quot;From LOCAL/NETWORK SERVICE to SYSTEM by abusing SeImpersonatePrivilege on Windows 10 and Server 2016/2019&quot; [@github-itm4n-printspoofer]. The blog post opens with credit and the canonical decoder_it quote: &quot;I want to start things off with this quote from @decoder_it: &apos;if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM&apos;&quot; [@itm4n-printspoofer-blog].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RemotePotato0 (Cocomazzi and Pierini, 2021)&lt;/strong&gt; [@github-antoniococo-remotepotato0]. The first Potato to escape the local machine. A cross-session DCOM activation lets the attacker reach a token from a &lt;em&gt;different&lt;/em&gt; logged-on user; a cross-protocol RPC-to-LDAP relay then turns that user&apos;s authentication into a domain-administrator action against Active Directory.&lt;/p&gt;
&lt;p&gt;The README is candid about the shape of the response: &quot;UPDATE 21-10-2022: The main exploit scenario RPC-&amp;gt;LDAP of RemotePotato0 has been fixed... Just another &apos;Won&apos;t Fix&apos; Windows Privilege Escalation from User to Domain Admin. RemotePotato0 is an exploit that allows you to escalate your privileges from a generic User to Domain Admin... It abuses the DCOM activation service and trigger an NTLM authentication of any user currently logged on in the target machine&quot; [@github-antoniococo-remotepotato0]. &lt;em&gt;Just another &quot;Won&apos;t Fix&quot; Windows Privilege Escalation&lt;/em&gt; is the precise framing: the underlying primitive is structural, the 2022 fix addressed the specific RPC-to-LDAP path, and the construction continues to work for other relay targets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PetitPotam (Lionel Gilles / topotam77, July 2021)&lt;/strong&gt; [@github-topotam-petitpotam, @nvd-cve-2021-36942]. Not strictly a local-LPE Potato, but the source of the EFSRPC coercion primitive that local-LPE Potatoes consume. PetitPotam exploits the Encrypting File System remote-procedure-call protocol&apos;s &lt;code&gt;EfsRpcOpenFileRaw&lt;/code&gt; (and several other functions) to coerce a Windows host to authenticate to an attacker-controlled endpoint.&lt;/p&gt;
&lt;p&gt;The README is exact about the interface choices: &quot;PoC tool to coerce Windows hosts to authenticate to other machines via MS-EFSRPC EfsRpcOpenFileRaw or other functions :) The tools use the LSARPC named pipe with inteface c681d488-d850-11d0-8c52-00c04fd90f7e because it&apos;s more prevalent. But it&apos;s possible to trigger with the EFSRPC named pipe and interface df1941c5-fe89-4e79-bf10-463657acf44d&quot; [@github-topotam-petitpotam]. PetitPotam&apos;s most-cited use case is cross-machine relay against Active Directory Certificate Services, but the EFSRPC coercion is also locally consumable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SharpEfsPotato (bugch3ck, 2021)&lt;/strong&gt; [@github-bugch3ck-sharpefspotato]. The local-machine variant of the PetitPotam coercion. The README is precise about lineage: &quot;Local privilege escalation from SeImpersonatePrivilege using EfsRpc. Built from SweetPotato by &lt;code&gt;@_EthicalChaos_&lt;/code&gt; and SharpSystemTriggers/SharpEfsTrigger by &lt;code&gt;@cube0x0&lt;/code&gt;&quot; [@github-bugch3ck-sharpefspotato]. SharpEfsPotato uses &lt;code&gt;EfsRpcOpenFileRaw&lt;/code&gt; against the local LSARPC pipe to coerce SYSTEM to authenticate to a local endpoint, then performs the by-now-familiar token capture and &lt;code&gt;CreateProcessAsUser&lt;/code&gt;.This article&apos;s stage-4 source verification corrected an attribution that had been carried forward from the original scope file: SharpEfsPotato&apos;s canonical repository is &lt;code&gt;bugch3ck/SharpEfsPotato&lt;/code&gt;, not the often-cited &lt;code&gt;ly4k/SharpEfsPotato&lt;/code&gt;. The latter URL returns HTTP 404. Cross-references that point at the &lt;code&gt;ly4k&lt;/code&gt; URL should be updated to point at &lt;code&gt;bugch3ck&lt;/code&gt; [@github-bugch3ck-sharpefspotato].&lt;/p&gt;
&lt;p&gt;The pattern across the lineage is that &lt;em&gt;the mitigation that did break a tool was always specific&lt;/em&gt; (the loopback-OXID restriction, the cross-session DCOM partial fix, the EFSRPC coercion partial mitigation in KB5005413), and &lt;em&gt;the mitigation that would break the family is structural&lt;/em&gt; (remove &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; from service accounts, end NTLM-to-self-as-machine relay, retire the bearer-credential property of tokens). Microsoft has shipped the first kind of fix seven times across the lineage and continues to ship them; the second kind requires architectural changes that arrive in successor articles in this series.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Author(s)&lt;/th&gt;
&lt;th&gt;Coercion vector&lt;/th&gt;
&lt;th&gt;Mitigation that broke it&lt;/th&gt;
&lt;th&gt;Mitigation that did not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Hot Potato&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;Breen&lt;/td&gt;
&lt;td&gt;NBT-NS + WPAD + HTTP-to-SMB relay&lt;/td&gt;
&lt;td&gt;Disable WPAD; KB3146965&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotten Potato&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;Breen, Mallz&lt;/td&gt;
&lt;td&gt;DCOM &lt;code&gt;CoGetInstanceFromIStorage&lt;/code&gt; (BITS)&lt;/td&gt;
&lt;td&gt;(none specific until Juicy fix)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Juicy Potato&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;decoder_it, ohpe&lt;/td&gt;
&lt;td&gt;DCOM CLSID brute-list, configurable port&lt;/td&gt;
&lt;td&gt;Loopback-OXID restriction (1809 / 2019)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rogue Potato&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Cocomazzi, Pierini&lt;/td&gt;
&lt;td&gt;Remote OXID resolver via &lt;code&gt;socat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cross-session DCOM partial fix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PrintSpoofer&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Labro&lt;/td&gt;
&lt;td&gt;Spooler RPC + named-pipe path bypass&lt;/td&gt;
&lt;td&gt;KB5005010 (PrintNightmare-era spooler hardening) [@nvd-cve-2021-34527]&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RemotePotato0&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Cocomazzi, Pierini&lt;/td&gt;
&lt;td&gt;Cross-session DCOM + RPC-to-LDAP relay&lt;/td&gt;
&lt;td&gt;RPC-to-LDAP relay fix (October 2022)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services; remaining relay targets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PetitPotam&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Gilles&lt;/td&gt;
&lt;td&gt;EFSRPC coercion via LSARPC&lt;/td&gt;
&lt;td&gt;KB5005413 partial; ADCS hardening [@nvd-cve-2021-36942]&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services; other relay targets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SharpEfsPotato&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;bugch3ck&lt;/td&gt;
&lt;td&gt;Local EFSRPC coercion&lt;/td&gt;
&lt;td&gt;(none specific to local variant)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SeImpersonate&lt;/code&gt; on services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Eight tools. One privilege. Every &quot;mitigation that did not&quot; cell points at the same thing: a bearer-token model plus &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; on a service account.&lt;/p&gt;

Eight tools in six years against the same underlying primitive is not a tooling coincidence. It is the empirical signature of the bearer-credential property and the omnipresent service-account `SeImpersonate` privilege. The Hot Potato post&apos;s verbatim &quot;hard to fix without breaking backward compatibility&quot; admission [@foxglove-hot-potato-blog] is the same argument Microsoft eventually formalised in the security-servicing-criteria position: this surface is intentionally retained for compatibility, and structural changes belong in a different architecture. The article earns the bridge to the Adminless and NTLMless successors here, six years before the calendar gets there.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A service account holding &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; plus &lt;em&gt;any&lt;/em&gt; RPC interface that authenticates to attacker-controllable endpoints equals SYSTEM. Eight Potatoes in six years prove this is structural, not a tooling fad. Audit every server: any non-LocalSystem-equivalent process holding &lt;code&gt;SeImpersonate&lt;/code&gt; or &lt;code&gt;SeAssignPrimaryToken&lt;/code&gt; should be treated as a Potato target until proven otherwise. Pre-deploy per-service SIDs and Group Managed Service Accounts where possible to constrain the blast radius [@github-itm4n-printspoofer].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Eight Potatoes prove the bearer-token property is unkillable by point fixes. But what does an attacker who is &lt;em&gt;already admin&lt;/em&gt; do? The answer is the most-cited offensive Windows tool of the past fifteen years.&lt;/p&gt;
&lt;h2&gt;11. Mimikatz, Conditional ACEs, and the Edges of the Model&lt;/h2&gt;
&lt;p&gt;May 2011. Benjamin Delpy releases the first version of Mimikatz [@en-wiki-mimikatz]. Wikipedia&apos;s biographical summary is precise: &quot;He released the first version of the software in May 2011 as closed source software&quot; [@en-wiki-mimikatz]. Fifteen years later, every offensive Windows engagement on Earth still reaches for it.&lt;/p&gt;
&lt;p&gt;Mimikatz contains many modules. Two of them sit directly on the access-control surface and are worth naming explicitly. The repository&apos;s own command surface lists them as &lt;code&gt;privilege::debug&lt;/code&gt; and &lt;code&gt;token::elevate&lt;/code&gt; [@github-gentilkiwi-mimikatz].&lt;/p&gt;
&lt;p&gt;&lt;code&gt;privilege::debug&lt;/code&gt; is one line of code: the command enables &lt;code&gt;SeDebugPrivilege&lt;/code&gt; on the caller&apos;s token. Any local administrator on stock Windows holds the privilege on the token by default; the command flips it from &lt;code&gt;Available&lt;/code&gt; to &lt;code&gt;Enabled&lt;/code&gt; via &lt;code&gt;AdjustTokenPrivileges&lt;/code&gt;. With &lt;code&gt;SeDebugPrivilege&lt;/code&gt; enabled, the calling process can &lt;code&gt;OpenProcess&lt;/code&gt; against any other process on the machine, including SYSTEM-level services such as &lt;code&gt;lsass.exe&lt;/code&gt;. Every Mimikatz session that wants to read process memory begins with &lt;code&gt;privilege::debug&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;token::elevate&lt;/code&gt; is three lines of code in spirit. The command opens a SYSTEM-owned process (typically &lt;code&gt;lsass.exe&lt;/code&gt;), calls &lt;code&gt;OpenProcessToken&lt;/code&gt; to retrieve a handle to the SYSTEM token, calls &lt;code&gt;DuplicateTokenEx&lt;/code&gt; to duplicate the handle for impersonation, and calls &lt;code&gt;SetThreadToken&lt;/code&gt; to attach the duplicated SYSTEM token to the calling thread. The thread is now SYSTEM. The bearer-token property in three lines of code.&lt;/p&gt;
&lt;p&gt;This article does not cover &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt;. That command is the most-cited Mimikatz capability in journalism (it reads cached credentials from &lt;code&gt;lsass.exe&lt;/code&gt;), but the credential-storage surface and the Credential Guard mitigation belong to the &lt;a href=&quot;https://paragmali.com/blog/the-windows-secure-kernel/&quot; rel=&quot;noopener&quot;&gt;Secure Kernel sibling article&lt;/a&gt; in this series [@secure-kernel-sibling]. For the purposes of &lt;em&gt;this&lt;/em&gt; article, the lesson stops at &lt;code&gt;token::elevate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The lesson is the structural concession. With administrator rights on the local machine and &lt;code&gt;SeDebugPrivilege&lt;/code&gt; enabled, the access-control model has &lt;em&gt;no defence&lt;/em&gt; for &quot;I will pretend to be a different process,&quot; because admin equals kernel by Microsoft&apos;s own boundary definition [@msrc-servicing-criteria]. The DACL evaluation algorithm does not protect against a caller who can read and write arbitrary kernel memory. The privilege list does not protect against a caller who can rewrite the privilege check. The integrity check does not protect against a caller who can edit the integrity label. Every primitive in the model is, by construction, defenceless against an attacker who has crossed the boundary the model considers itself responsible for defending.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; With administrator rights and &lt;code&gt;SeDebugPrivilege&lt;/code&gt;, the Windows access-control model has no defence for &quot;I will pretend to be a different process,&quot; because admin equals kernel by Microsoft&apos;s own boundary definition. Mimikatz &lt;code&gt;token::elevate&lt;/code&gt; is the canonical demonstration. The structural fix for &lt;em&gt;selected&lt;/em&gt; secrets is Credential Guard, which moves the secret out of the NT kernel&apos;s address space entirely. See the Secure Kernel sibling article for the architecture [@secure-kernel-sibling, @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The model has been extended in only one structural direction since 1993, and that direction is the &lt;em&gt;subject&lt;/em&gt; of the access matrix. &lt;em&gt;Conditional ACEs&lt;/em&gt; and &lt;em&gt;Dynamic Access Control&lt;/em&gt; (DAC) shipped together in Windows Server 2012 and Windows 8 [@ms-learn-dac]. They are the only extension of the access-matrix subject Microsoft has shipped in thirty-three years.&lt;/p&gt;
&lt;p&gt;The mechanism is twofold. First, ACEs gain an expression syntax. The SDDL ACE strings page documents &lt;code&gt;XA&lt;/code&gt;, &lt;code&gt;XD&lt;/code&gt;, &lt;code&gt;XU&lt;/code&gt;, and &lt;code&gt;ZA&lt;/code&gt; as conditional callback variants of the basic allow / deny / audit / object-allow ACE types [@ms-learn-ace-strings]. A conditional ACE carries an expression in addition to a SID and an access mask, and the kernel evaluates the expression against the token&apos;s claims at access time. The canonical example is &lt;code&gt;(XA;;FA;;;AU;(@User.Department==&quot;Finance&quot;))&lt;/code&gt; -- an allow-callback ACE that grants &lt;code&gt;FILE_ALL_ACCESS&lt;/code&gt; to Authenticated Users &lt;em&gt;if&lt;/em&gt; the token carries a &lt;code&gt;Department&lt;/code&gt; claim equal to &lt;code&gt;&quot;Finance&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Second, the token gains &lt;em&gt;claims&lt;/em&gt;. A claim is a typed key-value pair attached to the token by Active Directory at logon. Claims can be sourced from the user&apos;s AD attributes, the device&apos;s AD attributes, or resource properties on the object. Microsoft Learn states the role they play: &quot;A central access rule is an expression of authorization rules that can include one or more conditions involving user groups, user claims, device claims, and resource properties. Multiple central access rules can be combined into a central access policy&quot; [@ms-learn-dac].&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;Central Access Policy&lt;/em&gt; (CAP) is a set of &lt;em&gt;Central Access Rules&lt;/em&gt; (CARs), each of which is a conditional-ACE expression. The CAP is applied to file shares; the file-share metadata says &quot;evaluate this CAP for every access,&quot; and the CAP&apos;s expressions reference token claims. The DAC scenario guidance enumerates the deployment-side primitives -- automatic and manual file classification, central access policies for safety-net authorisation, central audit policies for compliance reporting, and Rights Management Service encryption for data-in-use protection [@ms-learn-dac-scenario].&lt;/p&gt;
&lt;p&gt;The reason DAC has not displaced classic DAC outside file-server scenarios is in the same Microsoft Learn page: &quot;Dynamic Access Control is not supported in Windows operating systems prior to Windows Server 2012 and Windows 8. When Dynamic Access Control is configured in environments with supported and non-supported versions of Windows, only the supported versions will implement the changes&quot; [@ms-learn-dac]. Heterogeneous environments fall back to classic DAC. Airgapped environments without a working AD plus AD FS plane have no claims to evaluate. Conditional ACEs are a real extension of the model&apos;s subject dimension; they are also a real bet that the AD-and-Kerberos plane is healthy enough to evaluate them on every access.AppContainer&apos;s Package SIDs (Windows 8) and conditional ACEs (Server 2012) shipped the same year. Both extend the &lt;em&gt;subject&lt;/em&gt; dimension of the access matrix -- one with code identity, one with attribute claims. Neither closes the kernel-equals-admin gap. The two extensions are coordinate, not stacked: a conditional ACE can reference a Package SID; a Package SID can be the subject of a conditional ACE [@ms-learn-dac, @app-identity-sibling].&lt;/p&gt;
&lt;p&gt;The model has been extended in two coordinate dimensions in thirty-three years. It has not been replaced. So what does the whole thing look like put together -- and what does it actually fail at?&lt;/p&gt;
&lt;h2&gt;12. The 2026 Plane: Ten Primitives, One Decision&lt;/h2&gt;
&lt;p&gt;Run a single &lt;code&gt;OpenObject&lt;/code&gt; call on a Windows 11 machine and walk the kernel&apos;s path. Every primitive the article has introduced fires for that one call.&lt;/p&gt;

flowchart LR
    A[User-mode caller] --&amp;gt;|OpenObject name, DesiredAccess, Token| B[Object Manager]
    B --&amp;gt;|Resolve name in namespace| C[Namespace lookup]
    C --&amp;gt;|Fetch security descriptor| D[Object header SD]
    D --&amp;gt; E[SeAccessCheck]
    E --&amp;gt; F[Generic-to-specific mapping]
    F --&amp;gt; G[Mandatory Integrity Control check]
    G --&amp;gt;|Pass| H[AppContainer / capability check]
    H --&amp;gt; I[Privilege bypass: SeBackup / SeRestore / SeDebug]
    I --&amp;gt; J[DACL walk in canonical order]
    J --&amp;gt; K[Conditional ACE expression evaluation]
    K --&amp;gt; L[GrantedAccess accumulated]
    L --&amp;gt; M[SACL audit ACE emit if matched]
    M --&amp;gt; N[Return HANDLE or STATUS_ACCESS_DENIED]
&lt;p&gt;The diagram is the article in one figure. Read it left to right. Every box is a primitive named in Sections 3 to 11. Every famous Windows escalation tool of the last twenty-five years targets one of those boxes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Primitive&lt;/th&gt;
&lt;th&gt;Section introduced&lt;/th&gt;
&lt;th&gt;Year shipped&lt;/th&gt;
&lt;th&gt;Canonical primary citation&lt;/th&gt;
&lt;th&gt;Canonical attack&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Security Reference Monitor&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-access-control]&lt;/td&gt;
&lt;td&gt;(Underlying surface; not directly attacked)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Security Identifier (SID)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-security-identifiers]&lt;/td&gt;
&lt;td&gt;Misused well-known SIDs (&quot;Everyone is just a SID&quot;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Access Token&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-access-tokens]&lt;/td&gt;
&lt;td&gt;The Potato lineage; Mimikatz &lt;code&gt;token::elevate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Security Descriptor&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-how-dacls-control-access]&lt;/td&gt;
&lt;td&gt;HiveNightmare (CVE-2021-36934)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;DACL + ACE&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-how-dacls-control-access, @ms-learn-order-of-aces]&lt;/td&gt;
&lt;td&gt;NULL DACL misconfigurations; out-of-order ACEs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;SACL + audit&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-access-control]&lt;/td&gt;
&lt;td&gt;Tools that copy DACL but not SACL silently drop integrity labels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Privilege&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1993&lt;/td&gt;
&lt;td&gt;[@ms-learn-privileges]&lt;/td&gt;
&lt;td&gt;Mimikatz &lt;code&gt;privilege::debug&lt;/code&gt;; &lt;code&gt;SeBackup&lt;/code&gt; abuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Mandatory Integrity Control&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;2007&lt;/td&gt;
&lt;td&gt;[@ms-learn-mic]&lt;/td&gt;
&lt;td&gt;IE7 Protected Mode broker bypasses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;UAC split-token&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;2007&lt;/td&gt;
&lt;td&gt;[@ms-learn-uac]&lt;/td&gt;
&lt;td&gt;UACMe: 70+ AutoElevate-redirect methods [@github-hfiref0x-uacme]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Conditional ACE / DAC&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;2012&lt;/td&gt;
&lt;td&gt;[@ms-learn-dac, @ms-learn-ace-strings]&lt;/td&gt;
&lt;td&gt;Falls back to classic DAC in heterogeneous environments&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Windows access-control model is one decision plane, not a feature catalogue. Every securable Windows operation resolves through &lt;code&gt;SeAccessCheck&lt;/code&gt; against five fixed inputs. Every famous escalation tool of the last twenty-five years attacks one of those inputs. Recognising the model as a single plane is the key to using its vocabulary against any specific attack.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The plane is whole. It is also full of structural holes its own keepers have publicly admitted. What are they?&lt;/p&gt;
&lt;h2&gt;13. The Five Structural Limits&lt;/h2&gt;
&lt;p&gt;Microsoft&apos;s &lt;em&gt;Security Servicing Criteria for Windows&lt;/em&gt; defines a security boundary as &quot;a logical separation between the code and data of security domains with different levels of trust... the separation between kernel mode and user mode is a classic [...] security boundary&quot; [@msrc-servicing-criteria]. The criteria document then enumerates which boundaries Microsoft commits to servicing. The kernel-mode / user-mode boundary qualifies. UAC and admin-to-kernel are not in the enumerated list. Once that admission is on the public record, the model&apos;s structural arc becomes legible. Five derived limits flow from the concession.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limit 1: Admin equals kernel.&lt;/strong&gt; Any compromise with administrator rights can rewrite the model&apos;s own enforcement code. &lt;em&gt;Consequence:&lt;/em&gt; Mimikatz, every kernel-driver-loading attack, every signed-driver bring-your-own-vulnerable-driver path. &lt;em&gt;Successor:&lt;/em&gt; VBS Trustlets, which host secrets and policy enforcement in the &lt;em&gt;Virtual Trust Level 1&lt;/em&gt; user-mode environment that the VTL0 NT kernel cannot read or modify. Detailed coverage belongs to the Secure Kernel sibling article in this series [@secure-kernel-sibling].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limit 2: Tokens are bearer credentials.&lt;/strong&gt; Whichever process holds the handle gets the rights. The kernel does not ask how the handle was obtained. &lt;em&gt;Consequence:&lt;/em&gt; the entire Potato lineage (eight tools, six years), Mimikatz &lt;code&gt;token::elevate&lt;/code&gt;, every cross-session token-theft attack. &lt;em&gt;Successor:&lt;/em&gt; Adminless / Administrator Protection, which retires the long-lived filtered/full token pair in favour of a fresh, time-limited, just-in-time elevation flow gated by Windows Hello plus a hidden, system-generated, profile-separated user account that issues an isolated admin token [@ms-learn-administrator-protection, @techcommunity-admin-protection]. The forthcoming Adminless article in this series will cover the architecture in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limit 3: &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; on every service account.&lt;/strong&gt; IIS, SQL Server, the Print Spooler, scheduled tasks, Docker, Citrix, almost every managed-service account by default. &lt;em&gt;Consequence:&lt;/em&gt; every Potato, by construction. &lt;em&gt;Partial successor today:&lt;/em&gt; per-service SIDs and Group Managed Service Accounts let administrators constrain the blast radius of a compromised service. &lt;em&gt;Structural successor:&lt;/em&gt; Adminless, which removes the privilege from the daily authentication path and demands a fresh elevation per privileged action [@ms-learn-administrator-protection, @techcommunity-admin-protection].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limit 4: NTLM relay surface.&lt;/strong&gt; As long as Windows services accept NTLM and the operating system signs NTLM challenges with the local-machine credential, the local-NTLM-to-self attack is structurally available. &lt;em&gt;Consequence:&lt;/em&gt; PetitPotam, RemotePotato0, every cross-protocol relay. &lt;em&gt;Successor:&lt;/em&gt; NTLMless, which formally retires NTLM as a default Windows authentication protocol [@techcommunity-windows-auth-evolution]. The on-ramp is the NTLM auditing channel introduced in Windows 11 24H2 and Windows Server 2025 (KB5064479, original publish date July 11, 2025), which records NTLMv1 usage in &lt;code&gt;Microsoft\Windows\NTLM\Operational&lt;/code&gt; and gives administrators a per-workload deprecation telemetry [@ms-support-ntlm-auditing]. The forthcoming NTLMless article in this series will cover the architecture in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Limit 5: The DACL is local.&lt;/strong&gt; Conditional ACEs and Dynamic Access Control claims need a working AD-and-AD-FS plane to evaluate; airgapped or heterogeneous environments fall back to user / group SIDs as the only available subject. &lt;em&gt;Consequence:&lt;/em&gt; the access-matrix subject is, in practice, still &quot;user and group&quot; for most non-file-server workloads. The 2012 extension to claims and code identity is real but operationally bounded.&lt;/p&gt;
&lt;p&gt;The deepest of the five limits is the one Norm Hardy named in 1988. Hardy&apos;s framing returned in Section 2 [@en-wiki-confused-deputy] holds: capability systems close the gap structurally; ACL engineering does not.&lt;/p&gt;
&lt;p&gt;seL4 closes it with machine-checked correctness proofs and a capability-based design that makes ambient authority a category error [@en-wiki-capability-based-security]. Windows closes it, when it closes it at all, with VBS Trustlets that move &lt;em&gt;the right to perform the operation&lt;/em&gt; into a separate execution domain. The Potato lineage is the textbook confused-deputy instance: a service running with &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; is the privileged compiler; the attacker is the user holding a billing-records-shaped pointer; the service uses &lt;em&gt;its own&lt;/em&gt; authority on every authentication it accepts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Hardy&apos;s 1988 paper [@wayback-cap-lore-hardy] and the Wikipedia summary [@en-wiki-confused-deputy] both say the same thing: ACL systems are structurally vulnerable to confused-deputy attacks; capability systems are not. The gap is not asymptotic. ACL engineering does not close it. The Potato lineage is what the gap looks like in the field, repeated against eight different coercion primitives over six years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; &lt;strong&gt;The next generation of Windows defences cannot live inside the kernel, because the kernel is on the wrong side of the boundary the model draws.&lt;/strong&gt; Microsoft&apos;s own servicing criteria admit it. Adminless, NTLMless, VBS Trustlets, and Credential Guard are the four non-overlapping ways to fix it. Each successor was scoped to close a specific gap the access-control model could not.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The five limits are named. The successors are shipping. What replaces what?&lt;/p&gt;
&lt;h2&gt;14. The Successors: Adminless, NTLMless, VBS Trustlets, Credential Guard&lt;/h2&gt;
&lt;p&gt;One paragraph each. This section is a forward-reference index, not a detailed walk-through.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adminless.&lt;/strong&gt; Removes the local Administrators group from the daily authentication path. The long-lived filtered / full token pair the UAC model produces at logon is replaced with a fresh, time-limited, just-in-time elevation flow: when a user wants to perform a privileged action, the system gates the action behind &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Windows Hello&lt;/a&gt; plus a hidden, system-generated, profile-separated user account that issues an isolated admin token, and the resulting token is bounded in time and scope [@ms-learn-administrator-protection].&lt;/p&gt;
&lt;p&gt;The Microsoft Tech Community announcement (modified November 19, 2024) summarises the security argument: &quot;By requiring explicit authorization for every administrative task, Administrator protection protects Windows from accidental changes by users and changes by malware... Malicious software often relies on admin privileges to change device settings and execute harmful actions. Administrator protection breaks the attack kill chain&quot; [@techcommunity-admin-protection]. &lt;em&gt;Closes:&lt;/em&gt; limits #2 and #3 -- there is no long-lived bearer credential to steal, and &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; does not need to live on every service account because services run as bounded principals issued capabilities at the moment of need. Forthcoming article in this series.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NTLMless.&lt;/strong&gt; Formally retires NTLM as a default Windows authentication protocol [@techcommunity-windows-auth-evolution]. The Tech Community announcement is unambiguous about direction: &quot;Reducing the use of NTLM will ultimately culminate in it being disabled in Windows 11. We are taking a data-driven approach and monitoring reductions in NTLM usage to determine when it will be safe to disable&quot; [@techcommunity-windows-auth-evolution].&lt;/p&gt;
&lt;p&gt;The transition rests on a local KDC (IAKerb) that lets Kerberos service both local and domain accounts, plus an audit channel introduced in Windows 11 24H2 and Windows Server 2025 (KB5064479, original publish date July 11, 2025) that records NTLMv1 usage in &lt;code&gt;Microsoft\Windows\NTLM\Operational&lt;/code&gt; and gives administrators per-service telemetry on which workloads still require the protocol [@ms-support-ntlm-auditing]. The local-NTLM-to-self attack class -- coerce a SYSTEM service to authenticate with the local-machine credential, accept the challenge, relay it back to a local service that trusts the credential -- ends when the local-machine NTLM credential ends. &lt;em&gt;Closes:&lt;/em&gt; limit #4. Forthcoming article in this series.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VBS Trustlets and Isolated User Mode.&lt;/strong&gt; Shipped in Windows 10 1507 in 2015. &lt;em&gt;Virtualization-Based Security&lt;/em&gt; (VBS) uses the Hyper-V hypervisor to host a second user-mode environment, &lt;em&gt;Virtual Trust Level 1&lt;/em&gt; (VTL1), whose memory the NT kernel running in VTL0 cannot read or write. A &lt;em&gt;Trustlet&lt;/em&gt; is a process that runs in VTL1. &lt;em&gt;Closes:&lt;/em&gt; limit #1, for selected secrets. The ordinary NT kernel still runs the show for ordinary processes; VTL1 is a side-channel for secrets and policy decisions that the model wants to protect even from a kernel-level attacker. Detailed coverage in the Secure Kernel sibling article [@secure-kernel-sibling].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credential Guard.&lt;/strong&gt; The canonical first Trustlet. &lt;code&gt;lsass.exe&lt;/code&gt; continues to run in VTL0 and answer authentication requests; the credential blobs &lt;code&gt;lsass.exe&lt;/code&gt; historically held are moved to a Trustlet called &lt;code&gt;LsaIso&lt;/code&gt; in VTL1. The VTL0 &lt;code&gt;lsass.exe&lt;/code&gt; retains &lt;em&gt;handles&lt;/em&gt; to the blobs but cannot read their contents; authentication happens by calling into the Trustlet. Mimikatz &lt;code&gt;sekurlsa::logonpasswords&lt;/code&gt; returns no plaintext credentials against a Credential-Guard-on system, because the plaintext does not live in VTL0 memory at all. The default-enablement timeline and the SKU-specific configuration matrix are covered in the Secure Kernel sibling article [@secure-kernel-sibling].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pluton-rooted attestation and the hardware foundation.&lt;/strong&gt; The successor architectures rest on a hardware identity chain that begins below the firmware, in Microsoft&apos;s Pluton in-die security processor. Pluton holds the keys that vouch for the boot measurements that the OS in turn uses to attest its own integrity to a remote relying party. The &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Pluton article&lt;/a&gt; in this series covers the architecture and the Caliptra root-of-trust direction it foreshadows [@pluton-sibling]. The &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM 2.0 architecture&lt;/a&gt; that the same chain extends and the &lt;a href=&quot;https://paragmali.com/blog/secure-boot-in-windows-the-chain-from-sector-zero-to-userini/&quot; rel=&quot;noopener&quot;&gt;Secure Boot chain&lt;/a&gt; that runs before the access-control model boots are covered in their own sibling articles in this series.&lt;/p&gt;

The five limits enumerated in Section 13 and the four successor articles in this section are in one-to-one correspondence: Adminless closes #2 and #3, NTLMless closes #4, VBS Trustlets close #1, and Credential Guard is the canonical first Trustlet that demonstrates #1 closing for a specific high-value secret. Limit #5 -- the DACL is local -- is operational rather than architectural and is closed by deployment investment in AD plus AD FS rather than by a new mechanism. The correspondence is not a coincidence. Each successor was scoped to close a specific gap the access-control model could not close from inside.
&lt;p&gt;With the gaps named and the successors mapped, what does an administrator actually do today?&lt;/p&gt;
&lt;h2&gt;15. Practical Guide&lt;/h2&gt;
&lt;p&gt;Six concrete recommendations for 2026, each tied to a primary Microsoft Learn or named-expert source.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;whoami /all&lt;/code&gt; prints the SIDs in the calling thread&apos;s token, the integrity level, every privilege with its &lt;code&gt;Enabled&lt;/code&gt; / &lt;code&gt;Disabled&lt;/code&gt; / &lt;code&gt;Default Enabled&lt;/code&gt; state, and -- on AD-joined machines with claims -- the user and device claim set. It is the single most useful diagnostic command for understanding what a session can do. Read the &lt;code&gt;Enabled&lt;/code&gt; column carefully: an available-but-disabled privilege does not affect any access check until the process explicitly enables it [@ms-learn-access-tokens].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;icacls &amp;lt;path&amp;gt;&lt;/code&gt; prints the DACL on a file or directory; the mass-rights letters are &lt;code&gt;(F)&lt;/code&gt; full, &lt;code&gt;(M)&lt;/code&gt; modify, &lt;code&gt;(RX)&lt;/code&gt; read and execute, &lt;code&gt;(R)&lt;/code&gt; read, &lt;code&gt;(W)&lt;/code&gt; write, &lt;code&gt;(D)&lt;/code&gt; delete, &lt;code&gt;(GA)&lt;/code&gt; generic all, &lt;code&gt;(GR)&lt;/code&gt; generic read, &lt;code&gt;(GW)&lt;/code&gt; generic write [@ms-learn-how-dacls-control-access]. PowerShell&apos;s &lt;code&gt;Get-Acl&lt;/code&gt; returns the same descriptor as a structured object that can be filtered and audited at scale. Sysinternals &lt;code&gt;accesschk.exe&lt;/code&gt; answers the inverted query (which paths grant a given SID a given right) and is the right tool for catching descriptor misconfigurations across a large file system. Treat NULL DACL and empty DACL surfaces as the most-likely misconfiguration vectors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On every Windows server, enumerate the principals whose tokens hold &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; or &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt; in their &lt;em&gt;Default&lt;/em&gt; or &lt;em&gt;Available&lt;/em&gt; lists. Treat any non-LocalSystem-or-equivalent holder as a Potato target until proven otherwise. Where a service must hold the privilege (most managed-service workloads do), constrain the blast radius with per-service SIDs and Group Managed Service Accounts so that a compromise of one service does not extend to a compromise of every service that shares the host&apos;s identity [@github-itm4n-printspoofer].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The UACMe README is the institutional memory for the seventy-method bypass canon. Every method&apos;s &lt;code&gt;Fixed in:&lt;/code&gt; field cites a specific Windows version or &lt;code&gt;unfixed&lt;/code&gt;. Before declaring a binary &quot;patched,&quot; consult the README; a method with a &lt;code&gt;Fixed in: unfixed&lt;/code&gt; annotation is structurally available on every supported Windows version. The institutional position is that UAC bypasses do not, by Microsoft&apos;s own servicing-criteria policy, earn CVEs of their own, so the mitigations are issued per-redirect rather than per-feature [@github-hfiref0x-uacme, @msrc-servicing-criteria].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Windows Event ID 4688 (&quot;A new process has been created&quot;) is the most-cited detection signal for the Potato lineage and the UAC bypass tradition, because almost every member of both families ends in a &lt;code&gt;CreateProcessAsUser&lt;/code&gt; or a redirected AutoElevate launch with a command-line argument that does not match the legitimate use of the parent binary. Enable command-line auditing under &lt;em&gt;Audit Process Creation&lt;/em&gt; and forward the log; Sysmon Event ID 1 is the equivalent and richer signal in environments that deploy Sysinternals&apos; Sysmon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The access matrix is the part of the model with deliberately extensible &lt;em&gt;subjects&lt;/em&gt;. New code that lives behind an AppContainer SID gets a Low-IL token, a Package SID, and a capability list that constrain what it can touch even when the user running it is an administrator. New file shares that need attribute-based authorization should use conditional ACEs and Dynamic Access Control rather than ad-hoc group membership. Cross-link to the &lt;a href=&quot;https://paragmali.com/blog/windows-app-identity-33-year-reinvention/&quot; rel=&quot;noopener&quot;&gt;App Identity sibling article&lt;/a&gt; for Package SID derivation [@app-identity-sibling] and to the Dynamic Access Control overview [@ms-learn-dac].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;{`
// Inputs:
//   token       -- {sids:[...], integrity:&apos;Low&apos;|&apos;Medium&apos;|&apos;High&apos;|&apos;System&apos;,
//                   appContainer:bool, capabilities:[...], claims:{...},
//                   privileges:{enabled:[...]}}
//   descriptor  -- {dacl:[...], integrityLabel:&apos;Low&apos;|...|&apos;System&apos;,
//                   policyNoWriteUp:bool}
//   desired     -- access mask (number)
// Output: {granted, status, fired:[...]}&lt;/p&gt;
&lt;p&gt;function fullAccessCheck(token, descriptor, desired) {
  const fired = [];
  const ilOrder = {Low:1, Medium:2, High:3, System:4};&lt;/p&gt;
&lt;p&gt;  // 1. MIC check fires before DACL walk.
  if (descriptor.policyNoWriteUp) {
    const writeBits = 0x00040000 | 0x00000002 | 0x00000004; // WRITE_DAC|WRITE|APPEND
    if ((desired &amp;amp; writeBits) &amp;amp;&amp;amp; ilOrder[token.integrity] &amp;lt; ilOrder[descriptor.integrityLabel]) {
      fired.push(&apos;MIC no-write-up: token IL &apos; + token.integrity + &apos; &amp;lt; object IL &apos; + descriptor.integrityLabel);
      return {granted:0, status:&apos;DENIED at integrity check&apos;, fired};
    }
  }&lt;/p&gt;
&lt;p&gt;  // 2. Privilege bypass short-circuit.
  if (token.privileges.enabled.includes(&apos;SeBackupPrivilege&apos;) &amp;amp;&amp;amp; (desired &amp;amp; 0x80000000)) {
    fired.push(&apos;SeBackupPrivilege bypass: GENERIC_READ granted&apos;);
    return {granted: desired, status:&apos;GRANTED via SeBackupPrivilege&apos;, fired};
  }&lt;/p&gt;
&lt;p&gt;  // 3. AppContainer capability check (simplified).
  if (token.appContainer &amp;amp;&amp;amp; descriptor.requiresCapability) {
    if (!token.capabilities.includes(descriptor.requiresCapability)) {
      fired.push(&apos;AppContainer capability check: missing &apos; + descriptor.requiresCapability);
      return {granted:0, status:&apos;DENIED at AppContainer check&apos;, fired};
    }
  }&lt;/p&gt;
&lt;p&gt;  // 4. DACL walk, deny-first, in canonical order.
  let remaining = desired;
  let granted = 0;
  for (const ace of (descriptor.dacl || [])) {
    if (!token.sids.includes(ace.sid)) continue;
    if (ace.condition &amp;amp;&amp;amp; !evalCondition(ace.condition, token.claims)) continue;
    if (ace.type === &apos;DENY&apos; &amp;amp;&amp;amp; (ace.mask &amp;amp; remaining) !== 0) {
      fired.push(&apos;Conditional/plain DENY: &apos; + ace.sid);
      return {granted:0, status:&apos;DENIED at DACL&apos;, fired};
    }
    if (ace.type === &apos;ALLOW&apos;) {
      const newBits = ace.mask &amp;amp; remaining;
      granted |= newBits;
      remaining &amp;amp;= ~newBits;
      fired.push(&apos;ALLOW &apos; + ace.sid + &apos;: granted 0x&apos; + newBits.toString(16));
    }
    if (remaining === 0) {
      return {granted, status:&apos;GRANTED&apos;, fired};
    }
  }
  return {granted, status: remaining === 0 ? &apos;GRANTED&apos; : &apos;DENIED end of DACL&apos;, fired};
}&lt;/p&gt;
&lt;p&gt;function evalCondition(expr, claims) {
  // Toy evaluator for &quot;(@User.Department == \&quot;Finance\&quot;)&quot;-style expressions.
  const m = expr.match(/@User\.(\w+)\s*==\s*&quot;([^&quot;]+)&quot;/);
  if (!m) return true;
  return claims[m[1]] === m[2];
}&lt;/p&gt;
&lt;p&gt;// Demo: a Medium-IL user trying to write to a System-IL object via an allow ACE.
console.log(fullAccessCheck(
  {sids:[&apos;S-1-5-21-X-Y-Z-1001&apos;], integrity:&apos;Medium&apos;, appContainer:false, capabilities:[], claims:{Department:&apos;Finance&apos;},
   privileges:{enabled:[]}},
  {dacl:[{type:&apos;ALLOW&apos;, sid:&apos;S-1-5-21-X-Y-Z-1001&apos;, mask:0xFFFFFFFF}],
   integrityLabel:&apos;System&apos;, policyNoWriteUp:true},
  0x00040000));  // WRITE_DAC
`}&lt;/p&gt;
&lt;p&gt;The simulator runs the full plane in order: MIC integrity check, privilege bypass short-circuit, AppContainer capability check, DACL walk with conditional-ACE evaluation. Reading the &lt;code&gt;fired&lt;/code&gt; log in the output tells you which primitive made the decision and why. It is the mental model the rest of the article has been building toward.
&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The six tips and the simulator together close the practical loop. With them, the practitioner can reason about any specific access decision the way the kernel does -- not by remembering features, but by walking the same plane.&lt;/p&gt;
&lt;p&gt;The Sysinternals &lt;code&gt;accesschk&lt;/code&gt; and &lt;code&gt;psgetsid&lt;/code&gt; utilities have long been first-line investigative tools for ACL audits. Both ship in the Sysinternals Suite today and continue to surface the same descriptors &lt;code&gt;Get-Acl&lt;/code&gt; and &lt;code&gt;icacls&lt;/code&gt; print, in the form most useful to an administrator working at scale.&lt;/p&gt;
&lt;h2&gt;16. Frequently Asked Questions&lt;/h2&gt;


No. By Microsoft&apos;s own *Security Servicing Criteria for Windows*, UAC and admin-to-kernel are not on the enumerated security-boundary list [@msrc-servicing-criteria]; bypasses are not, by policy, eligible for security servicing as boundary violations. The seventy-plus methods catalogued in UACMe are the empirical consequence of the classification, not a long string of bugs in a feature that was meant to defend against the techniques [@github-hfiref0x-uacme].


No. `Everyone` (the well-known SID `S-1-1-0`) is just a SID. ACEs that reference it are subject to the same DACL walk as any other SID; if a deny ACE for `Everyone` precedes an allow ACE for `Authenticated Users`, access is denied. The DACL evaluation algorithm does not know `Everyone` is special. Forshaw made the point with a meme-able rant in 2020: &quot;S-1-1-0 is NOT A SECURITY BOUNDARY&quot; [@tiraniddo-sharing-logon-session].


No. *Empty* DACL denies all access. *No* DACL (a NULL DACL) grants full access. Newly-written code that &quot;creates a file with no protection&quot; almost always gets this distinction wrong [@ms-learn-how-dacls-control-access]. Verify with `Get-Acl` or `icacls` after creation; an `icacls` output of `Everyone:(F)` on an object you intended to lock down is almost always a NULL DACL, not the policy you meant to write.


For DACL alone, yes. For MIC, no -- a System-IL administrator still cannot write to a process at higher integrity if MIC denies the request, because the integrity check fires before the DACL walk [@ms-learn-mic]. For AppContainer, no -- AppContainer-bound objects require the capability SID, not just an administrator SID. For VBS Trustlets, no -- secrets in VTL1 are unreachable from VTL0 even with administrator rights, which is the whole point of the architecture [@secure-kernel-sibling].


No. The list shows *available* privileges. The `Enabled` column is the one that matters for runtime decisions; available-but-disabled privileges must be enabled via `AdjustTokenPrivileges` before any privileged operation can use them. Most privileges are disabled by default precisely so that a process must explicitly opt in to using one, which lets a security-conscious application minimise the window in which a bug can abuse the privilege [@ms-learn-privileges].


No. The underlying NTLM-to-self surface is still open. SharpEfsPotato (2021) [@github-bugch3ck-sharpefspotato] is the most recent member of the lineage; new tools using fresh coercion primitives (EFSRPC, the spooler, the schedule-task COM interface, cross-session DCOM) appear every twelve to eighteen months. Microsoft&apos;s own Hot Potato post called the underlying issue &quot;hard to fix without breaking backward compatibility&quot; [@foxglove-hot-potato-blog]; the structural fix is the Adminless and NTLMless successor articles, not a point patch on any one primitive.


Partially. AppContainer is a process-level isolation mechanism with a Low-IL token plus a capability-SID list. It is also a *named principal* in the Windows access-control model -- something Chrome&apos;s sandbox is not -- which means AppContainer-bound code can be referenced by SID in a DACL or conditional ACE, and Windows can refuse access to it as a principal in its own right. The sibling App Identity article in this series covers the Package SID derivation and the relationship to Authenticode and App Control for Business [@app-identity-sibling].

&lt;h2&gt;17. Closing: Return to the Hook&lt;/h2&gt;
&lt;p&gt;Open a Windows PowerShell window again. Run &lt;code&gt;whoami /priv&lt;/code&gt;. Read the column on the right, this time with the article&apos;s vocabulary annotated above each line.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeShutdownPrivilege&lt;/code&gt; -- a privilege, in the kernel sense of a pre-checked superpower; bookkeeping rather than power.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeIncreaseWorkingSetPrivilege&lt;/code&gt; -- the same. Most of the twenty rows are housekeeping that the kernel checks at specific call sites to gate non-security-critical operations.&lt;/p&gt;
&lt;p&gt;The five rows that matter are easy to spot once you know what to look for. &lt;code&gt;SeDebugPrivilege&lt;/code&gt; -- Mimikatz starts here. &lt;code&gt;SeImpersonatePrivilege&lt;/code&gt; -- the entire Potato lineage starts here. &lt;code&gt;SeAssignPrimaryTokenPrivilege&lt;/code&gt; -- the second half of every token-replay attack. &lt;code&gt;SeBackupPrivilege&lt;/code&gt; -- HiveNightmare&apos;s privilege class. &lt;code&gt;SeRestorePrivilege&lt;/code&gt; -- service-binary replacement. The kernel reads the same column on every securable operation, billions of times a second, and the answer to &quot;can this code do this?&quot; is built out of this list every time.&lt;/p&gt;
&lt;p&gt;Now run &lt;code&gt;icacls C:\Windows\System32\drivers\etc\hosts&lt;/code&gt; again. &lt;code&gt;BUILTIN\Administrators:(F)&lt;/code&gt; is an allow ACE granting full control to the well-known SID &lt;code&gt;S-1-5-32-544&lt;/code&gt;. &lt;code&gt;NT AUTHORITY\SYSTEM:(F)&lt;/code&gt; is an allow ACE granting full control to &lt;code&gt;S-1-5-18&lt;/code&gt;. &lt;code&gt;BUILTIN\Users:(R)&lt;/code&gt; is an allow ACE granting &lt;code&gt;FILE_GENERIC_READ&lt;/code&gt; to &lt;code&gt;S-1-5-32-545&lt;/code&gt;. The DACL is in canonical order: explicit entries before inherited entries, deny entries (none here) before allow entries within each group. &lt;code&gt;SeAccessCheck&lt;/code&gt; will walk this DACL on every read of &lt;code&gt;hosts&lt;/code&gt; from any process on the machine, and the output will be deterministic -- the same answer every time, for the same caller -- because the model that produces it is closed and finite.&lt;/p&gt;
&lt;p&gt;The article&apos;s payoff. Every later post in this series starts where this one ends. The Adminless article retires the bearer-credential property of long-lived tokens. The NTLMless article retires the local-NTLM-to-self relay surface. The Secure Kernel article hosts secrets in VTL1 outside the NT kernel&apos;s address space and tells the Credential Guard story in detail [@secure-kernel-sibling]. The Pluton article roots the hardware identity chain that the successor architectures all eventually verify against [@pluton-sibling]. The TPM article and the Secure Boot article cover the static-time and boot-time chains that run before the access-control model even loads. Each successor was scoped to close a specific gap the access-control model could not close from inside.&lt;/p&gt;
&lt;p&gt;NT 3.1 froze a model in July 1993 because federal procurement demanded it. That model has not structurally changed in thirty-three years. The accumulated attack surface against it -- twenty-five years, eight Potatoes, seventy UAC bypasses, one Mimikatz -- is the empirical proof that &quot;frozen&quot; was always going to mean &quot;attackable from below.&quot; The next generation of defences takes that lesson and stops trying to fix the model from inside. The model is not a feature catalogue. It is a decision plane with five inputs, ten primitives, and five publicly conceded structural limits, and the four successor architectures of the next decade are the four non-overlapping ways to close those limits without re-evaluating against TCSEC C2 again.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SeAccessCheck&lt;/code&gt; decides every time. The next decade decides what it decides about.&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;windows-access-control-twenty-five-years&quot; keyTerms={[
  { term: &quot;SeAccessCheck&quot;, definition: &quot;The kernel routine that decides whether a thread may perform a requested set of operations on an object. Takes a security descriptor, an access token, a desired-access mask, a generic-mapping table, and previously-granted access; returns the granted access mask plus a status code.&quot; },
  { term: &quot;Security Reference Monitor (SRM)&quot;, definition: &quot;The kernel-mode component that owns SeAccessCheck and the audit log generation routines. Every other kernel component that needs to grant or deny access calls into it.&quot; },
  { term: &quot;Access Token&quot;, definition: &quot;A kernel object that names the security identity of a thread or process. Carries the user&apos;s SID, group SIDs, privileges, integrity level, primary/impersonation flag, and (for restricted tokens) a list of restricting SIDs. The kernel consults the token on every access check.&quot; },
  { term: &quot;Discretionary Access Control List (DACL)&quot;, definition: &quot;The ordered list of allow / deny ACEs attached to a securable object. The object&apos;s owner controls the contents, in contrast to a mandatory list.&quot; },
  { term: &quot;Mandatory Integrity Control (MIC)&quot;, definition: &quot;A Vista-era addition that adds an integrity-level check to SeAccessCheck. The integrity check fires before the DACL walk and enforces no-write-up by default.&quot; },
  { term: &quot;User Account Control (UAC)&quot;, definition: &quot;A Vista-era split-token mechanism in which an administrative user receives two linked tokens at logon: a filtered Medium-IL standard-user token and a full High-IL administrative counterpart. Not, by Microsoft&apos;s own servicing criteria, an enforced security boundary.&quot; },
  { term: &quot;SeImpersonatePrivilege&quot;, definition: &quot;The privilege that lets a service accept an impersonation token from a client. Held by every Windows service account by default. The load-bearing privilege for the entire Potato lineage.&quot; },
  { term: &quot;Confused Deputy&quot;, definition: &quot;Norm Hardy&apos;s 1988 framing of the structural failure mode of any ambient-authority access-control system: a privileged service can be tricked into using its own authority on the attacker&apos;s behalf because the system cannot distinguish authority the service has from authority the service is being asked to use.&quot; },
  { term: &quot;VBS Trustlet&quot;, definition: &quot;A Windows process that runs in Virtual Trust Level 1, a hardware-isolated user-mode environment whose memory the NT kernel running in VTL0 cannot read or write. The architectural answer to the admin-equals-kernel concession of the access-control model.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>access-control</category><category>privilege-escalation</category><category>security-tokens</category><category>uac</category><category>mimikatz</category><category>potato-attacks</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>