# Three Years of PrintNightmare: How the Oldest Windows Service Survived Four Patch Waves

> How the Windows Print Spooler produced nine SYSTEM-execution primitives in 2010-2024 and why Microsoft answered with two parallel architectures, not one.

*Published: 2026-06-02*
*Canonical: https://paragmali.com/blog/three-years-of-printnightmare-how-the-oldest-windows-service*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
Between June 2021 and August 2024, Microsoft patched the Windows Print Spooler four times for what the press collectively called PrintNightmare. The patches did not converge. Each wave revealed the last one as a behavior restriction rather than an architectural change. By October 2024 Microsoft had shipped two parallel architectural answers: Windows Protected Print Mode (WPP), an opt-in driverless local stack with a lower-privilege Spooler Worker process; and Universal Print, a cloud-hosted replacement. Two answers, because the local SYSTEM-context driver-loading primitive the spooler was built around in the early 1990s cannot be sandboxed without breaking the printer install base that depends on it. This article traces nine related Spooler EoP and RCE primitives from 2010 to 2024, the architectural concession that ended the patch cycle, and why no single 2026 configuration is the full answer.
</TLDR>

## 1. June 29, 2021: The Repository That Should Not Have Existed

On June 29, 2021, three researchers from Sangfor Technology -- Zhiniang Peng, Xuefeng Li, and Lewis Lee -- pushed a GitHub repository named `afwu/PrintNightmare` containing a working proof-of-concept exploit against the Windows Print Spooler service. The repository had been prepared for their upcoming Black Hat USA 2021 briefing, "Diving Into Spooler: Discovering LPE and RCE Vulnerabilities in Windows Printer" [@infocondb-bh2021-sangfor]. The team believed Microsoft's June 8 Patch Tuesday update had fixed the vulnerability they were about to demonstrate.

Within hours the repository was deleted. By then it had already been mirrored on multiple GitHub accounts and was spreading [@hackernews-printnightmare-poc-leak]. By the end of the day, the internet had a new name for the bug class: PrintNightmare. And by the end of the week, Microsoft, CERT/CC, and CISA had each independently confirmed what the Sangfor team realized about an hour after the deletion: the June 8 patch did not actually fix the vulnerability they had reported, and now the world had a working exploit for it [@cert-vu-383432] [@bleepingcomputer-domain-takeover].

The Wayback Machine preserves the original README. Below the technical description, the Sangfor team explained why they had thought it was safe to publish: Microsoft's June 8 advisory had marked CVE-2021-1675 as a local "Privilege Escalation" with a CVSS v3.1 base score of 7.8 [@nvd-cve-2021-1675]. The bug Sangfor had separately reported and analyzed was, they believed, a different bug -- a remote code execution against the same service. They were correct. Nobody knew it yet.<Sidenote>Microsoft silently reclassified CVE-2021-1675 from "Elevation of Privilege" to "Remote Code Execution" on June 21, 2021, after community analysis demonstrated the remote primitive. The reclassification appears in the NVD entry's revision history [@nvd-cve-2021-1675] and was reported the same week by BleepingComputer [@bleepingcomputer-domain-takeover]. The Sangfor team's confusion was reasonable: the advisory they were reading on June 28 still said EoP.</Sidenote>

The README's most striking line is an apology. "CVE-2021-1675 is a remote code execution in Windows Print Spooler," it begins. Then, two paragraphs in: "We also found this bug before and hope to keep it secret to participate Tianfu Cup" [@afwu-wayback-snapshot]. The Sangfor team had discovered the same primitive months earlier, planned to use it for the Tianfu Cup capture-the-flag prize money, and reasoned that Microsoft's June 8 patch had now closed it.<Sidenote>The Tianfu Cup is a Chinese-government-organized exploit competition. Chinese researchers are restricted from foreign competitions like Pwn2Own by a 2018 directive and instead route their work through Tianfu. Holding a bug secret to maximize Tianfu prize money is a known practice; what is unusual here is the public admission of the practice in an apology README.</Sidenote>

The rest of this article is about two questions. First: why does a single Windows service produce, on the public record, nine independently classed SYSTEM-code-execution primitives across fifteen years? Second: why does the answer Microsoft eventually shipped in 2024 take the form of two parallel architectures rather than one patch? We will not tell you which configuration to deploy. We will tell you why neither one alone is the full answer, and why that is the only honest place to land.

To understand why one Windows service can leak a SYSTEM-execution primitive to anyone who can reach an RPC named pipe on a domain controller, we have to understand what the service is for.

## 2. The Artifact: What `spoolsv.exe` Is and Why It Was Built This Way

The Windows Print Spooler service has been part of Windows continuously since the Windows NT era of the early 1990s.<Sidenote>The "Windows NT 3.1, July 1993" attribution often cited for the first Print Spooler service is folk knowledge. Microsoft's own Learn documentation anchors the spooler architecture to "Microsoft Windows 2000 and later" [@ms-print-spooler-architecture], and the Windows Internals team writes that the spooler is "largely unchanged since Windows NT 4" [@windows-internals-printdemon]. The early-1990s framing is the safe one.</Sidenote> Same name today (`spoolsv.exe`), same security context (LocalSystem), same RPC interface family, same in-process third-party DLLs (Print Providers, Print Processors, driver components). The interesting question is not why the spooler still has bugs. It is why a service designed before [AppContainer](/blog/appcontainer-and-lowbox-tokens-windowss-capability-sandbox/), before [Mandatory Integrity Control](/blog/the-integrity-level-stack-mic-uipi-and-twenty-years-of-uacs-/), before [AMSI](/blog/amsi-the-pre-execution-window-defender/), before [Driver Signature Enforcement](/blog/windows-kernel-code-integrity-2006-2026/) -- before the entire modern Windows security architecture existed -- still occupies the same SYSTEM-context process slot it did in 1996.

### 2.1 Anatomy

`spoolsv.exe` is, in Microsoft's own words, "the spooler's API server" [@ms-intro-spooler-components]. The Service Control Manager starts it at boot under the LocalSystem account. Inside the process, the router DLL `spoolss.dll` dispatches incoming API calls to one of three Print Provider DLLs [@ms-print-spooler-architecture].

<Definition term="Spooler Service (spoolsv.exe)">
The Windows service that mediates between print clients and printer drivers. It runs continuously as LocalSystem, exposes an RPC interface over the `\PIPE\spoolss` named pipe, and loads third-party Print Provider, Print Processor, and printer driver DLLs into its address space [@ms-intro-spooler-components]. Almost every named Print Spooler vulnerability since 2010 has cashed out as SYSTEM-context code execution inside this process.
</Definition>

The three Print Providers handle three kinds of printer connections. The Local Print Provider `localspl.dll` handles printers attached or shared on the local machine. The Remote Print Provider `win32spl.dll` handles printers reached via Windows networking. The HTTP / IPP Print Provider `inetpp.dll` handles printers exposed over the Internet Printing Protocol [@ms-print-spooler-architecture] [@ms-intro-spooler-components].

<Definition term="Print Provider DLL chain">
The three router-loaded DLLs that dispatch print operations to the appropriate transport. `localspl.dll` (Local Print Provider) handles local and SMB-shared printers; `win32spl.dll` (Remote Print Provider) handles Windows-network remote printers; `inetpp.dll` (HTTP / IPP Print Provider) handles IPP printers reached over HTTP [@ms-print-spooler-architecture]. The chain is often confused with the Print Processor layer (a different layer entirely; see below).
</Definition>

Once a print job is accepted, a separate component decides how to render it. That component is the Print Processor. The default Print Processor is `winprint.dll`. It is a sibling layer to the Print Providers, not a member of the chain.

<Definition term="Print Processor (winprint.dll)">
The component that interprets the spool file format (EMF, XPS, RAW, TEXT) and renders pages for a specific printer. `winprint.dll` is the default Print Processor that ships with Windows. Vendor-supplied Print Processors can be installed alongside it. A common pre-research misclassification names `winprint.dll` as a Print Provider; it is not. The Print Providers handle which printer; the Print Processor handles how to render the page [@ms-print-spooler-architecture].
</Definition>

Clients of `spoolsv.exe` are `winspool.drv` locally and `win32spl.dll` remotely [@ms-intro-spooler-components]. A user-mode application that calls a Win32 print API (`OpenPrinter`, `EnumPrinters`, `AddPrinter`, `AddPrinterDriverEx`) is, under the covers, sending an RPC request to `spoolsv.exe` through one of these client libraries.

<Mermaid caption="Figure 1: Print Spooler architecture circa Windows 10. A single LocalSystem-context process serves both local and remote callers through a chain of router-dispatched Print Provider DLLs. The optional PrintIsolationHost.exe sibling process hosts driver code only when a driver opts in via its INF file.">
flowchart TD
    SCM["Service Control Manager"] --> SPOOLSV["spoolsv.exe<br/>LocalSystem"]
    SPOOLSV --> ROUTER["spoolss.dll<br/>(router)"]
    ROUTER --> LOCALSPL["localspl.dll<br/>Local Print Provider"]
    ROUTER --> WIN32SPL["win32spl.dll<br/>Remote Print Provider"]
    ROUTER --> INETPP["inetpp.dll<br/>HTTP / IPP Print Provider"]
    ROUTER --> WINPRINT["winprint.dll<br/>Print Processor"]
    PIPE["\PIPE\spoolss<br/>(named pipe / ncacn_np)"] --> SPOOLSV
    WINSPOOL["winspool.drv<br/>local clients"] --> PIPE
    REMOTE["win32spl.dll<br/>remote clients"] --> PIPE
    SPOOLSV -. opt-in INF .-> PIH["PrintIsolationHost.exe<br/>(sibling, LocalSystem)"]
    PIH --> VDRIVER["vendor driver DLLs"]
</Mermaid>

### 2.2 The RPC Surface

The Print Spooler exposes two RPC interface families. MS-RPRN is the synchronous Print System Remote Protocol. MS-PAR is its asynchronous counterpart. Both bind to the same named pipe.

<Definition term="MS-RPRN and MS-PAR">
Microsoft's two open-specification RPC protocols for remote print management. MS-RPRN is synchronous; MS-PAR is asynchronous. The MS-RPRN specification states that "The RPC Protocol Sequence MUST be `ncacn_np`. The RPC Protocol Sequence Endpoint MUST be `\PIPE\spoolss`" [@ms-rprn-spec]. Both interfaces expose driver-installation entry points: `RpcAddPrinterDriverEx` in MS-RPRN [@ms-rprn-rpcaddprinterdriverex] and `RpcAsyncAddPrinterDriver` in MS-PAR [@ms-par-rpcasyncaddprinterdriver]. MS-PAR's documentation states verbatim that the latter is "The counterpart of this method in the Print System Remote Protocol."
</Definition>

Two symmetric entry points are the architectural seed of the entire PrintNightmare patch tree. `RpcAddPrinterDriverEx` (MS-RPRN section 3.1.4.4.8, Opnum 89) "installs a printer driver on the print server" [@ms-rprn-rpcaddprinterdriverex]. `RpcAsyncAddPrinterDriver` (MS-PAR section 3.1.4.1, Opnum 39) does the same thing through the asynchronous interface [@ms-par-rpcasyncaddprinterdriver]. When the June 8, 2021 patch tightened access checks on the first entry point, the second one remained as the obvious next bypass target. We will come back to this.

The authentication boundary is the part most worth dwelling on, because the answer is structurally surprising. **MS-RPRN does no authentication at the protocol layer.** The MS-RPRN Transport section states this verbatim: "The client MUST use no authentication, and the server MUST accept connections without authentication" [@ms-rprn-transport]. The initialization section adds that the binding handle "MUST specify an `ImpersonationLevel` of 2 (Impersonation)" against the SMB2 transport [@ms-rprn-initialization]. The RPC layer trusts whatever caller identity SMB hands it.

This means the practical authentication boundary on `\PIPE\spoolss` is the SMB named-pipe access control surface, not the RPC server. Two security policy settings govern that surface. The first, **Network access: Restrict anonymous access to Named Pipes and Shares** (the `RestrictNullSessAccess` registry value under `HKLM\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters`), has shipped at value `1` -- enforced -- by default since Windows Vista; its effective default is "Enabled" on stand-alone servers, domain controllers, member servers, and client computers [@ms-restrict-anonymous-named-pipes]. The second, **Network access: Named Pipes that can be accessed anonymously** (the `NullSessionPipes` list), enumerates the small set of pipes that an unauthenticated caller is allowed to touch even when the first policy is enforced. `spoolss` is **not** on the default `NullSessionPipes` list [@ms-named-pipes-anonymous].<Sidenote>The combination of these two settings is what makes a default modern Windows host immune to anonymous-SMB reachability of `\PIPE\spoolss`. The MS-RPRN spec's "MUST use no authentication" sentence [@ms-rprn-transport] reads like a security failure in isolation; combined with `RestrictNullSessAccess=1` and the absence of `spoolss` from `NullSessionPipes` [@ms-restrict-anonymous-named-pipes] [@ms-named-pipes-anonymous], it becomes a deliberate division of labour: RPC does not authenticate; SMB does. The architectural cost is that the boundary is administered through two settings on a different policy surface than the spooler itself.</Sidenote>

On a default Windows 11 24H2 host with the Print Spooler running, then: an unauthenticated remote attacker on the network cannot reach `\PIPE\spoolss`. A *domain* user authenticated to the same Active Directory forest can. That is the practical reachability boundary that CERT/CC and CISA had in mind when they called PrintNightmare a "domain takeover" primitive [@bleepingcomputer-domain-takeover] [@cisa-ed-21-04]: any domain user reaches the spooler on a domain controller; the spooler executes attacker-supplied code as LocalSystem; that LocalSystem code now runs on a host that owns the domain. The "domain user can reach it" half is true because SMB authenticates the user and the RPC layer accepts whatever SMB says; the "executes attacker-supplied code as LocalSystem" half is the architectural primitive section 2.3 will name.

