Important CVSS 7.8 EPSS 0.12636 🔬 Patch diffed 2022-02 archive

Executive Summary

"Windows Dirty Pipe." An integer-overflow-to-out-of-bounds-write in the Named Pipe File System driver (npfs.sys), reachable only from an AppContainer or restricted (sandboxed) token - making it a renderer/UWP sandbox-escape rather than an ordinary local EoP (it was used at TianfuCup 2021 to escape the Adobe Reader sandbox). Opening \Device\NamedPipe\LOCAL\<name> reaches NpTranslateContainerLocalAlias, which rewrites the name into the AppContainer object namespace and sizes a pool buffer using 16-bit (ushort) arithmetic. A sufficiently long pipe name wraps the size to 0 (yielding a tiny 0x20 allocation) while the UNICODE_STRING MaximumLength, decremented past 0, underflows to 0xFFFE; RtlUnicodeStringPrintf then writes ~64 KB of attacker-controlled name into the tiny buffer - a controlled paged-pool overflow that can be groomed (WNF + _TOKEN objects) into arbitrary kernel read/write and SYSTEM. Microsoft's February 2022 fix widens the size arithmetic to 32-bit and adds a bound check (allocate only when the length is < 0xFFFF); the fix is unconditional (no feature flag). Reported by k0shl of Kunlun Lab. Confirmed by an in-house binary diff of npfs.sys 10.0.18362.267 -> .2094.

Overview

7.8
CVSS HIGH
Important
MS Severity
Not Exploited
MS Exploit Status
More Likely
MS Exploit Likelihood
Category Elevation of Privilege
Released Feb 8 2022
Last Updated Feb 8 2022
Publicly Disclosed No
CISA KEV Not Listed
Known Exploits None Known
EPSS Score 0.12636 — 0.95892 percentile
NVD CVSS 7.8 HIGH — matches MSRC

CVSS Vector

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C
ATTACK VECTOR
Local
ATTACK COMPLEXITY
Low
PRIVILEGES REQUIRED
Low
USER INTERACTION
None
SCOPE
Unchanged
CONFIDENTIALITY
High
INTEGRITY
High
AVAILABILITY
High
EXPLOIT CODE MATURITY
Unproven
REMEDIATION LEVEL
Official Fix
REPORT CONFIDENCE
Confirmed
Temporal Score: 6.8

EPSS Score

0.12636
probability of exploitation in the next 30 days
0.95892 percentile - updated 2026-08-14
View on FIRST.org

Affected Products

20 affected products
Product KB Article Severity Impact Restart Required
Windows 10 Version 1809 for 32-bit Systems 5010351 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 1809 for ARM64-based Systems 5010351 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 1809 for x64-based Systems 5010351 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 1909 for 32-bit Systems 5010345 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 1909 for ARM64-based Systems 5010345 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 1909 for x64-based Systems 5010345 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 20H2 for 32-bit Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 20H2 for ARM64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 20H2 for x64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H1 for 32-bit Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H1 for ARM64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H1 for x64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H2 for 32-bit Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H2 for ARM64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 10 Version 21H2 for x64-based Systems 5010342 (Security Update) Important Elevation of Privilege Yes
Windows 11 version 21H2 for ARM64-based Systems 5010386 (Security Update) Important Elevation of Privilege Yes
Windows 11 version 21H2 for x64-based Systems 5010386 (Security Update) Important Elevation of Privilege Yes
Windows Server 2019 5010351 (Security Update) Important Elevation of Privilege Yes
Windows Server 2019 (Server Core installation) 5010351 (Security Update) Important Elevation of Privilege Yes
Windows Server 2022 5010354 (Security Update) 5010456 (Security Hotpatch Update) Important Elevation of Privilege 5009555 Base: 7.8 Temporal: 6.8 Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C 10.0.20348.524 10.0.20348.525 Yes 5010354 Windows Server 2022 (Server Core installation) 5010354 (Security Update) 5010456 (Security Hotpatch Update) Important Elevation of Privilege 5009555 Base: 7.8 Temporal: 6.8 Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C 10.0.20348.524 10.0.20348.525 Yes 5010354 Windows Server, version 20H2 (Server Core Installation) 5010342 (Security Update) Important Elevation of Privilege Yes

Patches

4 patches
Article Type Restart
5010351 Security Update Yes
5010345 Security Update Yes
5010342 Security Update Yes
5010386 Security Update Yes

Patch Diff

ghidriff · npfs.sys (KB5010342)

