A Mitigation That Became a Primitive: The Story of SeImpersonatePrivilege
How a 2003 backward-compatibility privilege became the most-abused Windows service primitive, and why every Microsoft closure path breaks something shipped.
Permalink1. The One Line in whoami /priv
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 whoami /priv. One line will read:
SeImpersonatePrivilege Impersonate a client after authentication Enabled
That single line is sufficient, given the right coercion primitive, to become NT AUTHORITY\SYSTEM in under a second. Microsoft has known this on the record since April 2009 [1]. The privilege has not moved.
A Windows user right that lets a process call any of the kernel's token-substitution APIs on a token it has received from another principal. The right is enumerated as the constant SE_IMPERSONATE_NAME [2]. 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 [3].
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's default privilege set; in both cases SE_IMPERSONATE_NAME appears with the marker (enabled) [@ms-learn-localservice; @ms-learn-networkservice].
The Microsoft Learn pages list this assignment as a default. "Enabled" is a token-state distinction with operational weight. Most privileges in a service-account token are present but disabled: the process can call AdjustTokenPrivileges to turn them on, but until that happens the kernel treats the privilege as absent during access checks. SeImpersonatePrivilege on a NETWORK SERVICE token is shipped enabled. The process can call CreateProcessWithTokenW immediately, on first instruction.
Andrea Pierini, the researcher who has spent more time with this primitive than anyone outside Microsoft, put the operational fact in eleven words: "if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM" [4]. Clement Labro, quoting him, added the qualifier: "a deliberately provocative shortcut obviously, but it's not far from the truth." The aphorism gets repeated in every PrintSpoofer-era writeup for a reason.
Here is the article's load-bearing claim, stated up front and re-argued through every section that follows:
The figure "roughly eighteen years" anchors to Cesar Cerrudo's March 2008 disclosure at Hack In The Box Dubai [5]. The privilege itself shipped earlier, in Server 2003 / XP SP2 (2003-2004), and the operational-pushbutton anchor is Stephen Breen's HotPotato (January 16, 2016) [6]. Three different dates, three different anchors for "how long has this been true." The article uses the Cerrudo date because that is when the fact entered the offensive-research public record.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.
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.
// On a Windows service account, this is the line that matters:
const tokenPrivileges = [
{ name: 'SeAssignPrimaryTokenPrivilege', state: 'Disabled' },
{ name: 'SeIncreaseQuotaPrivilege', state: 'Disabled' },
{ name: 'SeAuditPrivilege', state: 'Disabled' },
{ name: 'SeChangeNotifyPrivilege', state: 'Enabled' },
{ name: 'SeImpersonatePrivilege', state: 'Enabled' }, // <-- the gate
{ name: 'SeCreateGlobalPrivilege', state: 'Enabled' },
];
const gateOpen = tokenPrivileges.some(
p => p.name === 'SeImpersonatePrivilege' && p.state === 'Enabled'
);
console.log(gateOpen ? 'Gate is open. Token-source primitive is the only missing piece.' : 'Gate is closed.'); Press Run to execute.
If one line in whoami /priv 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's own "about eleven years ago" dating from his 1988 paper.
2. Hardy's Deputy and the 2003 Service-Hardening Pivot
In the late 1970s, around 1977, a Tymshare engineer named Norm Hardy watched a FORTRAN compiler with "home files license" overwrite the system billing file (SYSX)BILL because some user had passed that path as the compiler's debug-output target. The compiler had two authorities -- its own (to read system libraries) and the caller's (to write the caller's files) -- and no way to keep them separate when serving a request. The compiler was, in Hardy's later phrasing, confused about which authority to use [7].
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's 1988 paper [7] 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.
Hardy'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 [8]. Windows is an instance of that model. A NETWORK SERVICE process holding SeImpersonatePrivilege is Hardy's deputy: 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.
2.1 The kernel object Cutler's team shipped in 1993
Dave Cutler's NT 3.1 team chose the identity-and-ACL model and built a kernel object to carry it. The access token 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 "does this token, evaluated against this object's ACL, grant the requested rights?" The standard reference is Windows Internals, Part 1, chapter on security [9].
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).
NT 3.1 also shipped two structural distinctions that the rest of this article depends on. First, primary versus impersonation 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 impersonation levels (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's authority -- and both distinctions are the surface every Potato variant operates on.
The Tymshare anecdote that Hardy uses in the 1988 paper -- the FORTRAN compiler that overwrote(SYSX)BILL -- 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 "home files license" 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 "only files the caller could write." Hardy's own dating in the paper is "about eleven years ago" from 1988 -- so the events sit in the late 1970s, not the early ones.
2.2 Why the privilege exists: the 2003 service-hardening pivot
Through the 1990s, Windows services almost universally ran under NT AUTHORITY\SYSTEM. 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 [10]. Every successful remote code execution against a service became a SYSTEM compromise of the host, because the service was SYSTEM.
Microsoft's response was a structural retreat. Two new well-known accounts shipped in Windows Server 2003 (and reached desktop with XP SP2 in 2004): NT AUTHORITY\LOCAL SERVICE (no network credentials) and NT AUTHORITY\NETWORK SERVICE (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 -- SeTcbPrivilege, SeLoadDriverPrivilege, SeRestorePrivilege -- 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.
But the new accounts could not lose every SYSTEM authority. Pre-2003 services routinely impersonated their clients to make access checks against per-user resources -- IIS reading a user's home directory under the user'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 ImpersonateNamedPipeClient (or RpcImpersonateClient, or one of the LSA-side APIs) and then act under the caller's token. If LOCAL SERVICE and NETWORK SERVICE could not impersonate, the entire RPC server population would break.
So Microsoft introduced SeImpersonatePrivilege -- 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's auto-grant logic) every service configured to run under one of those accounts [3]. The policy-setting page is explicit about the intent: "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" [3].
The privilege, in other words, was created as a mitigation. 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.
Diagram source
flowchart TD
Client["Low-privileged caller"] -- "Connects to attacker pipe" --> NS["NETWORK SERVICE process"]
NS -- "Holds its own modest authority" --> A1["Authority 1, service identity"]
NS -- "Holds SeImpersonatePrivilege" --> A2["Authority 2, any token it receives"]
SYSPROC["Privileged caller, SYSTEM"] -- "Coerced to authenticate to the pipe" --> NS
NS -- "Impersonate caller token, then act" --> Action["Action runs under SYSTEM"] Microsoft did not introduce SeImpersonatePrivilege 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.
3. The Token API Surface
There is no single "impersonate" 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.
3.1 Primary versus impersonation tokens
The kernel distinguishes TOKEN_PRIMARY from TOKEN_IMPERSONATION. 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 SecurityImpersonation or SecurityDelegation lets you take real action under the borrowed identity. An Identification-level token can be checked against ACLs but cannot be used to open kernel objects under the new identity, and an Anonymous-level token is useless for almost everything [@ms-learn-windows-internals; @ms-learn-impersonateloggedonuser].
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.
SecurityIdentification versus SecurityImpersonation distinction is the gate that makes many naive coercion attempts fail. If the attacker controls only an RPC interface that performs an ImpersonateClient call without the right SQOS (Security Quality of Service) negotiation, the resulting token may land at SecurityIdentification -- usable for AccessCheck, useless for CreateProcessWithTokenW. Each Potato variant either chooses a coercion primitive that arrives at SecurityImpersonation or upgrades the token via a subsequent DuplicateTokenEx.
3.2 The substitution primitives
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.
SetThreadToken-- attach an impersonation token to a thread [11]. The thread now runs under the borrowed identity for every subsequent access check.ImpersonateLoggedOnUser-- the thread-level convenience wrapper [12]. Same effect asSetThreadToken, with simpler arguments.DuplicateTokenEx-- create a new token from an existing one, with adjustable type (primary vs impersonation) and level (the four-value enum above) [13]. The Potato lineage uses this to convert an impersonation token into a primary one before launching a process.CreateProcessWithTokenW-- spawn a new process under an arbitrary primary token [14]. The Microsoft Learn documentation is explicit about the gate: "The process that calls CreateProcessWithTokenW must have theSE_IMPERSONATE_NAMEprivilege."
That last sentence is the keystone. SeImpersonatePrivilege is not just "the right to impersonate." 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's hat; with it, the attacker has cmd.exe running as SYSTEM until the system reboots.
3.3 The coercion primitive
The three substitution primitives are inert without a token to substitute. The dominant token source on Windows is the named-pipe server primitive ImpersonateNamedPipeClient, shipped since Windows XP / Server 2003 [15]. Any process that owns a named pipe can call this API after a client connects; the impersonating thread then wears the caller's token at whatever impersonation level the caller's SQOS negotiated.
A Win32 API that copies the connected client's access token onto the calling thread, after which the thread acts under the client's identity until RevertToSelf is called. The API has shipped since Windows XP / Server 2003 [15]. 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.
This is the four-step chain every Potato operator runs, as enumerated in Forshaw's 2021 Project Zero retrospective on the lineage [16]:
CreateNamedPipe("\\.\pipe\<attacker_name>")-- a service-account process opens a pipe it controls.- Induce some privileged Windows component to authenticate to that pipe.
ImpersonateNamedPipeClient-- the impersonating thread now wears the caller's token.DuplicateTokenExto primary;CreateProcessWithTokenW(cmd.exe).
Diagram source
sequenceDiagram
participant Atk as Attacker, service account
participant Pipe as Named pipe attacker controls
participant Sys as Privileged caller, SYSTEM-context
Atk->>Pipe: CreateNamedPipe and listen
Atk->>Sys: Trigger coercion primitive
Sys->>Pipe: Authenticate to the pipe
Atk->>Pipe: ImpersonateNamedPipeClient
Atk->>Atk: DuplicateTokenEx, impersonation to primary
Atk->>Atk: CreateProcessWithTokenW cmd.exe
Note over Atk: cmd.exe now running as SYSTEM 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.
// Pseudocode showing the four-step Potato chain.
// Privilege checks shown as comments where the kernel enforces them.
function impersonationChain(coercionTrigger) {
const pipe = createNamedPipe("\\.\pipe\demo"); // no privilege required
coercionTrigger(pipe); // induce SYSTEM to connect
pipe.waitForConnect();
// kernel allows SecurityImpersonation only if caller has SeImpersonatePrivilege:
const callerToken = pipe.impersonateNamedPipeClient();
const primary = duplicateTokenEx(callerToken, "primary",
"SecurityImpersonation"); // no privilege required
// kernel gate: requires SE_IMPERSONATE_NAME on the calling process:
return createProcessWithTokenW(primary, "cmd.exe");
} 3.4 The privilege next to it
CreateProcessWithTokenW is gated on SeImpersonatePrivilege. Its sibling CreateProcessAsUser is gated on a different pair of privileges -- SeAssignPrimaryTokenPrivilege (constant name SE_ASSIGNPRIMARYTOKEN_NAME) when the supplied token is not assignable by the caller, plus SeIncreaseQuotaPrivilege (SE_INCREASE_QUOTA_NAME) in all cases. Both are enumerated separately in the privilege-constants table [2]. On a NETWORK SERVICE or LOCAL SERVICE token, SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME are both present but disabled [@ms-learn-localservice; @ms-learn-networkservice]: a service-account process must call AdjustTokenPrivileges to enable them before CreateProcessAsUser will succeed, whereas SeImpersonatePrivilege is shipped enabled and CreateProcessWithTokenW works on the first instruction. Pierini'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 SeImpersonatePrivilege is enabled, and the rest of this article treats it as the privilege that matters in practice.
| API | Privilege required | Input | Output |
|---|---|---|---|
ImpersonateNamedPipeClient | none for SecurityIdentification or SecurityAnonymous; for higher levels, either SeImpersonatePrivilege, or the token was created with explicit credentials via LogonUser/LsaLogonUser from within the caller's logon session, or the authenticated identity is the same as the caller (see [15]) | connected pipe handle | impersonation token on thread |
ImpersonateLoggedOnUser | none (caller must already hold the token) | token handle | impersonation token on thread |
SetThreadToken | depends on token level | token handle | impersonation token on thread |
DuplicateTokenEx | none | source token | new token, type/level adjustable |
CreateProcessWithTokenW | SeImpersonatePrivilege | primary token + command line | new process |
CreateProcessAsUser | SeAssignPrimaryTokenPrivilege | primary token + command line | new process |
Diagram source
flowchart LR
Process["Process, holds primary token"]
Thread["Thread, optional impersonation token"]
NewProc["New process, spawned with chosen primary token"]
Process -- "OpenProcessToken, read" --> TH["Token handle"]
TH -- "SetThreadToken or ImpersonateLoggedOnUser" --> Thread
Thread -- "GetThreadToken" --> TH
TH -- "DuplicateTokenEx, impersonation to primary" --> PT["Primary token handle"]
PT -- "CreateProcessWithTokenW, gated on SeImpersonatePrivilege" --> NewProc
Pipe["Connected named pipe"] -- "ImpersonateNamedPipeClient, gated on SeImpersonatePrivilege beyond SecurityIdentification" --> Thread 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.
4. Five Generations of Token Sources, One Constant Privilege
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 -- where do the tokens come from? -- differently, and Microsoft patched each token source one at a time.
This section is generation-level. The variant-by-variant chronology of every named Potato lives in the sibling Potato Family article (2026-05-31); here, variants appear only as evidence for claims about the primitive.
4.1 Generation 1, direct token theft (2008-2010)
Cerrudo's HITB Dubai 2008 paper, Token Kidnapping, named the privilege and named the technique [5]. 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); DuplicateTokenEx that token; CreateProcessWithTokenW to spawn cmd.exe under the new identity. Two years later, at DEF CON 18, Cerrudo presented Token Kidnapping's Revenge with fresh examples and a community-canonical title for the technique [17].
Microsoft's response was MS09-012 in April 2009 (community-known as the Chimichurri fix, after Cesar Cerrudo'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:
"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 [1]
The MSRC text continues: "the first update addresses service isolation, while the second addresses processes running as service accounts" [1]. Service isolation, not the privilege itself. The bulletin closed the specific handle-leak surface Cerrudo had used -- it did not revoke SeImpersonatePrivilege from NETWORK SERVICE, did not modify CreateProcessWithTokenW, did not modify ImpersonateNamedPipeClient. The MSRC acknowledged on the record that the privilege was sufficient for the escalation and elected to fix the symptom (the leak surface), not the gate.
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.
Chimichurri (sometimesChimichurri.exe) 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 argeniss.com/research/Chimichurri_CesarCerrudo.zip and preserved in the Internet Archive [18]. Microsoft's own naming for the bulletin is simply MS09-012 / KB959454. Offensive-research convention has used "Chimichurri" as shorthand for the Cerrudo PoC ever since -- never for a Microsoft internal codename. Forshaw's January 2020 service-hardening retrospective references the same Cerrudo / Argeniss lineage [19].
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.
4.2 Generation 2, local NTLM cross-protocol reflection (2014-2016)
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's HotPotato (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 [6]. Breen credits the genealogy openly: "If this sounds vaguely familiar, it'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" [6].
The conceptual leap is the one every subsequent generation depends on. Cerrudo's G1 had to find a high-privileged token leaked into the local process tree; Breen's G2 makes the system hand you one 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 [16].
Microsoft'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 SeImpersonatePrivilege or ImpersonateNamedPipeClient.
4.3 Generation 3, local DCOM activation (2016-2018)
Within months of HotPotato, the community converged on a more reliable coercion primitive: a forged DCOM OBJREF 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 [20], but as his 2021 retrospective notes:
"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." [16]
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 "Rotten" and "Juicy" 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's pipe when it tries to resolve the OXID.
RottenPotato (September 26, 2016) demonstrated the chain [21]; JuicyPotato (July 2018) industrialised it with a configurable CLSID table and reliable pipe handling. The canonical mirror for the JuicyPotato repository is the ohpe/juicy-potato GitHub project [22]. Crucially, the load-bearing API was still ImpersonateNamedPipeClient -- the DCOM trick is just the vehicle that delivers a SYSTEM-context authentication to the attacker's pipe.
4.4 Generation 4, coercion APIs beyond DCOM (2020-2024)
Clement Labro (itm4n) shipped PrintSpoofer on April 28, 2020 [@labro-2020-printspoofer-post; @itm4n-printspoofer-repo]. The coercion primitive was MS-RPRN's RpcRemoteFindFirstPrinterChangeNotificationEx -- an RPC method on the Print Spooler that takes an attacker-supplied UNC-like notification target and authenticates to it under the Spooler's SYSTEM identity. PrintSpoofer needed neither DCOM nor any leaked handle; the coercion primitive lived inside a always-running Windows service.
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 bugch3ck/SharpEfsPotato [23], not the ly4k mirror. MS-FSRVP, MS-DFSNM, and a long tail followed. CoercedPotato's --interface {ms-rprn, ms-efsr} switch operationalises the enumeration in a single tool [24]; the project's MS-EFSR catalogue alone lists fourteen entry points (indices 0-13, with two marked NOT WORKING).
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 PrintNightmare cluster around MS-RPRN, anchored by CVE-2021-34527 [25]; targeted MS-EFSR fixes), but no commitment to enumerate or class-close the surface.
4.5 Generation 5, into RPCSS itself (2022-2024)
In December 2022, the researcher who goes by BeichenDream published GodPotato, with a README that names the structural defect plainly:
"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
ImpersonatePrivilegepermission. Then you areNT AUTHORITY\SYSTEM. . . There are some defects in rpcss when dealing with oxid, and rpcss is a service that must be opened by the system." [26]
GodPotato survives every phase of CVE-2021-26414 (the three-phase DCOM hardening, rolled out 2021-06-08, 2022-06-14, 2023-03-14) [27] because the defect is in RPCSS's OXID handling, not in DCOM activation. The other structural half of the defect is documented by Forshaw in April 2020: "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's Token, not the caller's Token" [28]. Together those two structural properties keep GodPotato functional across the README'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 [26].
LocalPotato (February 2023) is the parallel branch: Antonio Cocomazzi and Andrea Pierini discovered that the NTLM Type-2 "Reserved" field could be used to swap context handles during local authentication, escalating from an unprivileged user -- the first variant in the lineage that does not require SeImpersonatePrivilege to start [29]. Microsoft fixed it as CVE-2023-21746 [30], but the conceptual proof remains: the local NTLM stack itself is an attacker-controllable token source.
SilverPotato (April 24, 2024) extended the family across hosts [31]. Members of the Distributed COM Users or Performance Log Users groups trigger remote activation of the sppui DCOM application (CLSID {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83}) on a target server. The coerced Domain Admin authentication is then chained through SMB relay to the ADCS host, SAM dump, Pass-the-Hash, 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 [32]; the original researcher's credit was subsequently removed after a second-reporter overlap and an MSRC severity re-grading from moderate to important [31]. 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.
FakePotato (CVE-2024-38100, July 2024 KB5040434) closed the ShellWindows DCOM activation path that Pierini disclosed; the patch shipped about a month before the public disclosure [@nvd-cve-2024-38100; @pierini-2024-fakepotato-post].
Diagram source
flowchart TD
G1["G1, 2008-2010, Cerrudo Token Kidnapping, leaked impersonation handles"]
G2["G2, 2014-2016, HotPotato, local NTLM WPAD reflection"]
G3["G3, 2016-2018, RottenPotato, JuicyPotato, DCOM OXID activation"]
G4["G4, 2020-2024, PrintSpoofer, CoercedPotato, non-DCOM RPC coercion"]
G5["G5, 2022-2024, GodPotato, LocalPotato, SilverPotato, RPCSS OXID and NTLM-loopback defects"]
Constant["SeImpersonatePrivilege plus ImpersonateNamedPipeClient, unchanged 2003 through 2026"]
G1 -- "MS09-012, Cerrudo Chimichurri PoC" --> G2
G2 -- "MS16-075 plus WPAD hardening" --> G3
G3 -- "Win10 1809 OXID hardening, then CVE-2021-26414 three phases" --> G4
G4 -- "Per-CVE coercion-API patches, PrintNightmare cluster" --> G5
G5 -- "GodPotato unpatched, SilverPotato patched CVE-2024-38061, LocalPotato patched CVE-2023-21746, FakePotato patched CVE-2024-38100" --> Open["Mid-2026 state, still functional via GodPotato and the coercion-API long tail"]
G1 --- Constant
G2 --- Constant
G3 --- Constant
G4 --- Constant
G5 --- Constant | Generation | Years | Token source | Microsoft response | Still works in 2026? |
|---|---|---|---|---|
| G1 Direct Token Theft (Cerrudo) | 2008-2010 | Leaked impersonation handles | MS09-012 (Cerrudo Chimichurri PoC) | No (handle leaks closed) |
| G2 Local NTLM Reflection (HotPotato) | 2014-2016 | WPAD + HTTP-to-SMB reflection | MS16-075 + WPAD hardening | No (chain too fragile) |
| G3 DCOM Activation (Rotten/Juicy) | 2016-2018 | Coerced DCOM auth to attacker pipe | Win10 1809 OXID + CVE-2021-26414 | Partial (some LTSC pins) |
| G4 Non-DCOM RPC Coercion (PrintSpoofer/Coerced) | 2020-2024 | MS-RPRN / MS-EFSR / MS-FSRVP coercion | Per-CVE patches | Yes (long tail) |
| G5 RPCSS OXID + NTLM-Loopback (GodPotato/Local/Silver) | 2022-2024 | RPCSS handling defect + cross-host NTLM relay | None for GodPotato; CVE-2023-21746 for LocalPotato; CVE-2024-38061 for SilverPotato (July 2024) | Yes (GodPotato unaddressed) |
Microsoft'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'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.
Eighteen years. Five generations. One privilege. The variable is the token source; the constant is the gate.
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's choice not to close the family at its root. What if those three components, taken together, form a closed system?
5. The Three-Piece Theorem
The Potato lineage is not a collection of bugs. It is the consequence of a single architectural identity:
SeImpersonatePrivilege+ImpersonateNamedPipeClient+ the MSRC servicing-criteria carve-out = service-account-to-SYSTEM.
Each summand is individually documented. Each is individually shipped by Microsoft. Each is individually justified by a real engineering or product requirement. 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.
This is the article'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.
Component 1: the privilege
SeImpersonatePrivilege is enumerated in the privilege-constants table as SE_IMPERSONATE_NAME [2] and is the subject of a dedicated security-policy page that lists default assignments [3]. The LOCAL SERVICE and NETWORK SERVICE account documentation each enumerate it as (enabled) in the default privilege set [@ms-learn-localservice; @ms-learn-networkservice].
Cost of removal: every shipping RPC server that impersonates clients breaks; §7.1 walks through the production-Windows surface this affects in detail.
Component 2: the coercion API
ImpersonateNamedPipeClient has shipped since Windows XP / Server 2003 [15]. 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 (RpcImpersonateClient, the LSA-side variants) ultimately compose into the same kernel-side token-substitution call.
Cost of removal: 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.
Component 3: the carve-out
Microsoft'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: "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?" If either answer is no, "the vulnerability will be considered for the next version or release of Windows but will not be addressed through a security update or guidance" [34].
The MSRC Windows Security Servicing Criteria document [34] 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 [35]. §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 documented and Microsoft-position-as-stated, not inferred from per-CVE behaviour.
Cost of removal: 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 [34].
"if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM" -- Andrea Pierini; "a deliberately provocative shortcut obviously, but it's not far from the truth" -- Clement Labro's gloss on the same line [4]
Diagram source
flowchart TB
Priv["SeImpersonatePrivilege, default-assigned to LOCAL SERVICE and NETWORK SERVICE. Removing this breaks every service that impersonates clients."]
API["ImpersonateNamedPipeClient, shipped since XP/Server 2003. Removing this breaks every named-pipe RPC server."]
Doctrine["MSRC servicing criteria: WSH is a safety boundary, not a security boundary. Changing this commits Microsoft to a structural-close servicing cadence."]
Center["Service-account to SYSTEM"]
Priv --> Center
API --> Center
Doctrine --> Center SeImpersonatePrivilege at all. Section 6.6 returns to this retraction in full.
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.
6. Five Mitigations and the Surface None of Them Closes
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.
6.1 Service SID isolation (Vista, 2007)
Vista shipped per-service SIDs of the form NT SERVICE\<name> -- a SID generated on the fly from the service's name and attached to the service-process token. Forshaw's The Art of Becoming TrustedInstaller is the canonical reference for the derivation: "The SID itself is generated on the fly as the SHA1 hash of the uppercase version of the service name" [33]. Service SIDs are also documented as part of the SCM service-security model [36].
A SID of the form NT SERVICE\<service-name> 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.
Closes: lateral movement between services sharing an account. A NETWORK SERVICE process for service A cannot, by Service SID alone, open files ACL'd to NETWORK SERVICE for service B.
Does NOT close: vertical movement to SYSTEM via NETWORK SERVICE. Forshaw's April 2020 Sharing a Logon Session a Little Too Much 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 session's token, not the caller's token, which is exactly the structural property GodPotato weaponises [28].
6.2 Restricted and write-restricted service tokens (Vista 2007, backport via MS09-012)
SERVICE_SID_TYPE_RESTRICTED and WRITE_RESTRICTED 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's January 2020 empirical assessment is the canonical study of what these settings actually accomplish: "In the past few years there's been numerous exploits for service to system privilege escalation. Primarily they revolve around the fact that system services typically have impersonation privilege" [19].
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.
Closes: the compromised service's ability to write to (or read, depending on configuration) arbitrary objects outside its restricting-SID set.
Does NOT close: SeImpersonatePrivilege is not revoked. A restricted token can still call ImpersonateNamedPipeClient and CreateProcessWithTokenW. The privilege gate is orthogonal to the restricting-SID gate.
6.3 LPAC (Less-Privileged AppContainer) for select services (Windows 10+)
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 AppContainer and LowBox Tokens article (2026-05-12) covers the model in depth.
Closes: the attack surface of a few specific Microsoft-shipped contained services.
Does NOT close: the LOCAL SERVICE and NETWORK SERVICE population this article is about is not LPAC-contained by default. Declaring an LPAC service requires rewriting the service to operate inside an AppContainer, which most product teams do not undertake.
6.4 group Managed Service Accounts (gMSA, Server 2012+)
gMSA is Microsoft'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 [37].
Closes: 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.
Does NOT close: anything to do with SeImpersonatePrivilege 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).
6.5 CVE-2021-26414 three-phase DCOM hardening
CVE-2021-26414 raised the minimum DCOM client authentication level to RPC_C_AUTHN_LEVEL_PKT_INTEGRITY. 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 [27].
Closes: 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.
Does NOT close: anything that does not depend on DCOM activation. GodPotato (RPCSS OXID handling, not DCOM activation) remains functional [26]; PrintSpoofer / CoercedPotato (non-DCOM RPC coercion) remain functional [@labro-2020-printspoofer-post; @prepouce-coercedpotato-repo]; JuicyPotatoNG found a same-quarter bypass on the DCOM side via the PrintNotify CLSID {854A20FB-2D44-457D-992F-EF13785D2B51} [38]; SilverPotato 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.
6.6 The mitigation that does not exist: "RBAC for services"
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 "RBAC for services" 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 SeImpersonatePrivilege at all. The §5 Sidenote on the Stage 0a focus-premise retraction covers the audit-trail framing; this subsection states the reader-facing point.
Diagram source
flowchart TB
M1["Service SID Isolation, Vista 2007"]
M2["Restricted and Write-Restricted Tokens, Vista 2007 plus MS09-012 backport"]
M3["LPAC for select services, Windows 10 plus"]
M4["gMSA, Server 2012 plus"]
M5["CVE-2021-26414 three-phase DCOM hardening, 2021-2023"]
Surface1["Closes lateral movement between same-account services"]
Surface2["Closes write access outside restricting-SID set"]
Surface3["Closes blast radius of select Microsoft-shipped services"]
Surface4["Closes domain-credential exposure"]
Surface5["Closes DCOM activation chain, Rotten and Juicy"]
Core["Service-account-to-SYSTEM, primitive remains open"]
M1 --> Surface1
M2 --> Surface2
M3 --> Surface3
M4 --> Surface4
M5 --> Surface5
Surface1 -. "does not reach" .-> Core
Surface2 -. "does not reach" .-> Core
Surface3 -. "does not reach" .-> Core
Surface4 -. "does not reach" .-> Core
Surface5 -. "does not reach" .-> Core | Mitigation | What it closes | What it does NOT close | Primary |
|---|---|---|---|
| Service SID Isolation (Vista 2007) | Lateral movement between services sharing an account | Vertical SYSTEM via NETWORK SERVICE LSASS-cached-token defect | [@forshaw-2017-08-trustedinstaller; @forshaw-2020-04-sharing-logon-session] |
| Restricted / Write-Restricted Tokens | Write access to non-restricting-SID objects | SeImpersonatePrivilege still present; CreateProcessWithTokenW still works | [19] |
| LPAC (Windows 10+) | Select-services blast radius | NETWORK / LOCAL SERVICE population not LPAC-contained by default | sibling AppContainer article |
| gMSA (Server 2012+) | Domain-credential exposure | Local SeImpersonate; SilverPotato-class cross-host relay | [37] |
| CVE-2021-26414 phase 3 (2023-03-14) | DCOM activation chain (Rotten/Juicy) | GodPotato (RPCSS), PrintSpoofer (non-DCOM), JuicyPotatoNG (same-quarter bypass) | [27] |
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?
7. The MSRC Servicing-Criteria Carve-Out
"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 [35]
This is the Microsoft-position-as-stated-to-researchers anchor for the entire article. The MSRC Windows Security Servicing Criteria page [34] is the policy-document anchor with the same content: the two-question test "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?" If either answer is no, the vulnerability is considered for the next version of Windows but is not addressed through a security update.
Service-to-SYSTEM escalation across the Windows Service Hardening boundary is not a violation of a security boundary. It is a violation of a safety boundary. 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].
Why? Walk through each of the three closure paths Microsoft could in principle take, and the cost of each.
7.1 Revoke SeImpersonatePrivilege from NETWORK SERVICE and LOCAL SERVICE
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 CreateProcessWithTokenW fails immediately.
Cost. Every RPC server, web server, database server, and Office service that needs to act on a client's behalf breaks. The privilege exists because 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'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.
7.2 Declare local DCOM activation a security boundary and service it
This was the partial path Microsoft did take with CVE-2021-26414 [27]: tighten the DCOM activation surface and ship the change in three phases over twenty-one months. But declaring all 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.
Cost. MSRC has declined to take on that workload. The on-the-record case is RemotePotato0 [39], which was classified "Won't Fix" by MSRC as the first explicit declination in the lineage -- documented in Forshaw's 2021 retrospective as still unpatched at the time of writing [16]. 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.
7.3 Deprecate ImpersonateNamedPipeClient
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.
Cost. 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.
Diagram source
flowchart LR
Start["Closure path"]
A["A. Revoke SeImpersonatePrivilege from NETWORK SERVICE and LOCAL SERVICE"]
B["B. Declare local DCOM activation a security boundary, service every CVE"]
C["C. Deprecate ImpersonateNamedPipeClient"]
Cost1["Breaks IIS, Exchange, MSSQL, Office services"]
Cost2["Per-CVE servicing pipeline for every cross-session COM activation, MSRC has declined"]
Cost3["Breaks SMB redirector, Print Spooler, EFS, every named-pipe RPC server that impersonates"]
Converge["Compatibility cost Microsoft has not accepted"]
Start --> A
Start --> B
Start --> C
A --> Cost1 --> Converge
B --> Cost2 --> Converge
C --> Cost3 --> Converge 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.
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.
8. The Hardy Ceiling
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 [7].
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 [7]. Lampson's 1971 access-matrix paper is the formal substrate the argument depends on [8].
Windows is not a capability system. It is an identity-and-ACL system, as Cutler's NT 3.1 team chose in 1993 [9]. As long as that remains true, some version of "service-account to higher-privileged identity" is reachable, and the only question is which specific token-source primitive is currently in play. Microsoft's eighteen-year per-CVE response cadence is consistent with that ceiling. Each individual token source is fixable; the class is not.
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 Adminless / Administrator Protection feature (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.
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.
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?
9. Open Problems
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.
9.1 The coercion-API treadmill
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's MS-EFSR catalogue alone lists fourteen entry points (two marked NOT WORKING) [24], 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.
9.2 GodPotato's RPCSS OXID path
Three years after the three-phase CVE-2021-26414 DCOM hardening completed [27], GodPotato remains functional across the README's tested Windows matrix (Server 2012-2022 / Windows 8-11) [26]. 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 [28] the right place -- remains open. Microsoft has assigned no CVE.
9.3 Credential Guard does not stop this
Credential Guard protects the NTLM hash and Kerberos TGT in the LSASS Isolated User Mode trustlet. It does not protect against runtime impersonation of an already-issued token. The boundary between credential-theft mitigations and impersonation mitigations is frequently confused.
Credential Guard'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 fromImpersonateNamedPipeClient is not a credential and is not held in LSASS-isolated memory; Credential Guard cannot see it.
9.4 The "service boundary" re-definition Microsoft has quietly avoided
Adminless / Administrator Protection -- the 2024-2025 feature that re-frames local admin identity as a per-action consent surface [40] (covered in the sibling Adminless article 2026-05-10) -- explicitly excludes services from its new boundary.
The Adminless documentation scopes the feature to interactive administrator accounts on a device [40]; 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 not on the public roadmap.9.5 Generation-6 candidates
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:
- Kerberos-only loopback coercion. 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.
- Virtual-account / gMSA token-state defects. Forshaw's April 2020 analysis [28] 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.
- Cross-host extensions beyond ADCS. SilverPotato's coerce-and-relay chain into ADCS infrastructure [31] -- patched as CVE-2024-38061 in July 2024 [32] but exemplifying an open class -- is the strongest current exemplar for the "Generation 6" 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.
If the lineage is not closing, what should a defender actually do today?
10. Defending, Detecting, and (Carefully) Removing the Privilege
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?
10.1 Auditing which accounts hold SeImpersonatePrivilege
The first defensive action is enumeration -- not removal. Concrete commands, in increasing order of detail:
whoami /priv-- per-process self-check from any shell. Reports the token's privileges in the form the article opens with.secedit /export /cfg secpol.cfg-- full local-policy export. Grep the output forSeImpersonatePrivilegeto see every SID the local policy grants it to.accesschk.exe -a SeImpersonatePrivilege-- the Sysinternals AccessChk tool [41] enumerates the effective holders directly from the LSA policy database.Get-NtTokenPrivilegesfrom James Forshaw's NtObjectManager PowerShell module [42] -- the same data, scriptable, with the broader NtObjectManager surface available for follow-up (named-pipe enumeration, token-handle leak search, kernel-object introspection).Invoke-PrivescCheckfrom Clement Labro's PrivescCheck module [43] -- the canonical local-privesc check-list. The output includesSeImpersonatePrivilegepresence as one of approximately forty enumerated checks.
| Tool | Author | What it reports |
|---|---|---|
| AccessChk (Sysinternals) | Mark Russinovich | Effective permissions, account-privilege enumeration via -a [41] |
| NtObjectManager | James Forshaw | Get-NtTokenPrivileges, named-pipe enumeration, token-handle leak search [42] |
| PrivescCheck | Clement Labro | Canonical local-privesc check-list incl. SeImpersonatePrivilege presence [43] |
// Logic of: secedit /export /cfg secpol.cfg ; grep SeImpersonate
const secpol = readPolicyExport(); // produced by secedit
const holders = secpol['SeImpersonatePrivilege'] || [];
console.log('SIDs holding SeImpersonatePrivilege:');
for (const sid of holders) {
console.log(' ' + sid);
}
// 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) Press Run to execute.
10.2 Removing the privilege where you can
The policy path is documented: Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment -> Impersonate a client after authentication [3]. The temptation, especially after reading an article like this one, is to remove SeImpersonatePrivilege from NETWORK SERVICE wholesale.
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: audit first, understand the dependency surface, then narrow the assignment to the specific service accounts that need it 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.
Concrete Group Policy click-through to AUDIT (not remove) the privilege
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 -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment -> 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.
10.3 Detection signatures
Detection in this space breaks into two abstractions: primitive-level rules that match the named-pipe pattern every Potato variant generates, and named-tool rules that match a specific binary's fingerprint.
The primitive-level open-source reference is the Elastic detection rule Privilege Escalation via Rogue Named Pipe [44] (as of June 2026; the cited URL pins to the master HEAD), rule_id 76ddb638-abf7-42d5-be22-4a70b0bf7241. The EQL queries Sysmon Event ID 17 (pipe-creation events) and matches paths in which a \pipe\ 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.
The named-tool reference is the SigmaHQ LocalPotato rule [45] (as of June 2026; the cited URL pins to the master HEAD), rule id 6bd75993-9888-4f91-9404-e1e4e4e34b77. Three OR-joined selectors: image path ending in \LocalPotato.exe; CLI fingerprint -i C:\ paired with -o Windows\; specific IMPHASH selectors E1742EE971D6549E8D4D81115F88F1FC and DD82066EFBA94D7556EF582F247C8BB5. Useful as a low-noise IOC tripwire; trivially evaded by binary rename or recompilation.
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.
11. FAQ -- Eight Misconceptions That Will Not Die
Frequently asked questions
Doesn't UAC stop this?
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.
Doesn't Credential Guard stop this?
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.
Doesn't running the service as a low-privileged account stop this?
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 "hardened" 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.
Aren't the Potato attacks all patched?
No. Microsoft has shipped CVEs for specific token-source primitives -- LocalPotato as CVE-2023-21746 [30], SilverPotato as CVE-2024-38061 [32], FakePotato as CVE-2024-38100 [46], the three-phase DCOM hardening as CVE-2021-26414 [27] -- 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 [26]. 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.
Is this a Windows problem or a service-developer problem?
Both, but the architectural responsibility is Windows'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'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.
Does revoking SeImpersonatePrivilege break IIS, Exchange, and SQL Server?
Yes. IIS application pools cannot perform Windows-authenticated user impersonation; Exchange cannot run mailbox operations under the connecting user'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 [3]. Audit before you remove.
Is Adminless / Administrator Protection a fix for this?
No. The Adminless / Administrator Protection feature is a per-action consent surface for interactive administrators [40]. 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.
Why does Microsoft not just deprecate ImpersonateNamedPipeClient?
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 [34] is the policy-level acknowledgement that the cost is not on the table.
12. The Line, Re-read
Bring the reader back to where this started: one line in whoami /priv.
SeImpersonatePrivilege Impersonate a client after authentication Enabled
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 CreateProcessWithTokenW. 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 safety boundary, not a security boundary [35]. The 1988 ceiling that explains why is older than the operating system.
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 [1]. They could not change it without breaking the service model: every closure path carries a documented compatibility cost they have explicitly declined to accept [34]. Pierini and Cocomazzi made the doctrine quotable at Troopers 24 [35]: WSH is a safety boundary, not a security boundary. Roughly eighteen years after Cerrudo first put that fact on the record [5], ten years after HotPotato made it pushbutton [6], 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.
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's CLSID, coercion primitive, and patch state. This one was about why the family exists at all.
The one line in whoami /priv is not a bug. It is the decision.
Study guide
Key terms
- SeImpersonatePrivilege
- 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.
- ImpersonateNamedPipeClient
- Win32 API by which a named-pipe-server thread receives the connected client's access token; shipped since Windows XP / Server 2003; the dominant token-source primitive on the platform.
- Confused Deputy
- Norm Hardy'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.
- Primary Token vs Impersonation Token
- 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's access checks.
- Impersonation Level
- 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.
- OXID Resolver
- 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.
- Windows Service Hardening (WSH)
- Microsoft'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.
- Service SID
- A SID of the form NT SERVICE\\<service-name>, 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.
- Restricted Token
- 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's write surface.
- MSRC Servicing Criteria
- Microsoft'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.
Comprehension questions
Why does NETWORK SERVICE hold SeImpersonatePrivilege by default?
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.
What three components combine into the three-piece theorem of section 5?
(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.
Why did MS09-012 not close the Potato family?
Because MS09-012 (the bulletin behind Cerrudo's *Chimichurri* PoC) closed the specific handle-leak surface Cerrudo'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.
What is the difference between primitive-level and named-tool detection, and why does it matter?
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'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.
If GodPotato is patchable in principle, why has Microsoft not patched it?
Because patching GodPotato requires changing either RPCSS'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.
References
- (2009). Token Kidnapping (MSRC blog, April 14, 2009). https://www.microsoft.com/en-us/msrc/blog/2009/04/token-kidnapping/ ↩
- Privilege Constants (Win32 SecAuthZ). https://learn.microsoft.com/en-us/windows/win32/secauthz/privilege-constants ↩
- Impersonate a client after authentication - Windows security policy setting. https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/impersonate-a-client-after-authentication ↩
- LocalService Account. https://learn.microsoft.com/en-us/windows/win32/services/localservice-account ↩
- NetworkService Account. https://learn.microsoft.com/en-us/windows/win32/services/networkservice-account ↩
- (2020). PrintSpoofer: Abusing Impersonate Privileges. https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/ ↩
- (2008). Token Kidnapping. https://dl.packetstormsecurity.net/papers/presentations/TokenKidnapping.pdf - HITB Dubai 2008 disclosure of service-account-to-SYSTEM via SeImpersonatePrivilege + leaked handles. ↩
- (2016). Hot Potato. https://www.foxglovesecurity.com/2016/01/16/hot-potato/ ↩
- (1988). The Confused Deputy (or why capabilities might have been invented). http://cap-lore.com/CapTheory/ConfusedDeputy.html - Tymshare FORTRAN compiler / (SYSX)BILL anecdote; structural argument for capabilities. ↩
- (1971). Protection. http://bwlampson.site/08-Protection/WebPage.html - Access-matrix model; the formal substrate Windows tokens instantiate. ↩
- (2017). Windows Internals, Part 1 (7th edition). https://learn.microsoft.com/en-us/sysinternals/resources/windows-internals ↩
- Timeline of computer viruses and worms. https://en.wikipedia.org/wiki/Timeline_of_computer_viruses_and_worms ↩
- ImpersonateLoggedOnUser function (securitybaseapi.h). https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-impersonateloggedonuser ↩
- SetThreadToken function (processthreadsapi.h). https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadtoken ↩
- DuplicateTokenEx function (securitybaseapi.h). https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex ↩
- CreateProcessWithTokenW function (winbase.h). https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw ↩
- ImpersonateNamedPipeClient function (namedpipeapi.h). https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient ↩
- (2021). Windows Exploitation Tricks: Relaying DCOM Authentication. https://googleprojectzero.blogspot.com/2021/10/windows-exploitation-tricks-relaying.html ↩
- (2010). Token Kidnapping's Revenge. https://defcon.org/images/defcon-18/dc-18-presentations/Cerrudo/DEFCON-18-Cerrudo-Token-Kidnapping-Revenge.pdf ↩
- (2009). Chimichurri.zip (Argeniss PoC for MS09-012; Wayback Machine snapshot). https://web.archive.org/web/20120108215145/http://www.argeniss.com/research/Chimichurri.zip ↩
- (2020). Empirically Assessing Windows Service Hardening. https://www.tiraniddo.dev/2020/01/empirically-assessing-windows-service.html ↩
- CVE-2015-2370 (DCOM activation; Forshaw Issue 325). https://nvd.nist.gov/vuln/detail/CVE-2015-2370 ↩
- (2016). Rotten Potato -- Privilege Escalation from Service Accounts to SYSTEM. https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/ ↩
- JuicyPotato (canonical mirror). https://github.com/ohpe/juicy-potato ↩
- PrintSpoofer (reference implementation). https://github.com/itm4n/PrintSpoofer ↩
- SharpEfsPotato (bugch3ck fork). https://github.com/bugch3ck/SharpEfsPotato ↩
- CoercedPotato. https://github.com/Prepouce/CoercedPotato ↩
- CVE-2021-34527 (PrintNightmare; Print Spooler RCE). https://nvd.nist.gov/vuln/detail/CVE-2021-34527 ↩
- (2022). GodPotato. https://github.com/BeichenDream/GodPotato ↩
- CVE-2021-26414 (DCOM three-phase hardening). https://nvd.nist.gov/vuln/detail/CVE-2021-26414 ↩
- (2020). Sharing a Logon Session a Little Too Much. https://www.tiraniddo.dev/2020/04/sharing-logon-session-little-too-much.html ↩
- (2023). LocalPotato: When Swapping the Context Leads You to SYSTEM. https://decoder.cloud/2023/02/13/localpotato-when-swapping-the-context-leads-you-to-system/ ↩
- CVE-2023-21746 (LocalPotato fix). https://nvd.nist.gov/vuln/detail/CVE-2023-21746 ↩
- (2024). Hello, I'm your Domain Admin and I want to authenticate against you (SilverPotato). https://decoder.cloud/2024/04/24/hello-im-your-domain-admin-and-i-want-to-authenticate-against-you/ ↩
- CVE-2024-38061 (SilverPotato / DCOM permissions, July 2024 Patch Tuesday). https://nvd.nist.gov/vuln/detail/CVE-2024-38061 ↩
- CVE-2024-38100 (FakePotato / ShellWindows AppID activation). https://nvd.nist.gov/vuln/detail/CVE-2024-38100 ↩
- (2024). The Fake Potato. https://decoder.cloud/2024/08/02/the-fake-potato/ ↩
- (2017). The Art of Becoming TrustedInstaller. https://www.tiraniddo.dev/2017/08/the-art-of-becoming-trustedinstaller.html ↩
- Microsoft Windows Security Servicing Criteria. https://www.microsoft.com/en-us/msrc/windows-security-servicing-criteria ↩
- (2024). 10 Years of Windows Privilege Escalation with Potatoes. https://www.troopers.de/troopers24/talks/cyzbj3/ ↩
- Service Security and Access Rights. https://learn.microsoft.com/en-us/windows/win32/services/service-security-and-access-rights ↩
- Group Managed Service Accounts Overview. https://learn.microsoft.com/en-us/windows-server/security/group-managed-service-accounts/group-managed-service-accounts-overview ↩
- JuicyPotatoNG. https://github.com/antonioCoco/JuicyPotatoNG ↩
- RemotePotato0. https://github.com/antonioCoco/RemotePotato0 ↩
- Administrator protection (Windows Security). https://learn.microsoft.com/en-us/windows/security/application-security/application-control/administrator-protection/ ↩
- AccessChk - Sysinternals. https://learn.microsoft.com/en-us/sysinternals/downloads/accesschk ↩
- NtObjectManager (sandbox-attacksurface-analysis-tools). https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools ↩
- PrivescCheck. https://github.com/itm4n/PrivescCheck ↩
- Elastic detection rule: Privilege Escalation via Rogue Named Pipe. https://raw.githubusercontent.com/elastic/detection-rules/main/rules/windows/privilege_escalation_via_rogue_named_pipe.toml ↩
- SigmaHQ LocalPotato detection rule. https://raw.githubusercontent.com/SigmaHQ/sigma/master/rules/windows/process_creation/proc_creation_win_hktl_localpotato.yml ↩