### 2.3 The Back-Compat Constraint

Why has the architecture not been replaced? Because essentially every Windows-compatible printer manufactured since 1993 ships a third-party driver DLL that expects to be loaded into `spoolsv.exe` as LocalSystem.

The v3 driver model -- introduced with Windows 2000 -- loads driver render code into the spooler process by default [@ms-print-spooler-architecture]. The v4 driver model, introduced with Windows 8, was a simpler XPS-based alternative meant to package drivers in a way that worked across multiple Windows form factors [@ms-print-spooler-architecture]. It did not replace v3. The two coexisted for more than a decade. The IPP class driver [@ms-modern-print-platform], which lets Windows print to any Mopria-certified printer without any vendor-specific driver at all, was not even an option for the first twenty years of the spooler's life [@mopria-certified-products].

What this means in practice: the installed base of printers in 2021 was overwhelmingly v3 drivers, signed by vendors, packaged for LocalSystem load. A naive "sandbox the spooler" change that broke that loading model would break printing for every one of those printers. Microsoft has spent twenty years trying not to make printing not work. That constraint is the protagonist of the rest of the article.

### 2.4 Point and Print and Why It Is Its Own Constraint

Point and Print is the SMB-fetch-and-install-driver-on-print behavior introduced with Windows NT 4.0. When a client first prints to a shared printer, the spooler downloads the driver package from the print server and installs it locally. The user does not have to be an administrator.

<Definition term="Point and Print">
A Windows print-client behavior in which a non-administrator user, on first use of a shared printer, causes their machine's spooler to download and install the printer's driver package from the print server. Two Group Policy registry values govern whether the user is warned and whether elevation is suppressed: `NoWarningNoElevationOnInstall` (suppress install-time elevation) and `NoWarningNoElevationOnUpdate` (suppress update-time elevation) [@kb-5005010-topic] [@kb-5005652-topic]. The Microsoft-supplied "fix" to this design surface is a third registry value, `RestrictDriverInstallationToAdministrators`, which overrides both.
</Definition>

Bake "any authenticated user can cause a driver DLL to be downloaded and registered" into a protocol and you have, by construction, a low-privilege code-installation path. The two relevant Group Policy levers (`NoWarningNoElevationOnInstall` and `NoWarningNoElevationOnUpdate`) and the registry override (`RestrictDriverInstallationToAdministrators`) all existed before PrintNightmare. All three defaulted to the permissive position. The June 2021 disclosure made the permissive defaults visible.

> **Key idea:** Three of the four Print Spooler design choices -- LocalSystem context, third-party DLL loading, and a low-privilege RPC entry point -- form the architectural primitive. The rest of this article is the story of what happens when the security community discovers, again and again, that any single primitive of that shape produces a SYSTEM-execution bug by construction.

## 3. Pre-history: Stuxnet, PrintDemon, and the Bug Class That Already Had a Decade Behind It

PrintNightmare is the name the press gave to a 2021 disclosure event. The bug class behind that event is older. The first weaponized Print Spooler privilege-escalation primitive in the public record is from 2010, and it is famous. It was one of the four zero-days Stuxnet chained to reach centrifuge controllers in Natanz.

### 3.1 CVE-2010-2729 (Stuxnet, MS10-061)

In September 2010, Microsoft shipped MS10-061 to patch a Print Spooler Service Impersonation Vulnerability that "could allow remote code execution if an attacker sends a specially crafted print request to a vulnerable system that has a print spooler interface exposed over RPC" [@ms-bulletin-ms10-061]. The NVD entry classifies it as a CWE-20 Improper Input Validation in the Print Spooler service that, "when printer sharing is enabled, does not properly validate spooler access permissions" [@nvd-cve-2010-2729]. NVD records publication on September 15, 2010 [@nvd-cve-2010-2729].

<Aside label="Why Stuxnet matters here">
The Symantec dossier on Stuxnet [@symantec-stuxnet-dossier-broadcom] is the canonical technical history of the Iran-Natanz campaign and is out of scope here. What matters for the Print Spooler story is the architectural pattern Stuxnet's operators noticed. A low-privilege caller could reach a SYSTEM-context RPC service, get the service to do something on the caller's behalf (write a file, load a DLL, validate a credential), and turn that operation into SYSTEM-context code execution. That pattern is the same one every later PrintNightmare-family bug exploits. The 2010 case is not the first instance of the pattern in Windows. It is the first instance of the pattern in the Windows Print Spooler in the public record.
</Aside>

### 3.2 CVE-2020-1048 (PrintDemon, May 2020)

Ten years later, in May 2020, two independent research teams published essentially the same Print Spooler bug. Peleg Hadar and Tomer Bar at SafeBreach Labs presented their work at DEF CON Safe Mode 2020 [@defcon-28-hadar-bar-pdf]. Yarden Shafir and Alex Ionescu at Windows Internals wrote it up under the name PrintDemon [@windows-internals-printdemon].<Sidenote>The co-discovery pattern is the norm for high-value Windows-internals research. Two well-resourced teams looked at the same architectural primitive and arrived at the same vulnerability within weeks of each other. The May 2020 Microsoft Security Response Center acknowledgments credit both groups.</Sidenote> The vulnerability was assigned CVE-2020-1048.

The mechanism: `spoolsv.exe` accepts a Win32 print API call to set a printer port. The port string can be a file path. The spooler, running as LocalSystem, then writes spool data to that file path. A low-privilege user can therefore cause SYSTEM-context arbitrary writes to anywhere on the filesystem. NVD classifies the bug as CWE-669 Incorrect Resource Transfer Between Spheres [@nvd-cve-2020-1048].

The Shafir-Ionescu writeup is the source of the line that most concisely captures the spooler's long arc:

<PullQuote>
"The Print Spooler continues to be one of the oldest Windows components that still has not gotten much scrutiny, even though it is largely unchanged since Windows NT 4, and was even famously abused by Stuxnet." -- Yarden Shafir and Alex Ionescu, May 2020 [@windows-internals-printdemon]
</PullQuote>

### 3.3 CVE-2020-1337 (PrintDemon Redux, August 2020)

Microsoft patched CVE-2020-1048 on May 12, 2020. Three months later, on August 11, 2020 Patch Tuesday, Microsoft patched CVE-2020-1337. Paolo Stagno (VoidSec) had demonstrated that the May patch was bypassable through an NTFS junction race [@voidsec-cve-2020-1337]. NVD classes the bypass as a CWE-367 TOCTOU [@nvd-cve-2020-1337].

The mechanism is the canonical pattern for path-validation patches. Microsoft's May fix resolved the printer port file path, validated it as benign, then re-resolved it during the actual spool write. Between check and use, a non-administrator could substitute a reparse point that redirected the write to a SYSTEM-writable target. The patch had moved the security check; the architectural primitive (SYSTEM-context filesystem operation on a caller-controlled path) was unchanged.

The detail to file away: the exact same primitive, NTFS reparse points racing a spooler-side resolve-validate-use sequence, would resurface eighteen months later in SpoolFool. Same primitive, different entry point.

### 3.4 The Pattern Nobody Had Yet Named

Three independent research efforts (the Microsoft analysis post-Stuxnet, the SafeBreach and Windows Internals work in 2020, the Sangfor work that would surface in 2021) each rediscovered variants of the same architectural primitive. The frustration the §1 hook left implicit is now nameable. The security community had documented this primitive twice before PrintNightmare became a news event.

Will Dormann's CERT/CC advisory VU#383432 (issued June 30, 2021) was not, strictly speaking, about the bug. It was about the disclosure-norms failure that turned an internal bug into an internet-mirrored zero-day inside twenty-four hours. Dormann wrote in plain language:

<PullQuote>
"CVE-2021-34527 is similar but distinct from the vulnerability that is assigned CVE-2021-1675, which addresses a different vulnerability in `RpcAddPrinterDriverEx()`. The attack vector is different as well." -- Will Dormann, CERT/CC VU#383432, June 30, 2021 [@cert-vu-383432]
</PullQuote>

The sentence is unusual for a CERT advisory because it concedes mid-disclosure that the June 8 patch had named one CVE and the public exploits were targeting another. CERT/CC's explicit "does NOT protect" framing -- which we quote verbatim in section 4.1 at the point in the patch-cascade narrative where it lands hardest -- followed in the same advisory and made the gap unmistakable.

PrintNightmare is not the name of a CVE. It is the name a panic gave, in the last week of June 2021, to a class of Print Spooler EoP and RCE primitives that had already been exploited in production eleven years earlier and rediscovered by independent researchers fourteen months earlier. The 2021 event made the class famous. It did not invent the class.

The next section is what happened when Microsoft and the security community spent three years trying to patch the class out of existence one entry point at a time.

## 4. The Patch Cascade: Four Generations of PrintNightmare

Between June 8, 2021, and August 13, 2024, Microsoft shipped four named patch waves targeting the PrintNightmare bug class. None of the first three converged. The fourth was issued for an unrelated-looking CVE (CVE-2024-38198) that turned out to be exploitable against a primitive the September 2021 wave had already documented as residual.

The Mermaid gantt below sets the spine of the timeline. It runs from Stuxnet through the announced third-party-driver end-of-servicing milestones in 2027. Every later subsection of this article maps to a bar in this chart.

<Mermaid caption="Figure 2: Print Spooler bugs (red lane), Microsoft patches (blue lane), and architectural redesigns (green lane) from 2010 through the announced WPP / third-party-driver end-of-servicing horizon in 2027.">
gantt
    title Print Spooler hardening timeline 2010-2027
    dateFormat YYYY-MM-DD
    axisFormat %Y
    section Bugs
    CVE-2010-2729 Stuxnet           :crit, 2010-09-15, 60d
    CVE-2020-1048 PrintDemon        :crit, 2020-05-12, 60d
    CVE-2020-1337 PrintDemon redux  :crit, 2020-08-11, 60d
    CVE-2021-1675                   :crit, 2021-06-08, 30d
    CVE-2021-34527 PrintNightmare   :crit, 2021-07-01, 30d
    CVE-2021-34481                  :crit, 2021-07-15, 30d
    CVE-2021-36958                  :crit, 2021-09-14, 30d
    CVE-2022-21999 SpoolFool        :crit, 2022-02-08, 30d
    CVE-2024-38198                  :crit, 2024-08-13, 30d
    section Patches
    MS10-061                        :active, 2010-09-14, 30d
    KB5004945 emergency             :active, 2021-07-06, 30d
    KB5005010 default flip          :active, 2021-08-10, 30d
    KB5005652 policy rewrite        :active, 2021-09-14, 30d
    SpoolFool fix                   :active, 2022-02-08, 30d
    Redirection Guard               :active, 2023-12-01, 60d
    section Architecture
    WPP announced                   :done, 2023-12-13, 30d
    WPP ships opt-in 24H2           :done, 2024-10-01, 30d
    No new 3p drivers WU            :2026-01-15, 30d
    IPP class preferred             :2026-07-01, 30d
    3p driver servicing ends        :2027-07-01, 30d
</Mermaid>

### 4.1 Generation 1: The June 8 Patch and the Sangfor Disclosure Failure

On June 8, 2021 Patch Tuesday, Microsoft fixed CVE-2021-1675, a Windows Print Spooler Elevation of Privilege Vulnerability rated CVSS v3.1 7.8 local EoP [@nvd-cve-2021-1675]. The fix added an authorization check to `RpcAddPrinterDriverEx` (MS-RPRN section 3.1.4.4.8) so that a low-privilege user could no longer install an arbitrary printer driver into the spooler process via that synchronous entry point [@ms-rprn-rpcaddprinterdriverex]. Microsoft credited Zhipeng Huo (Tencent Security Xuanwu Lab), Piotr Madej (AFINE), and Yunhai Zhang (NSFOCUS Security Team), as recorded in the Wayback snapshot of the Sangfor README [@afwu-wayback-snapshot]. Three reporters. No Victor Mata. Mata enters this story later, in section 4.3.

On June 21, 2021, Microsoft silently reclassified CVE-2021-1675 from EoP to RCE [@nvd-cve-2021-1675]. BleepingComputer's June 30 article documents the reclassification and the subsequent confusion it caused [@bleepingcomputer-domain-takeover]. The Sangfor team had been working from the June 8 advisory's EoP framing; by the time they noticed the reclassification, their PoC was already mirrored across the internet.

The chaos compressed into seventy-two hours. June 29: Sangfor pushes `afwu/PrintNightmare`, then deletes the repository on realizing the RCE was unpatched. June 30: public mirrors propagate across multiple GitHub accounts; CERT/CC publishes VU#383432 [@cert-vu-383432]; Sergiu Gatlan files the BleepingComputer "domain takeover" story [@bleepingcomputer-domain-takeover]. July 1: Microsoft assigns CVE-2021-34527 as a separate-bulletin entity covering the unpatched RCE primitive [@nvd-cve-2021-34527] [@msrc-cve-2021-34527]. CERT/CC documents the CVE pair as "similar but distinct" with the qualifier that "the attack vector is different as well" [@cert-vu-383432]. They are not the same bug; the new CVE is not simply the "remote" version of the old one.

<PullQuote>
"This update does NOT protect against public exploits that may refer to PrintNightmare or CVE-2021-1675." -- Will Dormann, CERT/CC VU#383432 [@cert-vu-383432]
</PullQuote>

CERT/CC's only available mitigation, in the window between July 1 and the emergency patch, was to stop and disable the Spooler service entirely [@cert-vu-383432]. The runnable block below models the PowerShell logic in JavaScript (the blog runtime supports JS, not PowerShell). The semantics are the same: turn the service off, verify it stays off across reboot.

