(CVE-2025-55336) Windows Cloud Files Mini Filter Driver Information Disclosure
CVE: CVE-2025-55336
Affected Versions: Windows 10 (21H2, 22H2, 1809), Windows 11 (22H2, 23H2, 24H2, 25H2), Windows Server 2019, 2022, 2022 23H2, 2025
CVSS3.1: 5.5 (Medium) — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Summary
| Product | Windows Cloud Files Mini Filter Driver (cldflt.sys) |
|---|---|
| Vendor | Microsoft |
| Severity | Medium — an unprivileged local attacker may exploit this to leak kernel addresses |
| Affected Versions | Windows 10 (21H2, 22H2, 1809), Windows 11 (22H2, 23H2, 24H2, 25H2), Windows Server 2019 / 2022 / 2022 23H2 / 2025 |
| Tested Versions | Windows 11 24H2 (Build 26100.2161) |
| CVE Identifier | CVE-2025-55336 |
| CVE Description | A side channel in the Windows Cloud Files Mini Filter Driver allows an unprivileged local attacker to leak the EPROCESS kernel address of the current process |
| CWE Classification(s) | CWE-200: Exposure of Sensitive Information to an Unauthorized Actor |
CVSS3.1 Scoring System
Base Score: 5.5 (Medium)
Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
| Metric | Value |
|---|---|
| Attack Vector (AV) | Local |
| Attack Complexity (AC) | Low |
| Privileges Required (PR) | Low |
| User Interaction (UI) | None |
| Scope (S) | Unchanged |
| Confidentiality (C) | High |
| Integrity (I) | None |
| Availability (A) | None |
Product Background
cldflt.sys is a filesystem minifilter driver that acts as a proxy between user applications and cloud sync engines. The sync engine handles on-demand downloading and uploading of data, while cldflt.sys works with the Windows Shell to present cloud-backed files as if they were locally available. It underpins technologies such as OneDrive.
Description of the vulnerability
An insecure comparison when processing a request to abort hydration (command 0x4002) allows a side channel attack to leak the EPROCESS address of the current process.
cldflt.sys creates a filter communication port \\CLDMSGPORT for usermode clients via CldPortInitialize():
RtlInitUnicodeString(&DestinationString, L"\\CLDMSGPORT");
status = SeSddlSecurityDescriptorFromSDDL((unsigned __int16 *)v7, v1, &P);
HsmDbgBreakOnStatus(status);
if ( status >= 0 )
{
ObjectAttributes.RootDirectory = 0LL;
ObjectAttributes.SecurityQualityOfService = 0LL;
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.SecurityDescriptor = P;
ObjectAttributes.Length = 48;
ObjectAttributes.Attributes = 576;
status = FltCreateCommunicationPort(
Globals,
&ServerPort,
&ObjectAttributes,
0LL,
(PFLT_CONNECT_NOTIFY)CldiPortNotifyConnect,
(PFLT_DISCONNECT_NOTIFY)CldiPortNotifyDisconnect,
(PFLT_MESSAGE_NOTIFY)CldiPortNotifyMessage,
0x7FFFFFFF);
When a client connects, CldiPortNotifyConnect() allocates a ClientInfo structure for each open handle:
clientInfo = (CLDFLT_PORT_CLIENT_INFO *)ExAllocatePool2(256LL, 0x118LL, 0x63706C43LL);
This structure contains various fields including the EPROCESS address of the client process.
Command 0x4002 is dispatched to CldiPortProcessAbortHydration(), which iterates over all registered clients and compares their stored EPROCESS pointer against Element13 — a value supplied directly from usermode:
FltAcquirePushLockSharedEx(&g_ClientInfoListLock, 0LL);
curClientInfo = g_ClientInfoList.Flink;
if ( g_ClientInfoList.Flink != &g_ClientInfoList )
{
elem13Val_ = elem13Val;
elem7Val_ = elem7Val;
do
{
if ( !elem13Val_ || curClientInfo->ClientProcess_ == elem13Val_ ) // Insecure comparison
{
FltAcquirePushLockSharedEx(&curClientInfo->Lock, 0LL);
if ( elem4Val )
{
PortrootData = CldiPortLookupSyncRootNoLock(curClientInfo, elem4Val);
if ( PortrootData )
CldSyncAbortOperation(elem14Val, PortrootData, elem7Val_, elem12Val, elem5Val);
}
else
{
elem7Val = 0LL;
while ( 1 )
{
portrootElem = RtlEnumerateGenericTableWithoutSplayingAvl(&curClientInfo->AvlTable, &elem7Val);
if ( !portrootElem )
break;
CldSyncAbortOperation(elem14Val, portrootElem[1], elem7Val_, elem12Val, elem5Val);
}
}
FltReleasePushLockEx(&curClientInfo->Lock, 0LL);
elem13Val_ = elem13Val;
}
curClientInfo = curClientInfo->Link.Flink;
}
while ( curClientInfo != &g_ClientInfoList );
When a match is found, CldSyncAbortOperation() waits for any in-progress operations on the syncroot to complete before aborting. This creates a timing oracle: by issuing a dir command on a connected syncroot directory and observing whether the abort call hangs, an attacker can determine whether their candidate address matched the real EPROCESS pointer.
Exploitation
EPROCESS structures are always allocated on a 0x40-byte alignment on the latest Windows 11 builds. The segment servicing EPROCESS allocations is empirically observed to fall within one of two ranges:
0xffffXX8000000000–0xffffXX90000000000xffffXX0000000000–0xffffXX1000000000
The XX byte ranges from 0x80 to 0xf0 (112 variations). With two threads per variation and 112 concurrent thread pairs, the full search space of ~1,073,741,824 candidates can be exhausted in under 30 minutes on an 8-core VM, yielding the EPROCESS address of one of the exploit threads — a powerful primitive for subsequent exploitation.
Proof of Concept
The PoC demonstrates the oracle for one of the 112 address variations. On success it pauses and prints the EPROCESS address of the running process.
Credit
Chen Le Qi (@cplearns2h4ck) of STAR Labs SG Pte. Ltd.
Timeline
- 2025-10-14 — Patch released via Microsoft Security Response Center (October 2025 Patch Tuesday)