"Windows Dirty Pipe": a 16-bit integer overflow -> pool out-of-bounds write in npfs.sys NpTranslateContainerLocalAlias, reachable ONLY from an AppContainer/restricted (sandboxed) token - a renderer/UWP sandbox escape (used at TianfuCup 2021 to escape the Adobe Reader sandbox). Opening \Device\NamedPipe\LOCAL\<name> routes NpFsdCreate -> NpTranslateAlias (matches the LOCAL\ prefix) -> NpTranslateContainerLocalAlias, which rewrites the name into Sessions\<n>\AppContainerNamedObjects\<sid>\...\<name>. All size vars were 16-bit: total = prefix + namelen + 0x14 (+2 if the remaining name starts with '\'); a long pipe name wraps this ushort to 0, so ExAllocatePoolWithTag returns a tiny 0x20 'NpFn' buffer, and the UNICODE_STRING MaximumLength decremented past 0 underflows to 0xFFFE. RtlUnicodeStringPrintf then writes ~64KB of attacker-controlled name bytes into the 0x20 pool -> controlled paged-pool OOB write (CWE-190 -> CWE-787). The trigger needs the total size to wrap to exactly 0. IN-HOUSE ghidriff diff of 10.0.18362.267 -> .2094 confirms NpTranslateContainerLocalAlias is the ONLY changed function (99.8% match): the fix widens the size arithmetic from short to 32-bit int/uint (iVar5/iVar10/uVar6) and adds a bound check `if (uVar6 < 0xffff)` before ExAllocatePoolWithTag, eliminating both the overflow and the 0xFFFE underflow. UNCONDITIONAL fix - no CFR/KIR flag. k0shl's PoC chains WNF _WNF_STATE_DATA + _TOKEN grooming into arbitrary R/W and sets ETHREAD.PreviousMode=0. Credit: k0shl of Kunlun Lab via TianfuCup 2021.

Pre-patch version 10.0.18362.267 Download
Post-patch version 10.0.18362.2094 Download
Function Address Change Note
NpTranslateContainerLocalAlias 99.8% match (only changed function) code (size arithmetic widened short->int + `< 0xffff` bound check, unconditional) Pre: 16-bit size vars (short sVar5/sVar10); total = (short)prefix + 100 + (ushort)namelen (+2 if ifslash) wraps to 0 -> ExAllocatePoolWithTag(PagedPool, sVar5, 'NpFn') tiny alloc; MaximumLength -= 2 underflows 0 -> 0xFFFE; RtlUnicodeStringPrintf OOB-writes ~64KB. Post: iVar5/iVar10/uVar6 computed as 32-bit uint (no 16-bit wrap) and `if (uVar6 < 0xffff)` gates the allocation. Reached only when the token is AppContainer or restricted (SeQueryInformationToken TokenIsAppContainer/TokenIsRestricted).
View full diff report View RCA report

Attack Path

A long LOCAL\ pipe name wraps a 16-bit size to 0 (tiny pool) while MaximumLength underflows to 0xFFFE, so the name format-copy overruns paged pool - from inside a sandbox

Attack path for CVE-2022-22715 A long LOCAL\ pipe name wraps a 16-bit size to 0 (tiny pool) while MaximumLength underflows to 0xFFFE, so the name format-copy overruns paged pool - from inside a sandbox 01 — ENTRY Sandboxed process (AppContainer / restricted token) opens a LOCAL named pipe NpTranslateContainerLocalAlias only proceeds when SeQueryInformationToken reports the caller is AppContainer or restricted - i.e. a browser renderer or Adobe Reader sandbox. This is a sandbox-escape primitive, not a generic local trigger. 02 — CONTROLLED INPUT NtCreateFile("\Device\NamedPipe\LOCAL\<long name>") NpFsdCreate -> NpTranslateAlias matches the 'LOCAL\' prefix and calls NpTranslateContainerLocalAlias to rewrite the name into the container object namespace. The attacker controls the name's length and bytes. 03 — PATH npfs computes the translated-name size in 16-bit fields and allocates a pool buffer total = prefix + namelen + 0x14, plus 2 if the remaining name starts with '\'. All size vars are ushort/short. The result sizes an ExAllocatePoolWithTag(PagedPool, size, 'NpFn') for RtlUnicodeStringPrintf to format into. 04 — MISSING CHECK The 16-bit size wraps to 0 and MaximumLength underflows to 0xFFFE A long enough name makes the ushort total wrap to exactly 0 -> a minimal 0x20 allocation; then MaximumLength (0) -= 2 underflows to 0xFFFE. RtlUnicodeStringPrintf copies up to MaximumLength bytes. 05 — PRIMITIVE ~64KB attacker-controlled paged-pool OOB write -> arbitrary R/W -> SYSTEM The format-copy writes ~0xFFFE bytes of controlled name data into the 0x20 buffer, smashing adjacent 0x20 LFH / neighbouring VS pool. k0shl grooms _WNF_STATE_DATA (manager) beside a _TOKEN (worker) to build arbitrary kernel R/W and sets ETHREAD.PreviousMode=0. The Feb 2022 fix widens the size math to 32-bit and adds `if (uVar6 < 0xffff)` - unconditional, no feature flag.

Derived from the patch delta: the checks added by the vendor identify which fields crossed a trust boundary unvalidated. Reachability and privilege are taken from the call chain in the RCA report.

Known Exploits

Acknowledgments

Kunlun lab (https://www.cyberkl.com) via TianfuCup (https://www.tianfucup.com)