<RunnableCode lang="js" title="CERT/CC July 2021 mitigation state probe (modelled in JS; original was PowerShell)">{`
// Original PowerShell from CERT/CC VU#383432:
//   Stop-Service -Name Spooler -Force
//   Set-Service -Name Spooler -StartupType Disabled
//   Get-Service -Name Spooler
//
// The probe below models the resulting state machine so you can
// see what "safe" looks like for a domain controller under CISA
// Emergency Directive 21-04.
const spoolerState = {
  status: 'Stopped',
  startupType: 'Disabled'
};
const isCertSafe = spoolerState.status === 'Stopped'
  && spoolerState.startupType === 'Disabled';
console.log(isCertSafe
  ? 'OK: spooler stopped and disabled (CERT/CC mitigation in force)'
  : 'WARN: spooler running or set to auto-start (vulnerable surface present)');
`}</RunnableCode>

On July 6 and July 7, 2021, Microsoft shipped KB5004945 out-of-band. The NVD entry for CVE-2021-34527 records both shipping dates verbatim: "UPDATE July 7, 2021: The security update for Windows Server 2012, Windows Server 2016 and Windows 10, Version 1607 have been released" [@nvd-cve-2021-34527]. KB5004945's summary line is unambiguous: "Updates a remote code execution exploit in the Windows Print Spooler service, known as PrintNightmare, as documented in CVE-2021-34527" [@kb-5004945-help].<Sidenote>KB5004945's SKU fan-out was unusually wide. Microsoft shipped the patch for Windows 10 across multiple feature updates, for Windows 11 (just-released at the time), for Windows Server 2016/2019/2022, and for ESU-only SKUs back through Windows 7 SP1 and Windows Server 2008 R2 [@kb-5004945-help]. The fan-out signals how broadly the vulnerable surface had spread across the supported install base, which is most of the reason the press could describe the bug as fleet-wide.</Sidenote>

The patch had two parts. The first closed the immediate RCE. The second added a new Group Policy registry value: `RestrictDriverInstallationToAdministrators`. KB5004945 shipped this value as OFF by default. KB5005010 (released August 10, 2021) records the timeline of the default flip verbatim: "Updates released July 6, 2021 or later have a default of 0 (disabled) until updates released August 10, 2021. Updates released August 10, 2021 or later have a default of 1 (enabled)" [@kb-5005010-topic].

The patch had a switch. The switch was off by default. The press named the bug PrintNightmare. By the end of the first week, the patch had not, in practice, been applied to most of the installed base.

### 4.2 Generation 2: `@cube0x0`, MS-PAR, and the Asynchronous-Variant Patch Bypass

After KB5004945 closed the synchronous `RpcAddPrinterDriverEx` entry point on MS-RPRN, a researcher under the handle `@cube0x0` updated his repository to target the symmetric asynchronous entry point in MS-PAR. Different protocol family. Same primitive. No patch.

`RpcAsyncAddPrinterDriver` (MS-PAR section 3.1.4.1, Opnum 39) is, in Microsoft's own words, "The counterpart of this method in the Print System Remote Protocol" [@ms-par-rpcasyncaddprinterdriver]. CERT/CC's updated VU#383432 names the bypass explicitly:

<PullQuote>
"While original exploit code relied on the `RpcAddPrinterDriverEx` to achieve code execution, an updated version of the exploit uses `RpcAsyncAddPrinterDriver` to achieve the same goal." -- Will Dormann, CERT/CC VU#383432 update [@cert-vu-383432]
</PullQuote>

The `@cube0x0` GitHub repository carries the artifact of the rename-mid-disclosure chaos in its very name. The repository is called `cube0x0/CVE-2021-1675`. The vulnerability it actually exploits is CVE-2021-34527. The README's first paragraph clarifies: "Impacket implementation of the PrintNightmare PoC originally created by Zhiniang Peng (@edwardzpeng) and Xuefeng Li (@lxf02942370). Tested on a fully patched 2019 Domain Controller" [@cube0x0-cve-2021-1675].<Sidenote>The repository-name-versus-CVE mismatch is a small artifact of the disclosure chaos, but it caused real downstream confusion. Detection rule authors had to handle both names. SigmaHQ's Zeek-on-the-wire rule for the wire-level driver-install primitive lists both `RpcAddPrinterDriverEx` and `RpcAsyncAddPrinterDriver` precisely because the entry point split between the two CVEs [@sigma-cve-2021-1675-zeek].</Sidenote>

The July 6 emergency patch (KB5004945) added the access check to MS-PAR's `RpcAsyncAddPrinterDriver` in addition to MS-RPRN's `RpcAddPrinterDriverEx`. Microsoft's NVD entry for CVE-2021-34527 records the residual configuration risk verbatim:

> **Note:** "Having `NoWarningNoElevationOnInstall` set to 1 makes your system vulnerable by design." -- Microsoft, NVD entry for CVE-2021-34527 [@nvd-cve-2021-34527]

CISA's response was Emergency Directive 21-04, issued July 13, 2021. The directive mandated that federal civilian agencies disable the Print Spooler service on all Microsoft Active Directory domain controllers by 11:59 PM EDT on Wednesday, July 14, 2021 [@cisa-ed-21-04]. The framing in CISA's own words was direct: "exploitation of the vulnerability allows an attacker to remotely execute code with system level privileges enabling a threat actor to quickly compromise the entire identity infrastructure of a targeted organization" [@cisa-ed-21-04].

<Aside label="What CISA actually told federal agencies to do">
ED 21-04 is narrower than the press summaries suggest. It applies only to Active Directory domain controllers. It does not require disabling Spooler on every Windows endpoint in a federal agency, only on the hosts where the bug's domain-takeover impact is largest. CISA closed ED 21-04 in January 2026 and folded its required actions into BOD 22-01 (the Known Exploited Vulnerabilities catalogue), but the operational guidance survived intact: disable Spooler on DCs, patch elsewhere. The DC-disabled baseline is still the federal civilian default for agencies that have not migrated to Universal Print [@cisa-ed-21-04]. We come back to this in section 10.4.
</Aside>

The June 8 patch covered one RPC entry point. The July 6 patch covered the other. Neither patch changed the architectural primitive. Within five weeks, a third primitive (not an RPC entry point but a registry default) was already failing.

### 4.3 Generation 3: CVE-2021-34481, KB5005010, KB5005652, and the September Policy Rewrite

On August 10, 2021, Microsoft shipped the cumulative update that flipped the `RestrictDriverInstallationToAdministrators` default from 0 to 1. On September 14, 2021, it shipped the knowledge-base article that documented why the previous defaults could not be saved.

CVE-2021-34481 had already been published as a Print Spooler local EoP on July 15, 2021, classified by NVD as CWE-269 Improper Privilege Management [@nvd-cve-2021-34481]. The August 10 KB5005010 / KB5005033 cumulative updates closed it and flipped the default value for the `HKLM\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint\RestrictDriverInstallationToAdministrators` registry value from 0 to 1 [@kb-5005010-topic]. NVD's entry for CVE-2021-34481 carries the cross-reference verbatim: "UPDATE August 10, 2021: Microsoft has completed the investigation and has released security updates to address this vulnerability... This security update changes the Point and Print default behavior; please see KB5005652" [@nvd-cve-2021-34481].

The five-week opt-in window between July 6 and August 10, 2021, is the most interesting failure in the entire patch cascade. Hosts that received KB5004945 but had no Group Policy push for the new value were still exploitable through Point and Print elevation suppression even with the emergency patch applied. The lesson is structural. Opt-in safe defaults do not protect a real installed base.

On September 14, 2021, KB5005652 shipped. The article's title spells out its scope: "Manage new Point and Print default driver installation behavior (CVE-2021-34481)" [@kb-5005652-topic]. The article's most-quoted sentence is the most consequential one Microsoft has shipped about Print Spooler:

> **Note:** KB5005652 says, in a customer-facing knowledge-base article, that there is no settings-tweak combination that gives you the same protection as flipping the new admin-only switch. That is Microsoft, in its own voice, naming the configuration surface as insufficient.

<PullQuote>
"There is no combination of mitigations that is equivalent to setting `RestrictDriverInstallationToAdministrators` to 1." -- Microsoft, KB5005652, September 14, 2021 [@kb-5005652-topic] [@kb-5005652-help]
</PullQuote>

Read that sentence twice. Microsoft, in its own knowledge-base voice, said that no combination of the previously available configuration knobs added up to the protection the new admin-only restriction provided. The implication is that for the entire period from Windows NT 4 through August 10, 2021 (roughly twenty-three years), the configuration surface for Point and Print did not contain a setting that made the bug class go away. Tightening individual knobs got you somewhere short of the architectural answer. That is the verbatim concession the September article makes.

The same Patch Tuesday (September 14, 2021), Microsoft also patched CVE-2021-36958, another Print Spooler RCE in the same family [@nvd-cve-2021-36958].<Sidenote>The reporter attribution for CVE-2021-36958 remains disputed in the public record. Public consensus credits Victor Mata (Accenture Security FusionX) for the formal MSRC acknowledgment. Benjamin Delpy demonstrated public bypasses of the existing PrintNightmare mitigations through August 2021 that are most often cited as the immediate motivation for the September fix. We have not located a Microsoft-primary source that resolves the question, and we cite both names rather than collapse them.</Sidenote>

Three patch waves into PrintNightmare, Microsoft had written down, in a customer-facing knowledge-base article, that no configuration-surface response was equivalent to the architectural fix. The architectural fix did not yet exist. SpoolFool was four months away.

### 4.4 Generation 4: CVE-2022-21999 (SpoolFool, February 8, 2022)

On February 8, 2022, Oliver Lyak (handle `@ly4k_`, trailing underscore) of SafeBreach Labs published SpoolFool. The exploit is a Print Spooler local privilege escalation that abuses the `SpoolDirectory` registry value plus an NTFS junction [@ly4k-spoolfool]. The primitive was the same one Shafir and Ionescu had described eighteen months earlier in CVE-2020-1337. The patch surface had moved. The architectural primitive had not.

The mechanism, walked through carefully: each per-printer registry key under `HKLM\System\CurrentControlSet\Control\Print\Printers\<printer-name>` has a `SpoolDirectory` value. The SYSTEM-context spooler reads that value, calls `CreateDirectory` on the path, and then writes spool files into the resulting directory. The `SpoolDirectory` value is writable by an authenticated user. The exploit therefore composes three steps: (1) set `SpoolDirectory` to an attacker-chosen path, (2) plant an NTFS junction or symbolic link at that path pointing into a SYSTEM-writable directory, (3) trigger a printer reload to cause the SYSTEM-context spooler to create the destination directory and drop attacker-controlled files there [@ly4k-spoolfool]. NVD classifies the bug as CWE-59 Link Following [@nvd-cve-2022-21999].

Anti-regression note for readers familiar with the early coverage: SpoolFool is a Print Spooler arbitrary-file-write LPE. It is not a Win32k integrity-level bypass. Win32k is the GUI subsystem and is uninvolved in this bug class. The researcher handle is `@ly4k_` (Oliver Lyak), not `@jonas_lyk` (a distinct security researcher).

From arbitrary file write to SYSTEM code execution is the next step. Lyak's repository demonstrates a DLL-drop into a path that a SYSTEM-context process will load on next start, then a service restart, then SYSTEM-context execution of the attacker's DLL [@ly4k-spoolfool]. The end-to-end primitive is the same shape as the post-PrintDemon exploit chain from August 2020.

The architectural moral: patching `RpcAddPrinterDriverEx`, patching `RpcAsyncAddPrinterDriver`, and flipping the Point and Print elevation default did not change the fact that the spooler runs as SYSTEM and operates on user-controlled filesystem paths. SpoolFool is the bug-fixing-bug exhibit for the section 5 architectural-concession argument. Four patches into the cycle, the same TOCTOU primitive that the August 2020 PrintDemon bypass had used was still exploitable eighteen months later, against a different callsite, against the same SYSTEM-context spooler.

### 4.5 Generation 5: CVE-2024-38198 (August 13, 2024 Patch Tuesday)

On August 13, 2024 Patch Tuesday, Microsoft patched a Windows Print Spooler Elevation of Privilege Vulnerability. The CVSS v3.1 base score was 7.5, with vector `AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H` [@wiz-cve-2024-38198] [@rapid7-cve-2024-38198]. The CWE class was 345, Insufficient Verification of Data Authenticity [@wiz-cve-2024-38198]. The exploit primitive required winning a race condition. No public researcher attribution exists for it. There is, as of mid-2026, no public PoC.

The framing here has to be precise. CWE-345 is "Insufficient Verification of Data Authenticity"; CWE-362 is "Race Condition." These are two different classes. The exploit happens to require winning a race condition to be exploitable; that is a statement about how hard it is to exploit, not a statement about the underlying bug class. Microsoft (per Wiz, citing the MSRC advisory) classified the underlying defect as CWE-345.<Sidenote>The CWE-345 attribution for CVE-2024-38198 is INFERRED via Wiz's vulnerability database, which states verbatim that "the vulnerability has been classified under CWE-345 (Insufficient Verification of Data Authenticity) by Microsoft Corporation" [@wiz-cve-2024-38198]. The MSRC update-guide page is a JavaScript single-page application, so verification of the CWE attribution by automated tools like `web_fetch` runs through Wiz's vulnerability database as the one-step intermediary; a reader with a browser can confirm the same classification directly on the MSRC page. Rapid7's vulnerability database carries the per-SKU KB list and confirms the August 13, 2024 publication date [@rapid7-cve-2024-38198].</Sidenote>

Why this CVE matters for the section 5 argument: it is the empirical proof point that the spooler was still producing novel-class EoP primitives three years after PrintNightmare, eight months after Microsoft announced WPP in the December 2023 MORSE blog [@ms-blog-secure-print-experience-4002645], and seven weeks before WPP shipped opt-in.

Four patch waves across three years. Five named CVEs in the patch tree, plus four more in the pre-history. Nine independently classed Print Spooler SYSTEM-code-execution primitives in fifteen years. The next section is about why Microsoft did not, and could not, ship a tenth patch that closed the class.

### 4.6 The Four-Generation Patch Tree, in One Diagram

The patch tree, mapped to the entry point each generation closed and the bypass each generation enabled:

<Mermaid caption="Figure 3: The four-generation PrintNightmare patch tree. Each generation closes one entry point. The next bypass exploits a different conjunct of the same architectural primitive.">
flowchart TD
    G1["G1: June 8, 2021<br/>RpcAddPrinterDriverEx<br/>auth check added"]
    G2["G2: July 6, 2021<br/>KB5004945 emergency<br/>RpcAsyncAddPrinterDriver patched"]
    G3["G3: August 10, 2021<br/>KB5005010 / KB5005033<br/>RestrictDriverInstallationToAdmins default 0 to 1"]
    G3b["G3b: September 14, 2021<br/>KB5005652<br/>no settings combination is equivalent"]
    G4["G4: February 8, 2022<br/>CVE-2022-21999 SpoolFool<br/>SpoolDirectory + NTFS junction CWE-59"]
    G5["G5: August 13, 2024<br/>CVE-2024-38198<br/>CWE-345 race-condition-exploitable"]
    G1 --> G2
    G2 --> G3
    G3 --> G3b
    G3b --> G4
    G4 --> G5
    G5 --> EXIT["Architectural exit:<br/>WPP / Universal Print<br/>(section 5)"]
</Mermaid>

And the four-fix-strategy comparison matrix in scannable form:

| Generation | CVE | Patch artifact | Attack surface closed | Attack surface left open | Time to documented bypass |
|---|---|---|---|---|---|
| G1 | CVE-2021-1675 | June 8 monthly patch | `RpcAddPrinterDriverEx` (MS-RPRN) low-priv path | `RpcAsyncAddPrinterDriver` (MS-PAR) low-priv path | ~3 weeks |
| G2 | CVE-2021-34527 | KB5004945 (July 6-7 OOB) | Both RPC entry points | Point-and-Print elevation suppression (`NoWarningNoElevationOnInstall=1`) | ~5 weeks (config-not-yet-flipped) |
| G3 | CVE-2021-34481 | KB5005010 / KB5005033 / KB5005652 | Admin-only default for new printer driver install | Spool directory filesystem operations | ~21 weeks (SpoolFool) |
| G4 | CVE-2022-21999 | February 2022 patch | `SpoolDirectory` reparse-point race | Other spooler filesystem operations and authenticity checks | ~30 months (CVE-2024-38198) |
| G5 | CVE-2024-38198 | August 13, 2024 patch | CWE-345 authenticity gap (race-condition exploitable) | Architectural primitive itself | (no public bypass as of June 2026) |

Five subsections. Five entry points. One architectural primitive. The patches do not converge because they cannot.

## 5. The Architectural Concession: Why Microsoft Cannot Sandbox `spoolsv.exe`

An obvious question reading section 4 is: why does Microsoft not just sandbox `spoolsv.exe`? AppContainer exists. Win32 has had constrained-token processes since Windows 8. The Microsoft Office suite runs in low-trust containers. Why is the Print Spooler the exception?

### 5.1 The Naive Sandbox Proposal

The naive proposal is to run `spoolsv.exe` in an AppContainer with no SYSTEM token. The proposal fails for two reasons. The first is engineering. The spooler must register with the Service Control Manager, must coordinate with kernel-mode print components, and must accept inbound RPC over a system named pipe -- operations a fully constrained token does not permit. That problem is solvable; it costs engineering effort, but it has obvious answers (broker process, careful capability grants, custom token).

<Definition term="AppContainer">
A Windows process sandboxing primitive introduced for the Universal Windows Platform that runs a process with a custom integrity level, a restricted token, and a set of explicitly granted capabilities. AppContainer-restricted processes cannot make network connections, read user files, or invoke APIs outside their capability set without explicit permission. Microsoft Edge content processes and many Windows Store apps run in AppContainers; legacy Win32 services typically do not.
</Definition>

The second reason is the back-compat constraint from section 2.3. The third-party driver DLLs in the installed base are signed and packaged to expect LocalSystem context. They use Win32 APIs that a constrained token cannot call. They write to filesystem locations a constrained token cannot reach. They register printer ports through interfaces that a fully sandboxed spooler could not host. The cost of the constrained-token migration is not the cost of changing one Microsoft binary. It is the cost of breaking, in the worst case, every Windows-compatible printer manufactured before 2024.<Sidenote>Microsoft has never published a statement that AppContainer was explicitly evaluated and rejected for `spoolsv.exe`. The argument above is INFERRED from the absence of any constrained-token Spooler in any shipped Windows release, and from the MORSE blog's repeated framing of the third-party driver install base as the binding constraint [@ms-wpp-more-info]. The inference is well grounded but not directly stated.</Sidenote>

### 5.2 PrintIsolationHost.exe as Partial Answer

Microsoft's first attempt to break the "DLL loaded inside `spoolsv.exe`" conjunct shipped with Windows 7 and Windows Server 2008 R2 (October 22, 2009) [@ms-print-spooler-architecture] [@ms-previous-versions-server-2008-R2]. It was called Printer Driver Isolation. The mechanism: third-party driver code can run in a sibling process called `PrintIsolationHost.exe`. The spooler talks to that process over IPC instead of loading the driver DLL into its own address space.

<Definition term="PrintIsolationHost.exe">
A sibling host process introduced in Windows 7 / Server 2008 R2 (October 22, 2009) that can load third-party printer driver code outside of `spoolsv.exe`. Drivers opt in via the `DriverIsolation` directive in their INF file: Microsoft's documentation enumerates two values, `2` ("the driver supports driver isolation") and `0` ("the driver does not support driver isolation"; the same effect as omitting the keyword) [@ms-printer-driver-isolation]. By default, `PrintIsolationHost.exe` runs as LocalSystem [@ms-printer-driver-isolation] [@ms-print-spooler-architecture]. The isolation is process isolation, not privilege isolation.
</Definition>

Three details matter for the section 5 argument. First, the isolation is process isolation, not privilege isolation: `PrintIsolationHost.exe` itself runs as LocalSystem. A bug in `PrintIsolationHost.exe` is still a SYSTEM bug, just in a different process. Second, the opt-in is the driver vendor's responsibility, set in the INF file's `DriverIsolation` directive [@ms-printer-driver-isolation]. By default, if the INF does not opt in, the spooler loads the driver in-process. Third, and most importantly: `PrintIsolationHost.exe` only hosts driver code at print time. It does not move the RPC server, the driver-installation flow (`RpcAddPrinterDriverEx` and `RpcAsyncAddPrinterDriver`), or the spool directory filesystem operations out of `spoolsv.exe`. The PrintNightmare entry points are all in code paths Printer Driver Isolation does not touch.

So Printer Driver Isolation existed for twelve years before PrintNightmare. It did not help. It addresses a different attack surface.

### 5.3 The MORSE Framing

In December 2023, the Microsoft Offensive Research and Security Engineering (MORSE) team and the Print team co-authored a Microsoft Security Blog post announcing what would become Windows Protected Print Mode. The blog and its companion Microsoft Learn pages contain two sentences that are load-bearing for the rest of this article.

The first sentence sets the cadence empirically:

<PullQuote>
"Print bugs accounted for 9% of all cases reported to the Microsoft Security Response Center (MSRC) over the past three years." -- Microsoft, December 2023 [@ms-wpp-more-info] [@ms-blog-secure-print-experience-4002645]
</PullQuote>

The "over the past three years" qualifier matters. The 9% is a baseline measurement for 2020 through 2023, not a long-term steady-state rate. Without the qualifier, the number reads as a stable structural fact about Windows. With the qualifier, it reads as what it actually is: a measurement of the period during which the patch cascade documented in section 4 was running.

The second sentence is more consequential. Microsoft, in its own voice, names the architectural answer:

<PullQuote>
"The ideal solution would be to remove drivers entirely and move the Spooler to a least privilege security model." -- Microsoft, MORSE / Print team [@ms-wpp-more-info]
</PullQuote>

Read that sentence in the context of the section 4 patch cascade. Microsoft is saying that the architectural answer to the bug class is not a better authorization check, not a tighter Point and Print policy, not a more aggressive default flip. It is to remove third-party drivers entirely and to move the spooler off LocalSystem. The enterprise version of the same document spells out the coverage expectation:

<PullQuote>
"Windows protected print mode would mitigate over half of past reported security issues for Windows print." -- Microsoft, Windows Protected Print Mode for Enterprises [@ms-wpp-enterprises]
</PullQuote>

"Past reported security issues for Windows print" is a class. "Would mitigate over half" is a coverage statement at the class level, not at the bug level. WPP is a class mitigation; it is the architectural answer the patch cascade could not produce.

### 5.4 The Forced Parallel-Stack Answer

Here is where the argument turns. Microsoft did not ship one architectural answer. It shipped two. The reason is that neither one alone covers the back-compat envelope.

Universal Print is the cloud-hosted answer. It removes the local print queue, removes the local SYSTEM-context Spooler from the workflow entirely, and centralizes the print fan-out in Microsoft 365 [@ms-universal-print-whatis]. On a Universal-Print-only endpoint with the local Spooler service disabled, there is no `\PIPE\spoolss` exposed to a low-privilege user. The architectural primitive's conjunct (a) -- the low-privilege RPC entry -- simply does not exist on that host.

Windows Protected Print Mode is the local-stack answer. It keeps the local Spooler service but restructures it: most operations are deferred to a Spooler Worker process with a restricted token, and the spooler refuses to load any driver DLL that is not Microsoft-signed [@ms-wpp-more-info] [@ms-wpp-canonical]. The architectural primitive's conjuncts (b) (caller-influenced DLL load) and partially (c) (SYSTEM context, for per-user operations) are broken.

Neither answer covers the union of constraints that a real Windows fleet faces. Universal Print requires cloud connectivity, Microsoft 365 / Entra ID licensing, and per-printer service costs. It does not work offline. It does not work for specialty printers (industrial label printers, healthcare imaging printers, secure check printers) that have no IPP-class-compatible firmware. WPP requires Mopria-certified printers or the small set of Microsoft-signed drivers that ship inbox. It does not work for the same specialty-printer category. The two answers cover different threat models, different licensing models, and different operational realities.

> **Key idea:** Windows Protected Print Mode and Universal Print are not redundant. They break different conjuncts of the architectural primitive, and together they cover what neither covers alone. The 2024 Windows print stack is a deliberate parallel architecture, not a transition state.

The WPP FAQ confirms the parallel-stack reading. When asked "Will Windows protected print mode ever be enabled by default?" the page answers verbatim: "Windows protected print mode will be enabled by default at a future date" [@ms-wpp-faq].<Sidenote>The "future date" phrasing in the WPP FAQ is preserved verbatim because it carries the entire commitment. Microsoft has published deprecation milestones for third-party drivers (January 15, 2026; July 1, 2026; July 1, 2027) [@ms-end-of-servicing], but it has not committed to a date for WPP-on-by-default. As of June 2026, "at a future date" is still the only formal commitment.</Sidenote>

### 5.5 The Conjunct Framing as Lead-in to Section 8

We can state the architectural argument compactly now and we will return to it formally in section 8. The architectural primitive has three conjuncts. (a) The service accepts low-privilege RPC. (b) It loads caller-influenced third-party DLLs. (c) It runs at SYSTEM. Any service of that shape produces a SYSTEM-execution primitive by construction. Microsoft's three shipped approaches each break exactly one conjunct:

<Mermaid caption="Figure 4: The three architectural exits from the Print Spooler primitive. PrintIsolationHost (2009) and WPP Spooler Worker (2024) break conjunct (c); WPP module blocking (2024) breaks conjunct (b); Universal Print (2021) breaks conjunct (a). The CERT/CC 2021 mitigation -- stop the Spooler service -- is the same exit as Universal Print, with larger collateral damage.">
flowchart LR
    PRIM["Architectural primitive<br/>(a) low-priv RPC entry<br/>(b) caller-influenced DLL load<br/>(c) SYSTEM context"]
    EXITA["Break (a) low-priv RPC entry"]
    EXITB["Break (b) caller-influenced DLL load"]
    EXITC["Break (c) SYSTEM context"]
    PRIM --> EXITA
    PRIM --> EXITB
    PRIM --> EXITC
    EXITA --> UP["Universal Print (2021)<br/>no local pipe spoolss"]
    EXITA --> CERT["Stop Spooler service<br/>(CERT/CC 2021)"]
    EXITB --> WPPMOD["WPP module blocking (2024)<br/>only Microsoft-signed drivers"]
    EXITC --> PIH["PrintIsolationHost (2009)<br/>partial: still LocalSystem"]
    EXITC --> WPPWORKER["WPP Spooler Worker (2024)<br/>restricted token, below SYSTEM IL"]
</Mermaid>

The remaining sections are about the design space Microsoft chose to occupy in 2024, why it occupies two points rather than one, and what is still missing in 2026 -- including, candidly, a satisfying answer for environments that cannot adopt either architectural exit.

## 6. State of the Art: Windows Protected Print Mode in 24H2

Windows Protected Print Mode shipped to Windows 11 24H2 on October 1, 2024 as an opt-in feature [@computerweekly-quocirca-wpp] [@ms-wpp-canonical]. As of June 2026 it is still opt-in. The WPP FAQ uses the verbatim phrase "at a future date" for when the default-on flip will happen [@ms-wpp-faq]. No date has been committed.

<Definition term="Windows Protected Print Mode (WPP)">
An opt-in Windows print stack introduced with Windows 11 24H2 (October 1, 2024) that exclusively uses the modern print stack, blocks all third-party printer drivers, runs normal spooler operations in a Spooler Worker process with a restricted token below SYSTEM integrity, and falls back to the inbox Microsoft IPP Class Driver for printer communication [@ms-wpp-canonical] [@ms-wpp-more-info]. Activation is by Group Policy ("Configure Windows protected print"), Intune (`./Device/Vendor/MSFT/Policy/Config/Printers/ConfigureWindowsProtectedPrint` via the Policy CSP for Printers [@ms-policy-csp-printers]), or registry [@ms-wpp-enterprises].
</Definition>

### 6.1 What WPP Changes

Microsoft's MORSE / Print team blog enumerates six concurrent changes [@ms-wpp-more-info]. Each one is interesting on its own; together they constitute the architectural exit.

**Spooler Worker process with restricted token.** Normal `spoolsv.exe` operations are deferred to a new Spooler Worker process. The worker runs with a restricted token that drops `SeTcbPrivilege` and `SeAssignPrimaryTokenPrivilege` and runs below SYSTEM integrity level. This is the operational form of "move the Spooler to a least privilege security model" from the MORSE quote.

<PullQuote>
"The new Spooler Worker process has a new restricted token that removes many privileges such as SeTcbPrivilege, SeAssignPrimaryTokenPrivilege, and no longer runs at SYSTEM IL." -- Microsoft Learn, More information on Windows Protected Print Mode [@ms-wpp-more-info]
</PullQuote>

That sentence, taken verbatim from Microsoft's own architecture documentation [@ms-wpp-more-info] [@ms-wpp-more-info-wayback], is the most concrete claim Microsoft has shipped about how WPP breaks conjunct (c). Two privileges enumerated, one integrity level reduced. The legacy `spoolsv.exe` process is still SYSTEM; the *worker* that does the per-job work is not.

**Module blocking.** APIs that previously allowed third-party module loading (`AddPrintProviderW` and similar) are gated by a module-blocking policy. The MORSE document states the new policy verbatim: "only Microsoft Signed binaries required for IPP are loaded" [@ms-wpp-more-info].

**XPS rendering per-user.** XPS rendering, historically a source of memory-corruption bugs in `PrintFilterPipelineSvc`, runs per-user instead of as SYSTEM. A memory-corruption bug in the XPS parser now compromises a user, not the machine.

**Process hardening on the Spooler Worker.** The Spooler Worker process is built with [Control Flow Guard](/blog/process-mitigation-policies-cfg-acg-cig-and-the-layer-betwee/), Control Flow Enforcement Technology (Intel CET shadow stack), Arbitrary Code Guard, Child Process Creation Disabled, and Redirection Guard enabled [@ms-wpp-more-info] [@msrc-redirectionguard-blog]. The MORSE blog explicitly says why the legacy spooler could not enable these mitigations: "many print drivers are decades old and are incompatible with modern security mitigations" [@ms-wpp-more-info].

**Point and Print restricted.** Point and Print can configure an IPP printer but cannot install a third-party driver. The MORSE document is verbatim: "Windows protected print mode prevents Point and Print from ever installing third-party drivers" [@ms-wpp-more-info]. That sentence is the architectural answer to the Generation 3 patch wave from section 4.3.

**Fallback to inbox IPP class driver.** Printing falls back to the Microsoft IPP Class Driver that ships with Windows. The driver works with Mopria-certified printers and with the Microsoft-signed driver subset [@mopria-certified-products] [@ms-modern-print-platform].

### 6.2 Mapping WPP to the Three Conjuncts

WPP breaks conjunct (b) by refusing to load anything that is not Microsoft-signed. It weakens conjunct (c) by moving the bulk of operations into a Spooler Worker with a restricted token below SYSTEM integrity. The low-privilege RPC entry (conjunct a) is preserved by design: the RPC interface still exists, clients still talk to it, but what they can ask the service to do is reduced.

That last asymmetry matters. WPP does not delete the `\PIPE\spoolss` endpoint. A WPP-enabled host still answers `RpcAddPrinterDriverEx` calls; it just refuses to load an unsigned driver in response. Detection rules that watched for the RPC call itself (the SigmaHQ Zeek-on-the-wire rule, for instance [@sigma-cve-2021-1675-zeek]) still see traffic on WPP hosts; rules that watched for the resulting unsigned DLL load (the SigmaHQ image-load rule [@sigma-cve-2021-1675-win-spooler]) should see audit events instead.

### 6.3 The Compatibility Envelope

WPP requires either a printer that the inbox IPP class driver can drive (a Mopria-certified printer in practice) or one of the small set of Microsoft-signed drivers. The Mopria Alliance certified-products directory lists a multi-vendor catalog of printers across Brother, Canon, HP, Epson, Lexmark, Xerox, and others [@mopria-certified-products]. The installed base of Mopria-certified printers is large.<Sidenote>The Mopria Alliance does not publish a single official total install-base count. The certified-products directory is the canonical inventory [@mopria-certified-products], and the industry-analyst framing in the December 2023 MORSE blog points to a multi-vendor catalog "covering many of the most common printer brands sold worldwide" [@ms-blog-secure-print-experience-4002645]. We report the order of magnitude (industry-wide) rather than a brittle exact count.</Sidenote>

Printers that require vendor-specific v3 drivers are not WPP-compatible by default. Industrial label printers (Zebra, Honeywell, SATO, TSC, Dymo) are the painful case. Their command languages (ZPL, EPL) are not part of the IPP class driver's repertoire [@ezeep-label-printers-wpp]. ezeep's June 2026 writeup is blunt: "Most thermal label printers... are not Mopria-certified, so they stop working when Windows Protected Print Mode is enforced. ZPL and EPL are not part of the IPP spec the IPP class driver speaks" [@ezeep-label-printers-wpp]. Three paths are open: keep WPP disabled on label workstations via GPO, refresh hardware to IPP-capable models, or use a cloud-rendered alternative.

Vendors that want WPP compatibility without a full IPP firmware conversion can ship Print Support Apps. Brother is one of the first vendors to publish a PSA [@brother-print-support-app]. Lexmark's vendor primary on the WPP transition documents the same path [@lexmark-wpp-support].

<Definition term="IPP class driver and Mopria certification">
The Microsoft-supplied inbox driver that uses the Internet Printing Protocol (IPP) to communicate with printers that implement the Mopria-Alliance-certified IPP everywhere subset. WPP-enforced clients use this driver instead of a vendor-specific driver. Printers must be Mopria-certified (or implement Mopria-compatible IPP) for the inbox driver to drive them [@mopria-certified-products] [@ms-modern-print-platform].
</Definition>

<Definition term="v3 vs v4 driver model">
The two pre-WPP Windows printer driver packaging models. v3 (Windows 2000 era) loads driver render code into the spooler process by default. v4 (Windows 8 era) is XPS-based, packaged for portability across architectures, and has a more limited print processor model. WPP deprecates both in favor of the inbox IPP class driver (or, transitionally, vendor Print Support Apps) [@ms-print-spooler-architecture] [@ms-end-of-servicing].
</Definition>

### 6.4 Deployment Surfaces and Detection Signals

WPP's enable / disable control is a binary two-state CSP. The Policy CSP page documents `Printers/ConfigureWindowsProtectedPrint` as accepting `0` (disabled, the 2026 default) or `1` (enabled), with no audit / monitor intermediate enum [@ms-policy-csp-printers]. The corresponding Group Policy path is "Computer Configuration > Administrative Templates > Printers > Configure Windows protected print" [@ms-wpp-enterprises]. CIS Benchmarks v5.0.1 (Windows 11) and v1.0.0 (Server 2025) treat the setting as a Level-2 hardening recommendation with the same binary registry value [@tenable-cis-w11-l2] [@tenable-cis-server-2025-l2].

<Sidenote>This is an important correction to a piece of folk wisdom about WPP. The Windows kernel and AppLocker have audit / enforce modes; AppControl for Business has audit / enforce modes; AMSI has logging tiers. WPP does not. Microsoft did not ship an "audit" enum on `ConfigureWindowsProtectedPrint`. Administrators who want pre-enforcement telemetry have to instrument it themselves, either by reading the existing `Microsoft-Windows-PrintService/Admin` event log (which carries Point and Print failures and module-load refusals regardless of whether WPP is on) or by deploying WPP to a pilot ring and watching the same log on those pilot machines. The deployment pattern is rollout rings, not an in-product audit mode.</Sidenote>

Because there is no in-product audit mode, the pre-enforcement signal is the existing print-services event log. The `Microsoft-Windows-PrintService/Admin` channel records driver-load failures, Point and Print restrictions, and plug-in load failures. Splunk Research's `spoolsv.exe` rule pack covers PrintService Admin Event ID 808 (plug-in load failure) paired with security log Event ID 4909 [@splunk-research-spoolsv-plugin-fail], and Event ID 316 for driver-add operations [@splunk-printnightmare-story] [@splunk-research-printnightmare-driver]. Redirection Guard mitigation events land in `Microsoft-Windows-Security-Mitigations/Operational` [@msrc-redirectionguard-blog]. The diagnostic Event ID 4098 (in the Application log) is the workhorse signal for Point and Print restrictions and predates WPP [@ms-event-ids-point-print].

> **Note:** The `ConfigureWindowsProtectedPrint` CSP has two states: `0` (disabled) and `1` (enabled). There is no in-product audit / monitor mode. The right deployment pattern is rings: pilot, broad-pilot, production. Pilot a small ring of representative endpoints with WPP enforced and watch `Microsoft-Windows-PrintService/Admin` events 316, 808, and 4098 for failed driver loads and Point and Print restrictions. Identify the printers that would fail. Decide between a fleet hardware refresh, a transitional Print Support App, or an exclusion list. Then expand the ring.

The probe below models a WPP-state PowerShell script in JavaScript for the runtime. It pretends the four signals (WPP policy state, Redirection Guard, recent PrintService Admin events, IPP class driver availability) are already retrieved; in production the values come from the Group Policy resultant set, `Get-ProcessMitigation`, `Get-WinEvent`, and `Get-PrinterDriver`.

<RunnableCode lang="js" title="WPP state probe (modelled in JS; original would be PowerShell)">{`
// Original PowerShell equivalents:
//   $wppPolicy = (Get-ItemProperty 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows NT\\Printers')
//                .ConfigureWindowsProtectedPrint  # 0 = disabled, 1 = enabled
//   $rg        = (Get-ProcessMitigation -Name spoolsv.exe).RedirectionTrust
//   $events    = Get-WinEvent -LogName 'Microsoft-Windows-PrintService/Admin' \
//                  -MaxEvents 200 | Where-Object { $_.Id -in 316,808,4098 -and \
//                  $_.TimeCreated -ge (Get-Date).AddDays(-7) }
//   $ipp       = (Get-PrinterDriver -Name 'Microsoft IPP Class Driver') -ne $null

const state = {
  wppPolicy: 0,                   // 0 = disabled, 1 = enabled (binary CSP)
  redirectionGuard: 'Enabled',    // 'Disabled' | 'Audit' | 'Enabled'
  recentPrintServiceFailures: 14, // count of EventID 316/808/4098 in last 7d
  inboxIppDriverPresent: true,
  deploymentRing: 'pilot'         // 'pilot' | 'broad-pilot' | 'production'
};

function classify(s) {
  if (s.wppPolicy === 0) {
    return s.deploymentRing === 'pilot'
      ? 'NotProtected: enable WPP on pilot ring and monitor PrintService/Admin'
      : 'NotProtected: WPP is disabled in ring ' + s.deploymentRing;
  }
  // wppPolicy === 1 means enforced; there is no audit/monitor intermediate
  const supportingMitigations =
    s.redirectionGuard === 'Enabled' && s.inboxIppDriverPresent;
  if (s.recentPrintServiceFailures > 0) {
    return 'Enforced: ' + s.recentPrintServiceFailures
      + ' PrintService/Admin failures in 7d. Investigate before expanding ring.';
  }
  return supportingMitigations
    ? 'Protected: WPP enforced, Redirection Guard on, IPP driver present'
    : 'Enforced: review Redirection Guard / IPP driver gaps';
}

console.log(classify(state));
`}</RunnableCode>

### 6.5 Redirection Guard

Redirection Guard is an independent process mitigation that ships separately from WPP but composes with it. It first arrived in Windows 11 22H2 in late 2023 and was the subject of a June 2025 MSRC blog post that documents its design [@msrc-redirectionguard-blog]. The mitigation is documented in the `PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY` Win32 API structure [@ms-redirection-trust-policy] and is invoked through `Set-ProcessMitigation -Name spoolsv.exe -Enable RedirectionGuard` [@ms-set-processmitigation].

The mechanism: a process opted into Redirection Guard refuses to follow filesystem junctions or symbolic links created by non-administrator users. The MSRC blog frames the scope plainly: "Junctions remain the biggest existing gap. Outside of a sandbox, they can be created by standard users and target any folder on the system" [@msrc-redirectionguard-blog]. The Risky Business bulletin on the launch documents the empirical impact: of forty-two filesystem-path-redirection CVEs Microsoft patched in 2024, thirty-two used attacker-created junctions and could have been blocked by Redirection Guard had it been in place [@risky-biz-redirectionguard].

Redirection Guard is the closest thing to a post-SpoolFool architectural fix in the legacy stack. WPP composes with it; a WPP-enabled host has both Redirection Guard on the legacy `spoolsv.exe` process and the additional CFG / CET / ACG / Child Process Creation Disabled / Redirection Guard set on the Spooler Worker [@ms-wpp-more-info].

### 6.6 A Failed PrintNightmare Attempt Against a WPP-Enabled Host

The sequence below shows what happens when a low-privilege user attempts the Generation 1 PrintNightmare exploit against a WPP-enabled host. The RPC entry point is still answered; the module load is refused; the audit log captures the attempt; the elevation does not happen.

<Mermaid caption="Figure 5: A failed PrintNightmare exploit attempt against a WPP-enabled host. The RPC call arrives, the spooler worker performs the driver-load attempt, the module-blocking signature check refuses the third-party DLL, and the audit event is logged. The attacker gains nothing; the defender sees the attempt.">
sequenceDiagram
    participant U as Low-priv user
    participant P as PIPE spoolss endpoint
    participant S as spoolsv.exe (parent)
    participant W as Spooler Worker (restricted token)
    participant L as Module loader
    participant V as Signature check
    participant E as PrintService Admin log
    U->>P: RpcAddPrinterDriverEx (unsigned DLL)
    P->>S: dispatch RPC call
    S->>W: forward driver-install to worker
    W->>L: load requested driver DLL
    L->>V: verify signature
    V-->>L: reject (not Microsoft-signed)
    L-->>W: load refused
    W->>E: write audit event 4098 (Point and Print failure)
    W-->>S: return access-denied
    S-->>U: STATUS_ACCESS_DENIED
    Note over U,W: No code runs as SYSTEM. Defender sees attempt in PrintService Admin.
</Mermaid>

WPP is a partial answer that covers a large fraction of the threat model and a smaller fraction of the printer install base. The size of that smaller fraction -- specialty printers without IPP-class compatibility -- is the largest open practical problem in 2026 Print Spooler security.

## 7. Competing Answers: Universal Print versus Windows Protected Print Mode

Microsoft did not ship one architectural answer to Print Spooler. It shipped two. They are not redundant. They cover different threat models and different operational realities, and they are designed to coexist.

### 7.1 Universal Print at One Glance

Universal Print became generally available on March 2, 2021 [@ms-365-blog-universal-print-2212333] [@ms-universal-print-fundamentals].<Sidenote>The exact March 2, 2021 GA date is industry knowledge anchored to Microsoft Ignite Spring 2021. The contemporaneous Microsoft 365 blog post [@ms-365-blog-universal-print-2212333] covers the wave but does not contain the verbatim date string. The Microsoft Learn fundamentals page documents the program's original `ms.date` of March 2, 2020 (one year before GA) [@ms-universal-print-fundamentals]. We cite both because each one supports a different facet of the same date.</Sidenote> The service moves the print queue to Microsoft 365 / Entra ID, removes the on-premises print server entirely, and removes the need for client-side third-party drivers. An optional on-prem connector lets the cloud service drive printers that are not directly cloud-aware [@ms-universal-print-whatis].

<Definition term="Universal Print">
Microsoft's cloud-hosted print service. Universal Print eliminates print servers like OneDrive eliminates file servers [@ms-universal-print-whatis]. The architectural exit it takes is breaking conjunct (a): a Universal-Print-only endpoint with the local Spooler service disabled has no `\PIPE\spoolss` exposed to a low-privilege user. Universal Print became generally available on March 2, 2021 [@ms-365-blog-universal-print-2212333] and reached GCC / GCC High in October 2023 [@ms-universal-print-government].
</Definition>

The architectural exit it takes is the one section 5 labelled (a): there is no `\PIPE\spoolss` endpoint exposed on a Universal-Print-only host. The endpoint is a Microsoft 365 service called MPSIPPService that runs at `https://print.print.microsoft.com/` [@ms-universal-print-getting-started]. Authentication is Entra ID OAuth2 / OIDC [@ms-universal-print-getting-started]. The threat model it removes is the local SMB-reachable low-privilege caller; the threat model it introduces is the cloud-account compromise.

### 7.2 The Cost of Universal Print

Universal Print is not free. It requires a Microsoft 365 / Entra ID license that includes the Universal Print entitlement. It requires network connectivity to print (the optional on-prem connector mitigates this for cached jobs; pure offline printing without the connector is not supported) [@ms-universal-print-getting-started]. It is per-user / per-printer in cost. The compatibility envelope is the IPP class driver plus the connector's translation surface; vendor-specific drivers are not part of the cloud service.

Universal Print is available in commercial Microsoft 365 tenants and, as of October 2, 2023, in the GCC and GCC High government clouds. The fundamentals page records "Universal Print is FedRamp certified by Office 365 and is now available in GCC, GCC High, and DoD environments" [@ms-universal-print-government].

The threat model Universal Print does not cover: an attacker who can reach Microsoft 365 / Entra ID tokens has cloud-side access, not local-spooler access. The PrintNightmare-class attack is moved off the endpoint; a different attack class (cloud-token compromise, mailbox compromise, OAuth phishing) takes its place. Universal Print does not, on its own, harden the surface; it relocates the surface to a cloud the customer outsources.

### 7.3 Head-to-Head

The trade-offs are easiest to compare in scannable form:

| Aspect | Universal Print | Windows Protected Print Mode |
|---|---|---|
| Architectural exit | Breaks conjunct (a): no local pipe spoolss | Breaks (b) and partially (c): no third-party drivers, Spooler Worker below SYSTEM IL |
| Deployment model | Cloud-hosted M365 service; optional on-prem connector | Local Windows feature, GPO / Intune toggle |
| Driver requirement | None on client; connector translates server-side | Microsoft IPP class driver or Microsoft-signed driver; Print Support Apps as transitional |
| Offline support | None native; on-prem connector required | Yes (local printing continues) |
| License requirement | M365 / Entra ID with Universal Print entitlement | None beyond Windows 11 24H2 |
| Threat model covered | Removes the architectural primitive from the local host | Removes third-party-driver and SYSTEM-context surfaces |
| Threat model NOT covered | Cloud-side token / account compromise | The RPC entry point still exists; specialty printers still require legacy stack |
| Default state in 2026 | Opt-in (license-gated) | Opt-in (Group Policy off by default) |

### 7.4 The Composition Pattern

WPP and Universal Print can run on the same client. A managed enterprise endpoint can use Universal Print for its enrolled shared printers (cloud-mediated) and WPP for its locally-discovered printers (driverless local stack). Microsoft's documented stance is that this composition is the long-term direction. The WPP FAQ's "at a future date" language about default-on [@ms-wpp-faq] and the third-party-driver end-of-servicing milestones [@ms-end-of-servicing] together sketch a 2027-and-after world: WPP locally, Universal Print for cloud-enrolled printers, legacy stack restricted to specialty hosts that explicitly opt out.

<Aside label="Why Microsoft is not deprecating the local stack">
A complete migration to Universal Print would force every Windows user to require Microsoft 365 entitlements and continuous network connectivity to print. That is a price Microsoft has not been willing to ask the global Windows install base to pay. WPP is the answer for endpoints that print locally; Universal Print is the answer for endpoints that print to enrolled shared printers; the parallel-stack architecture is the answer to the union. As of June 2026, no Microsoft document announces a date at which the local stack will be removed.
</Aside>

The composed architecture in one picture:

<Mermaid caption="Figure 6: Universal Print and WPP as parallel architectures on a managed Windows endpoint. Universal Print handles enrolled shared printers via the cloud service; WPP handles locally discovered printers via the inbox IPP class driver and the restricted-token Spooler Worker. The legacy stack remains available for endpoints that explicitly opt out for specialty hardware.">
flowchart LR
    subgraph EP["Managed Windows endpoint"]
        APP["User application"]
        WIN["winspool.drv"]
        SPL["spoolsv.exe"]
        WORKER["Spooler Worker<br/>restricted token"]
        UPCLI["Universal Print client"]
    end
    subgraph CLD["Microsoft 365 cloud"]
        UPSVC["Universal Print service<br/>MPSIPPService"]
        CONN["Optional on-prem connector"]
    end
    subgraph LOC["Locally discovered printers"]
        IPP["Mopria / IPP printer"]
        SPEC["Specialty printer<br/>(opt-out path)"]
    end
    APP --> WIN
    WIN --> SPL
    SPL --> WORKER
    WORKER --> IPP
    SPL -. opt-out .-> SPEC
    APP --> UPCLI
    UPCLI --> UPSVC
    UPSVC --> CONN
    CONN --> IPP
</Mermaid>

Two answers, deliberately. We promised in section 1 that we would not tell you which one to deploy. We are keeping that promise. The next section is about why no third answer covers the gap.

## 8. Theoretical Limits: The Architectural Impossibility Argument

We can state the architectural-impossibility claim formally now. It is bounded, it has been bounded for fifteen years on this artifact, and it is sharp enough to act on.

### 8.1 The Three-Conjunct Primitive

Any local service that simultaneously satisfies three conditions exposes a SYSTEM code-execution primitive by construction:

- (a) accepts low-privilege RPC,
- (b) loads caller-influenced third-party DLLs as part of those requests, and
- (c) runs at SYSTEM context.

The primitive is independent of any particular implementation bug. Particular implementation bugs are how the primitive is exercised. The primitive itself is what makes those bugs exploitable.

> **Key idea:** Any local service that simultaneously accepts low-privilege RPC, loads caller-influenced DLLs, and runs at SYSTEM context exposes a SYSTEM code-execution primitive by construction. No patch on individual entry points can close the class. The class is closed only by breaking one of the three conjuncts.

The argument is not an empirical generalization. It is a structural one. Given (a), (b), and (c), the attacker's path to SYSTEM-execution is a finite search problem: enumerate the entry points that load DLLs, find one whose DLL-load arguments the attacker can steer, supply an attacker-supplied DLL. The defender's only options are to remove one of the conjuncts. Patching individual entry points moves the search problem; it does not eliminate it. The 2021-2024 patch cascade is the empirical record of that move-but-not-eliminate dynamic.

### 8.2 The Three Exits

Each shipped architectural approach breaks exactly one conjunct.

**Break (c), the SYSTEM context.** PrintIsolationHost.exe shipped in 2009 as a partial answer: drivers can run in a sibling process, but that sibling process is itself LocalSystem by default [@ms-printer-driver-isolation]. WPP's Spooler Worker (2024) is more complete: a restricted token, below SYSTEM integrity level, for the bulk of per-user spooler operations [@ms-wpp-more-info].

**Break (b), the caller-influenced DLL load.** WPP module blocking (2024) refuses to load anything except Microsoft-signed binaries required for IPP [@ms-wpp-more-info]. The conjunct is no longer "loads caller-influenced DLLs"; it is "loads only Microsoft-signed DLLs the OS shipped."

**Break (a), the low-privilege RPC entry.** Universal Print (2021) removes the local `\PIPE\spoolss` endpoint from the endpoint's surface [@ms-universal-print-whatis]. The CERT/CC 2021 mitigation -- stop and disable the Spooler service -- is the same architectural exit with larger collateral damage (no local printing at all) [@cert-vu-383432].

### 8.3 What No Exit Covers

The intersection of constraints that no shipped exit covers: specialty printers that require v3 or v4 drivers, on a host that needs offline printing, on a non-managed endpoint, in an environment that cannot adopt cloud printing. Industrial label printers, secure check printers, and healthcare imaging devices are the canonical examples [@ezeep-label-printers-wpp]. This intersection is the empirical gap that justifies the parallel-stack answer in 2026 and the absence of a default-on commitment for WPP [@ms-wpp-faq].

### 8.4 The Argument as a Lower Bound

The three-conjunct argument is a *lower bound on bug class*, not a *security analysis*. It says the architectural primitive cannot be made safe without breaking one of the conjuncts. It does not say that a specific implementation of an exit is itself secure. WPP could ship a bug. The Microsoft-signed module loader could have a parser vulnerability. The Spooler Worker process could be coerced into elevation through some intermediate IPC channel; that channel is itself a research question we return to in section 9.4. The architectural argument bounds what *kind* of bugs are still possible. It does not promise that no bugs will be.

<Aside label="The 1970s capability-systems precedent">
The "service that loads caller-influenced code in a privileged context produces a privilege-escalation primitive by construction" pattern predates Windows. The capability-systems literature of the 1970s -- Hydra, KeyKOS, and the related work that gave us Mandatory Integrity Control as a Windows feature decades later -- worked through the same argument in different language. Confused-deputy attacks (the Hardy formulation) are exactly the case where a privileged process performs an operation on behalf of a less-privileged caller and the operation cashes out at the privileged process's authority. PrintNightmare is a confused-deputy primitive on `spoolsv.exe`. The architectural exits in section 5 are confused-deputy mitigations: revoke the deputy's authority (Universal Print breaks delegation entirely), confine what the deputy is willing to do (WPP module blocking), or split the deputy into a privileged broker and an unprivileged worker (WPP Spooler Worker).
</Aside>

Fifteen years of Print Spooler CVEs have produced a single argument with three corollaries. It is not new. It is not Microsoft's. It has been latent in the academic literature on capability systems since the 1970s. What is new in 2024 is that it shipped, in two flavors, on consumer Windows.

## 9. Open Problems

Three years after Microsoft shipped the architectural answer, the Print Spooler security story is not complete. We end with five open problems, presented without recommendation.

### 9.1 WPP Adoption Velocity Through the Opt-In Tail

No default-on commitment exists. The WPP FAQ uses the verbatim phrase "at a future date" for the default-on flip [@ms-wpp-faq]. As of June 2026, opt-in adoption is reported only anecdotally; Microsoft has not published telemetry. The three published deprecation milestones are real and dated -- January 15, 2026 (no new third-party drivers via Windows Update), July 1, 2026 (Windows IPP class driver preferred over third-party drivers for new printer installs), July 1, 2027 (third-party servicing ends except for security fixes) [@ms-end-of-servicing] -- but they do not equal "WPP is on by default."

The Lexmark vendor primary on the WPP transition spells out the operational reading from the printer-OEM perspective: "WPP is disabled by default until 2027... January 2026: no new third-party drivers published via Windows Update; July 2026: Windows defaults to IPP Class Driver when adding devices; July 2027: no updates for third-party drivers except security fixes" [@lexmark-wpp-support]. The OEMs are reading the milestones as a 2027 horizon for the default-on flip. Microsoft has not, in writing, confirmed that reading.

A negative-search finding sharpens the gap. The trade press that tracks Microsoft security launches (BleepingComputer's unveil coverage [@bleepingcomputer-wpp-unveil] and its dedicated WPP tag page [@bleepingcomputer-tag-wpp], BornCity's April 2026 Patch Tuesday print-issues report [@borncity-april-2026-patchday]), the Microsoft Tech Community discussion threads (the 2024 WPP intro discussion [@techcommunity-discuss-msec-print-4008206] and the Ignite 2024 Windows-security companion [@techcommunity-discuss-ignite-2024-4304464]), analyst output (the MPSA member eBook [@mpsa-wpp-ebook], Quocirca's vendor-published commentary [@computerweekly-quocirca-wpp]) -- none of these surface a quantitative WPP adoption number. Microsoft has not published telemetry, third-party analysts have not estimated it, and OEM disclosures cover hardware compatibility, not enterprise enablement rates. The gap is not a measurement difficulty; it is an absence in the public record.

### 9.2 The Specialty-Printer Gap

v3 / v4 driver printers without IPP-class compatibility still exist in production. Industrial label printers, healthcare imaging printers, secure check printers, line-printer holdouts. The honest answer is that these endpoints cannot adopt WPP and cannot adopt Universal Print and they will continue to run a legacy spooler. The defense for them is segmentation, not patching.

Print Support Apps help bridge some categories. The PSA design guide is the canonical specification [@ms-print-support-app-design-guide]. A walk through the Microsoft Store [@apps-microsoft-store-root] surfaces a sampled (not exhaustive) roster of vendor PSAs available as of June 2026: Brother's PSA was one of the first to ship [@brother-print-support-app] [@brother-support-page]; Canon Print Assistant covers Canon's IPP-everywhere subset [@canon-print-assistant-psa]; HP Smart bridges HP's IPP-everywhere set [@hp-smart-psa]; Konica Minolta's bizhub PSA covers the bizhub series [@konica-bizhub-psa]; Xerox and Lexmark co-publish a joint PSA [@xerox-lexmark-psa] [@lexmark-wpp-support]. The cloud-print intermediaries ezeep document the operational reality for the categories the PSA model does not cover: industrial label printers (Zebra, Honeywell, SATO, TSC, Dymo) speaking ZPL / EPL are absent from the Mopria-certified IPP-everywhere catalogue and from the Microsoft-Store PSA roster as of June 2026 [@ezeep-label-printers-wpp]. For those vendors the operational guidance is to keep WPP disabled on the affected workstations and to segment them off the production network.

### 9.3 CVE-2024-38198: Attribution and PoC Gap

No public researcher is named in any primary source for CVE-2024-38198. No public PoC exists [@wiz-cve-2024-38198] [@rapid7-cve-2024-38198]. The bug was found, patched, and remained unattributed. This is not necessarily a problem -- silent fixes are normal in vendor patch flow -- but it is a data point: the bug class is still being mined three years after the disclosure event, and the public-research apparatus has not surfaced the next finding.

> **Note:** CVE-2024-38198, patched on August 13, 2024, has no public researcher attribution and no public PoC as of June 2026 [@wiz-cve-2024-38198] [@rapid7-cve-2024-38198]. It is the most recent named Print Spooler EoP in the public record. Its existence is the empirical proof point that the legacy spooler is still producing novel CWE-class bugs three years after PrintNightmare.

### 9.4 The spoolsv-to-Spooler-Worker IPC Primitive

WPP's per-user worker model introduces an IPC channel between the parent `spoolsv.exe` service and the Spooler Worker process [@ms-wpp-more-info]. Microsoft documents the worker's restricted token in detail (see the verbatim quote in section 6.1: "no longer runs at SYSTEM IL" [@ms-wpp-more-info] [@ms-wpp-more-info-wayback]) but does not, in public, document the IPC primitive itself. The absence is the load-bearing finding.

<Sidenote>The Windows kernel offers at least four plausible IPC mechanisms that a service like the spooler could use to dispatch work to a per-user worker: an [Advanced Local Procedure Call (ALPC)](/blog/every-uac-prompt-is-an-alpc-handshake-a-field-guide-to-windo/) port, a named pipe (the same family `\PIPE\spoolss` is from), a COM activation under RPC, or a shared-memory section with notification. Each has a different attack surface. ALPC ports are not directly named in the filesystem but are reachable through documented APIs; named pipes inherit the SMB and named-pipe-anonymous policy plane [@ms-named-pipes-anonymous] [@ms-restrict-anonymous-named-pipes]; COM-RPC inherits the COM permission DACL surface; shared-memory sections inherit the section-object DACL surface. Per-user services in Windows (the per-user-services framework Microsoft introduced in 1709) typically use ALPC or named pipes for parent / worker dispatch [@ms-per-user-services]. Which mechanism WPP uses, and what authentication the parent demands of the worker (and vice versa), is the specific research question. As of June 2026 it is unanswered in the public record.</Sidenote>

If that channel is itself coercible (TOCTOU on the IPC, redirection-style attacks on a worker named pipe), WPP may exhibit a SpoolFool-class bug at a different layer. Redirection Guard partially answers the obvious junction-following attack on the worker [@msrc-redirectionguard-blog] [@ms-redirection-trust-policy], but the worker has other IPC handles, and the worker's restricted token still has authority over operations the parent has delegated to it. No public research has surfaced an IPC-channel exploit as of June 2026. The research surface here is real and only loosely mapped.

### 9.5 Detection Signal Coverage for the Post-WPP Era

SigmaHQ, Splunk Security Content, Elastic, and Microsoft Defender XDR all ship rules for the PrintNightmare-era event signatures. SigmaHQ's PrintNightmare rule pack covers the PoC DLL load pattern (`win_exploit_cve_2021_1675_printspooler.yml`, rule ID `4e64668a-4da1-49f5-a8df-9e2d5b866718`) [@sigma-cve-2021-1675-win-spooler]. The Zeek-on-the-wire DCE-RPC rule (ID `7b33baef-2a75-4ca3-9da4-34f9a15382d8`) watches both MS-RPRN's `RpcAddPrinterDriverEx` and MS-PAR's `RpcAsyncAddPrinterDriver` [@sigma-cve-2021-1675-zeek]. Splunk's research-team detection on `Microsoft-Windows-PrintService/Admin` event code 316 (driver-add) carries the rule ID `313681a2-da8e-11eb-adad-acde48001122` and maps to MITRE ATT&CK technique T1547.012 (Print Processors) [@splunk-research-printnightmare-driver] [@splunk-printnightmare-story] [@attack-mitre-t1547-012]. Splunk's `spoolsv.exe`-focused rule pack adds: plug-in loading failure detection (`1adc9548-da7c-11eb-8f13-acde48001122`, PrintService Admin Event 808 and security log Event 4909) [@splunk-research-spoolsv-plugin-fail]; [Sysmon](/blog/from-cmdexe-to-a-kusto-row-in-90-seconds-how-sysmon-and-defe/) Event ID 11 spool-folder DLL writes (`347fd388-da87-11eb-836d-acde48001122`) [@splunk-research-spoolsv-dll-sysmon]; Sysmon Event ID 7 loaded-modules signal on `spoolsv.exe` (`a5e451f8-da81-11eb-b245-acde48001122`) [@splunk-research-spoolsv-loaded-modules]; Sysmon Event ID 10 process-access signal on `spoolsv.exe` (`799b606e-da81-11eb-93f8-acde48001122`) [@splunk-research-spoolsv-process-access]. Elastic's prebuilt rule "Unusual Print Spooler Child Process" catches the post-exploit child-process spawn pattern (risk score 47) [@elastic-unusual-printspooler-child]. Azure Sentinel's KQL hunting query for PrintNightmare watches file creations in the print-spooler drivers folder (`C:\WINDOWS\SYSTEM32\SPOOL\drivers`) [@azure-sentinel-printnightmare-yaml].

Coverage for the WPP era is sparser, and the gap has a specific shape: because WPP has **no in-product audit mode** -- the `ConfigureWindowsProtectedPrint` CSP is the binary two-state setting documented in section 6.4 [@ms-policy-csp-printers] [@tenable-cis-w11-l2] -- pre-enforcement detection has to be synthesized from the existing PrintService Admin and Sysmon event signals (Event 316 driver-adds, 808 / 4909 plug-in failures, Sysmon 7 / 10 / 11 on `spoolsv.exe`) plus SCM service-state events (System log Event ID 7036 records spooler service start / stop transitions). Redirection Guard mitigation events appear in `Microsoft-Windows-Security-Mitigations/Operational` [@msrc-redirectionguard-blog]. IPC-related signals on the Spooler Worker do not have public detection content as of June 2026. The audit-without-audit-mode pattern is well understood by detection engineers running PrintNightmare content already; the synthesis work to compose it into a WPP rollout-ring playbook is the gap detection content vendors have not yet closed.

Five open problems. None of them are emergencies. All of them are reasons that a 2026 security program for Print Spooler is still a security program for Print Spooler, not an absence.

## 10. Practical Guide: What a Defender Does in 2026

We end with what a Windows administrator with print infrastructure should actually do in 2026. Four tiers, each with its own action list, none of them long.

### 10.1 Tier 1: Managed Enterprise with Cloud Workflows

For organizations already on Microsoft 365 with Entra-joined endpoints and cloud-friendly printers:

1. Adopt Universal Print for shared printers [@ms-universal-print-whatis] [@ms-universal-print-getting-started].
2. Adopt WPP on a pilot ring of managed endpoints (`ConfigureWindowsProtectedPrint = 1`); WPP has no in-product audit mode, so the deployment pattern is rings, not audit-then-enforce [@ms-wpp-enterprises] [@ms-policy-csp-printers] [@tenable-cis-w11-l2].
3. Verify Redirection Guard is enabled on `spoolsv.exe` [@ms-set-processmitigation] [@ms-redirection-trust-policy].
4. Verify the September 2021 default Point-and-Print policy is in force: `RestrictDriverInstallationToAdministrators=1` [@kb-5005652-topic].

### 10.2 Tier 2: Managed Enterprise Without Cloud Workflows

For organizations with on-prem print infrastructure and no Universal Print appetite:

1. Deploy WPP to a pilot ring of managed endpoints (`ConfigureWindowsProtectedPrint = 1`) and watch `Microsoft-Windows-PrintService/Admin` for 30 or more days [@ms-wpp-enterprises] [@ms-policy-csp-printers] [@tenable-cis-server-2025-l2].
2. After the pilot, expand the ring to the subset of endpoints whose printers are Mopria-certified [@mopria-certified-products].
3. For non-Mopria printers, segment to dedicated print VLANs and enforce the September 2021 admin-only default [@kb-5005652-topic].
4. Verify Redirection Guard on `spoolsv.exe` on all spooler-bearing hosts [@msrc-redirectionguard-blog].

### 10.3 Tier 3: Specialty, Industrial, Regulated

For organizations whose print fleet includes specialty hardware (label printers, secure check printers, healthcare imaging):

1. Segment Spooler-bearing endpoints onto dedicated VLANs with restricted inbound RPC reachability [@ms-windows-firewall-overview].
2. Where possible, enforce the CERT/CC 2021 guidance on domain controllers (Spooler disabled); CISA's required actions for the same hosts now flow through BOD 22-01 KEV remediation after the January 2026 closure of ED 21-04, but the DC-disabled baseline is unchanged [@cert-vu-383432] [@cisa-ed-21-04].
3. Apply the September 2021 admin-only Point and Print default on every host [@kb-5005652-topic].
4. Subscribe to MSRC notifications for the affected SKUs [@msrc-cve-2021-34527].
5. Plan a multi-year IPP / PSA migration path; track vendor PSA availability [@brother-print-support-app] [@canon-print-assistant-psa] [@hp-smart-psa] [@konica-bizhub-psa] [@xerox-lexmark-psa] [@lexmark-wpp-support] [@ms-print-support-app-design-guide].

### 10.4 Tier 4: Print Server or Domain Controller Specifically

For hosts that are themselves print servers or domain controllers:

1. Spooler off where possible. CERT/CC's 2021 guidance remains in force; CISA closed ED 21-04 in January 2026 and folded its requirements into BOD 22-01 (KEV-catalog remediation), but the practical effect on a domain controller is unchanged [@cert-vu-383432] [@cisa-ed-21-04]. SCM service state-changes appear in the System event log under Event ID 7036 (service start / stop transitions); alert on unexpected `Print Spooler` Event 7036 entries on hosts where the service should remain stopped.
2. Where Spooler-off is impossible, isolate the host, restrict `\PIPE\spoolss` exposure at the firewall, and harden the named-pipe-anonymous policies (`RestrictNullSessAccess = 1`; `spoolss` absent from `NullSessionPipes`) [@ms-restrict-anonymous-named-pipes] [@ms-named-pipes-anonymous] [@ms-ad-firewall-ports].
3. Log MS-RPRN and MS-PAR calls; alert on `RpcAddPrinterDriverEx` and `RpcAsyncAddPrinterDriver` invocations from non-administrator SIDs [@sigma-cve-2021-1675-zeek]. The canonical event-log signals to instrument are: PrintService Admin Event ID 316 (driver-add) [@splunk-research-printnightmare-driver]; PrintService Admin Event ID 808 (spooler plug-in load failure) paired with security log Event ID 4909 [@splunk-research-spoolsv-plugin-fail]; Sysmon Event ID 7 (loaded modules on `spoolsv.exe`) [@splunk-research-spoolsv-loaded-modules]; Sysmon Event ID 10 (process access on `spoolsv.exe`) [@splunk-research-spoolsv-process-access]; Sysmon Event ID 11 (spool-folder DLL writes under `C:\WINDOWS\SYSTEM32\SPOOL\drivers`) [@splunk-research-spoolsv-dll-sysmon] [@azure-sentinel-printnightmare-yaml].
4. Confirm Redirection Guard is enabled on `spoolsv.exe` and watch `Microsoft-Windows-Security-Mitigations/Operational` for mitigation events [@msrc-redirectionguard-blog].

> **Note:** CISA Emergency Directive 21-04, issued July 13, 2021, mandated that federal civilian agencies stop and disable the Print Spooler service on Active Directory domain controllers [@cisa-ed-21-04]. CISA closed ED 21-04 in January 2026 and transitioned its required actions to BOD 22-01 (Reducing the Significant Risk of Known Exploited Vulnerabilities). The compliance vehicle changed; the operational outcome did not. Agencies that have not adopted Universal Print on their DC infrastructure should still keep Spooler stopped and disabled on every DC.

<Aside label="Detection rule packs by ID">
For detection engineers, the named-rule packs to start from are: SigmaHQ `4e64668a-4da1-49f5-a8df-9e2d5b866718` (PrintService Admin Event 808 PoC DLL-load failure) [@sigma-cve-2021-1675-win-spooler]; SigmaHQ `7b33baef-2a75-4ca3-9da4-34f9a15382d8` (Zeek DCE-RPC wire-level driver install) [@sigma-cve-2021-1675-zeek]; Splunk story `fd79470a-da88-11eb-b803-acde48001122` (PrintNightmare analytic story, production status) [@splunk-printnightmare-story]; Splunk research `313681a2-da8e-11eb-adad-acde48001122` (PrintService Admin Event Code 316 driver-add) [@splunk-research-printnightmare-driver]; Elastic prebuilt rule "Unusual Print Spooler Child Process" (EQL, risk 47) [@elastic-unusual-printspooler-child]; Azure Sentinel hunting query `8f404352-c4ff-44d1-8d70-c50ee2fad8f8` (DeviceFileEvents in spool drivers folder) [@azure-sentinel-printnightmare-yaml]. Jacob Baines's DEF CON 29 "Bring Your Own Print Driver Vulnerability" [@defcon-29-baines-pdf] and the companion `concealed_position` repository [@baines-concealed-position] are the canonical reference for the BYOV attack class, which detection rule packs for installed-driver behavior also need to model.
</Aside>

The unifying pattern across the tiers: enforce the September 2021 default, enable Redirection Guard, audit WPP on the way to enforcement, and segment what cannot be migrated. The architectural answer to PrintNightmare exists. The operational answer is to use it.

## 11. Frequently Asked Questions

<FAQ title="Frequently asked questions">

<FAQItem question="Was PrintNightmare one CVE?">
No. The press attached the name to a sequence. CVE-2021-1675 (June 8, 2021) was originally classed as a local EoP, then silently reclassified to RCE on June 21 [@nvd-cve-2021-1675] [@bleepingcomputer-domain-takeover]. CVE-2021-34527 (July 1, 2021) was the separate-bulletin out-of-band assignment for the RCE primitive Sangfor's PoC actually exploited [@nvd-cve-2021-34527] [@cert-vu-383432]. CVE-2021-34481 (July 15, 2021) was a related local EoP fixed in KB5005652 [@nvd-cve-2021-34481] [@kb-5005652-topic]. CVE-2021-36958 (September 14, 2021) was the next-cycle Print Spooler RCE [@nvd-cve-2021-36958]. Several adjacent bugs (CVE-2022-21999 SpoolFool, CVE-2024-38198) are often called "PrintNightmare-class" without being assigned the name themselves [@nvd-cve-2022-21999] [@wiz-cve-2024-38198].
</FAQItem>

<FAQItem question="Who wrote the original PrintNightmare PoC?">
The proof-of-concept that triggered the disclosure event on June 29, 2021 was written by Zhiniang Peng, Xuefeng Li, and Lewis Lee at Sangfor Technology for their Black Hat USA 2021 briefing "Diving Into Spooler" [@infocondb-bh2021-sangfor] [@afwu-wayback-snapshot]. They published it briefly believing the bug had been patched on June 8; the patch turned out to cover only the synchronous MS-RPRN entry point [@nvd-cve-2021-1675]. A second variant against the asynchronous MS-PAR `RpcAsyncAddPrinterDriver` was published shortly after by the researcher `@cube0x0` [@cube0x0-cve-2021-1675] [@cert-vu-383432]. The CERT/CC disclosure-norms advisory VU#383432 was a separate document by Will Dormann about the disclosure failure itself, not the bug [@cert-vu-383432].
</FAQItem>

<FAQItem question="Is SpoolFool a Win32k integrity-level bypass?">
No. SpoolFool (CVE-2022-21999, disclosed February 8, 2022 by Oliver Lyak / `@ly4k_` of SafeBreach Labs) is a Print Spooler local privilege escalation that abuses the printer `SpoolDirectory` registry value and NTFS reparse points, classified as CWE-59 (Link Following) [@nvd-cve-2022-21999] [@ly4k-spoolfool]. Win32k is the GUI subsystem and is uninvolved. The researcher handle is `@ly4k_` with a trailing underscore; `@jonas_lyk` is a distinct researcher.
</FAQItem>

<FAQItem question="Is CVE-2024-38198 a Point and Print bypass?">
No, and it is not from March 2024 either. CVE-2024-38198 (August 13, 2024 Patch Tuesday) is a Print Spooler Elevation of Privilege Vulnerability classified as CWE-345 Insufficient Verification of Data Authenticity [@wiz-cve-2024-38198] [@rapid7-cve-2024-38198]. Exploitation requires winning a race, but the CWE is 345, not 362, and Microsoft did not name Point and Print as the affected component. CVSS v3.1 base 7.5 (`AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H`) [@wiz-cve-2024-38198]. No public PoC and no public researcher attribution exist as of June 2026.
</FAQItem>

<FAQItem question="Why does Microsoft not just sandbox spoolsv.exe?">
Because the third-party printer-driver install base assumes drivers are loaded into a LocalSystem-context process. Sandboxing the spooler would break compatibility with the v3 and v4 driver model that the entire pre-2024 printer install base ships against [@ms-printer-driver-isolation] [@ms-print-spooler-architecture]. Microsoft's chosen architectural exits (Windows Protected Print Mode and Universal Print) sidestep the constraint by either restricting which DLLs the spooler will load (WPP module blocking plus the lower-privilege Spooler Worker) or removing the local spooler from the workflow entirely (Universal Print) [@ms-wpp-more-info] [@ms-wpp-canonical] [@ms-universal-print-whatis].
</FAQItem>

<FAQItem question="Does enabling Universal Print fix PrintNightmare?">
For endpoints that print only through Universal Print and where the local Spooler service is disabled, yes. The `\PIPE\spoolss` RPC entry point is not exposed and the architectural primitive is broken [@ms-universal-print-whatis] [@ms-universal-print-getting-started]. Most enterprise deployments are mixed (Universal Print for some workflows, local Spooler for others), in which case the PrintNightmare risk surface is reduced but not eliminated. Universal Print does not automatically disable the local Spooler.
</FAQItem>

<FAQItem question="Was there a Tas Giakouminakis talk at Black Hat 2021 on PrintNightmare?">
We can find no record of one. The Sangfor "Diving Into Spooler" talk on August 4, 2021 at Black Hat USA 2021 is the canonical primary-source talk for the technique [@infocondb-bh2021-sangfor]. Jacob Baines's DEF CON 29 (August 2021) talk "Bring Your Own Print Driver Vulnerability" is a related contemporary talk worth citing if you have heard the Giakouminakis attribution and are trying to track down its source [@defcon-29-baines-pdf] [@baines-concealed-position].

<Spoiler kind="solution" label="Where to find the actual primary talks">
The Sangfor Black Hat USA 2021 session record (presenters, time, abstract) is preserved on InfoconDB at `infocondb.org/con/black-hat/black-hat-usa-2021/diving-into-spooler-discovering-lpe-and-rce-vulnerabilities-in-windows-printer` [@infocondb-bh2021-sangfor]. Jacob Baines's DEF CON 29 slides are mirrored at `media.defcon.org/DEF CON 29/DEF CON 29 presentations/Jacob Baines - Bring Your Own Print Driver Vulnerability.pdf` [@defcon-29-baines-pdf], and the companion `concealed_position` GitHub repository documents the four-CVE driver exploit set (ACIDDAMAGE / RADIANTDAMAGE / POISONDAMAGE / SLASHINGDAMAGE) [@baines-concealed-position].
</Spoiler>
</FAQItem>

</FAQ>

<StudyGuide slug="print-spooler-three-generations-of-printnightmare" keyTerms={[
  { term: "spoolsv.exe", definition: "The Windows Print Spooler API server, running as LocalSystem, that loads third-party Print Provider, Print Processor, and printer driver DLLs into its address space. The architectural protagonist of every named Print Spooler CVE 2010-2024." },
  { term: "Print Provider DLL chain", definition: "The three router-loaded DLLs that dispatch print operations to the appropriate transport: localspl.dll (Local), win32spl.dll (Remote), inetpp.dll (HTTP/IPP). Often confused with the Print Processor layer; the Provider handles which printer, the Processor handles how to render the page." },
  { term: "Print Processor (winprint.dll)", definition: "The component that interprets the spool file format (EMF, XPS, RAW, TEXT) and renders pages for a specific printer. winprint.dll is the default. A separate layer from the Print Providers." },
  { term: "MS-RPRN and MS-PAR", definition: "Microsoft's synchronous (MS-RPRN) and asynchronous (MS-PAR) print-system RPC protocols. Both bind to the named pipe PIPE spoolss. The MS-PAR spec verbatim describes RpcAsyncAddPrinterDriver as the counterpart of MS-RPRN's RpcAddPrinterDriverEx." },
  { term: "Point and Print", definition: "Windows behavior in which a non-admin user causes their machine to download and install a printer driver from a print server on first use. Governed by the registry values NoWarningNoElevationOnInstall, NoWarningNoElevationOnUpdate, and overridden by RestrictDriverInstallationToAdministrators." },
  { term: "PrintIsolationHost.exe", definition: "Sibling host process introduced in Windows 7 / Server 2008 R2 (October 22, 2009) that can load third-party printer driver code outside spoolsv.exe. The isolation is process isolation, not privilege isolation; the host runs as LocalSystem by default." },
  { term: "AppContainer", definition: "A Windows process sandboxing primitive with a custom integrity level, a restricted token, and a set of explicitly granted capabilities. Microsoft has not deployed AppContainer to spoolsv.exe because of the back-compat constraint with v3/v4 drivers." },
  { term: "Windows Protected Print Mode (WPP)", definition: "An opt-in Windows print stack introduced with Windows 11 24H2 (October 1, 2024) that blocks all third-party drivers, runs normal operations in a Spooler Worker process with a restricted token below SYSTEM integrity, and falls back to the inbox Microsoft IPP Class Driver." },
  { term: "IPP class driver / Mopria certification", definition: "The Microsoft-supplied inbox driver that uses the Internet Printing Protocol to communicate with printers implementing the Mopria-certified IPP everywhere subset. WPP-enforced clients use this driver instead of vendor-specific v3 drivers." },
  { term: "v3 vs v4 driver model", definition: "The two pre-WPP Windows printer driver packaging models. v3 (Windows 2000 era) loads driver render code into the spooler process by default. v4 (Windows 8 era) is XPS-based and more portable. WPP deprecates both in favor of the inbox IPP class driver." },
  { term: "Universal Print", definition: "Microsoft's cloud-hosted print service (GA March 2, 2021). Eliminates print servers like OneDrive eliminates file servers. The architectural exit it takes is breaking conjunct (a): no local pipe spoolss exposed on a Universal-Print-only endpoint." },
  { term: "Redirection Guard", definition: "A Windows process mitigation that refuses to follow filesystem junctions or symbolic links created by non-administrator users. Enabled on spoolsv.exe via Set-ProcessMitigation -Name spoolsv.exe -Enable RedirectionGuard. Mitigates the SpoolFool-class reparse-point primitive." }
]} questions={[
  { q: "Which three Print Provider DLLs are loaded by the spooler router, and which one would handle a printer reached over IPP?", a: "localspl.dll (Local), win32spl.dll (Remote), inetpp.dll (HTTP/IPP). inetpp.dll handles IPP." },
  { q: "Why did Microsoft need four patch waves between June 2021 and August 2024 instead of one fix?", a: "The first patch closed one RPC entry point (MS-RPRN's RpcAddPrinterDriverEx); the second closed the symmetric MS-PAR entry point (RpcAsyncAddPrinterDriver); the third flipped the RestrictDriverInstallationToAdministrators default from 0 to 1 and published the verbatim 'no combination of mitigations is equivalent' concession; the fourth (SpoolFool) and fifth (CVE-2024-38198) exploited filesystem-side primitives that the RPC-side patches did not touch. The patches did not converge because they targeted entry points, not the architectural primitive." },
  { q: "What is the three-conjunct architectural primitive that every PrintNightmare-class bug exploits, and how does each shipped Microsoft exit break exactly one conjunct?", a: "(a) low-priv RPC entry, (b) caller-influenced DLL load, (c) SYSTEM context. Universal Print breaks (a); WPP module blocking breaks (b); WPP Spooler Worker and PrintIsolationHost.exe break (or weaken) (c)." },
  { q: "Why does Microsoft not sandbox spoolsv.exe in an AppContainer?", a: "Because the third-party driver install base (v3/v4 drivers shipped by essentially every Windows-compatible printer manufactured since 1993) is packaged to load in LocalSystem context. Constraining the spooler's token would break the installed printer base. Microsoft's architectural exits (WPP module blocking, Spooler Worker, Universal Print) sidestep the constraint rather than violate it." },
  { q: "What does WPP's module-blocking policy do, and what is the verbatim sentence Microsoft uses to describe it?", a: "WPP refuses to load any third-party driver DLL into the spooler. Microsoft's verbatim phrase is 'only Microsoft Signed binaries required for IPP are loaded.' The policy makes Point and Print 'never install third-party drivers' on a WPP-enabled host." }
]} />
