# CVE-2026-50697 — Windows CLFS `clfs.sys` Information Disclosure via Kernel Pointer Leak in CopyImage

---

## Summary

| **Product**           | Microsoft Windows — `clfs.sys` (Common Log File System kernel driver) |
|-----------------------|-----------------------------------------------------------------------|
| **Vendor**            | Microsoft Corporation |
| **Severity**          | High |
| **Affected Versions** | Windows 11 24H2 (10.0.26100.x); likely all Windows versions shipping clfs.sys with CClfsBaseFileSnapshot |
| **Tested Version**    | Windows 10.0.26100.8737 (pre-patch) vs 10.0.26100.8875 (post-patch) |
| **Impact**            | Information Disclosure — Kernel pointer leak enabling KASLR bypass |
| **CVE ID**            | CVE-2026-50697 |
| **CWE**               | CWE-200: Exposure of Sensitive Information to an Unauthorized Actor |
| **PoC Available**     | Yes (trigger PoC — demonstrates reading the leaked kernel pointer) |
| **Exploit Available** | No public exploit; Microsoft rates "Exploitation Unlikely" |
| **Patch Available**   | Yes |
| **Patch Date**        | July 2026 — KB5101650 |
| **Exploitation Maturity** | Exploitation Unlikely |

---

## CVSS 4.0 Detailed Scoring

**Base Score:** 5.9 (MEDIUM)
**Vector String:** `CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N`

| **Metric** | **Value** | **Rationale** |
|---|---|---|
| **Attack Vector (AV)** | Local | Requires local authenticated session |
| **Attack Complexity (AC)** | Low | Standard CLFS archive APIs; no race conditions |
| **Attack Requirements (AT)** | None | CLFS is always present on all Windows installations |
| **Privileges Required (PR)** | Low | Standard user account; no administrative rights required |
| **User Interaction (UI)** | None | No interaction from any other user required |
| **Vulnerable System Confidentiality (VC)** | High | Leaks kernel pointers, breaking KASLR |
| **Vulnerable System Integrity (VI)** | None | No write capability from this bug alone |
| **Vulnerable System Availability (VA)** | None | No crash or DoS |
| **Subsequent System Confidentiality (SC)** | None | Info leak alone does not chain further without a separate vuln |
| **Subsequent System Integrity (SI)** | None | — |
| **Subsequent System Availability (SA)** | None | — |

> **Note:** Microsoft rates this CVE at CVSS 3.1 7.8 (`AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H`), suggesting they consider the EoP chain potential. NVD may score differently.

---

## Product Description

`clfs.sys` is the kernel driver implementing the Common Log File System (CLFS), a general-purpose high-performance logging subsystem used by TxF (Transactional NTFS), Active Directory, MSDTC, and other Windows components. CLFS manages Base Log Files (`.blf`) containing control records, general metadata, scratch blocks, and container descriptors.

The CLFS archival subsystem allows applications to snapshot and read the base-file metadata blocks for backup/archival purposes. The `CClfsBaseFileSnapshot::CopyImage` function serializes the in-memory log metadata into a caller-supplied buffer. Each metadata block references container context structures, which hold runtime kernel state including live kernel pointers.

CLFS has been a persistent source of kernel vulnerabilities — CVE-2023-28252, CVE-2023-23376, CVE-2022-37969, and many others have exploited various aspects of its complex on-disk format and kernel parsing logic.

---

## Vulnerability Summary

`CClfsBaseFileSnapshot::CopyImage` copies the base-file log image — a serialization of all CLFS metadata blocks — into a user-supplied buffer without sanitizing the `container_context + 0x18` field. This field holds a live kernel pointer (a runtime state pointer within the `_CLFS_CONTAINER_CONTEXT` structure). When a user-mode application calls `ReadLogArchiveMetadata()`, the kernel copies this unsanitized image to user space, leaking a kernel address. This breaks KASLR and can serve as a stepping stone for chaining with a separate write primitive to achieve full EoP.

---

## Prerequisites and Constraints

- Local authenticated session (standard user; no administrative rights required)
- CLFS is always present — it is a core Windows kernel component, not an optional feature
- Log files can be created in any user-writable directory via the `CreateLogFile` API
- At least one container must be added to the log (via `AddLogContainer`) so that a container context exists with a non-null `+0x18` pointer
- The archival path must be invoked: `PrepareLogArchive` → `ReadLogArchiveMetadata`
- No kernel driver, special hardware, or pre-existing elevated token required
- Info-disclosure only; a separate vulnerability is needed to leverage the leaked address for EoP

---

## Vulnerability Details

### Call Chain (Ghidra MCP–Verified)

The complete kernel call chain from userspace API to the vulnerable function, verified via live Ghidra MCP xref tracing against the **pre-patch** binary (`clfs-2026-06.sys`, 10.0.26100.8737). Every `→` below was confirmed by `get_function_xrefs` as an `UNCONDITIONAL_CALL`.

```
User mode:
  CreateLogFile()           → opens CLFS log, returns handle
  AddLogContainer()         → adds container (creates container contexts with +0x18 pointer)
  PrepareLogArchive()       → starts archival, creates CClfsBaseFileSnapshot
  ReadLogArchiveMetadata()  → sends IOCTL 0x80076856 to clfs.sys
                               ↓
Kernel mode:
  CClfsDriver::LogIoDispatch()                    [IRP_MJ_DEVICE_CONTROL handler]
    → ClfsDispatchIoRequest()                      [allocates CClfsRequest, dispatches]
      → CClfsRequest::Dispatch()                   [IOCTL switch: 0x80076856 → ReadArchiveMetadata]
        → CClfsRequest::ReadArchiveMetadata()      [maps MDL, extracts params]
          → CClfsLogCcb::ReadArchiveMetadata()     [acquires resource, calls snapshot]
            → CClfsBaseFileSnapshot::CopyImage()   [*** VULNERABLE ***]
```

### IOCTL Routing

In `CClfsRequest::Dispatch`, the IRP major function `0xe` (`IRP_MJ_DEVICE_CONTROL`) routes to a switch on the IOCTL code at offset `+0x18` of the IRP stack location. IOCTL `0x80076856` maps to `ReadArchiveMetadata`:

```c
// From CClfsRequest::Dispatch @ 0x14006bd50 (pre-patch, Ghidra decompilation)
if (uVar4 == 0x80076856) {
    uVar4 = ReadArchiveMetadata(this, (longlong)pCVar2);
    goto LAB_14006c210;
}
```

### CClfsRequest::ReadArchiveMetadata

This function extracts the offset, buffer size, and MDL-mapped buffer from the IRP, then delegates to `CClfsLogCcb::ReadArchiveMetadata`:

```c
// Simplified from Ghidra decompilation
long CClfsRequest::ReadArchiveMetadata(CClfsRequest *this) {
    // Extract params from IRP
    longlong irp_extension = *(longlong *)(*(longlong *)(this+0x30) + 0xb8);
    uint offset = **(uint **)(*(longlong *)pCVar1 + 0x18);  // archive read offset
    uint bufsize = *(uint *)(irp_extension + 8);             // output buffer size

    // Get the CClfsLogCcb from the file object
    CClfsLogCcb *ccb = *(CClfsLogCcb **)(*(longlong *)(irp_extension + 0x30) + 0x20);
    CClfsLogCcb::AddRef(ccb);

    // Map the MDL for the output buffer
    char *buffer = MmMapLockedPagesSpecifyCache(mdl, 0, MmCached, ...);

    // Call into CClfsLogCcb::ReadArchiveMetadata
    result = CClfsLogCcb::ReadArchiveMetadata(ccb, offset, bufsize, buffer, &bytesRead);
    return result;
}
```

### CClfsLogCcb::ReadArchiveMetadata

A thin wrapper that acquires an exclusive resource lock, checks the snapshot exists (`this+0x28 != 0`), and calls `CopyImage`:

```c
// Ghidra decompilation
ulonglong CClfsLogCcb::ReadArchiveMetadata(CClfsLogCcb *this, ..., char *param_4) {
    ExAcquireResourceExclusiveLite(this + 0x98, TRUE);
    if (*(int *)(this + 0x28) == 0) {
        return STATUS_LOG_NO_RESTART;  // 0xc01a0020
    }
    result = CClfsBaseFileSnapshot::CopyImage(
        *(CClfsBaseFileSnapshot **)(this + 0x80),
        offset, bufsize, buffer, &bytesRead);
    ExReleaseResourceLite(this + 0x98);
    return result;
}
```

### CClfsBaseFileSnapshot::CopyImage (Pre-Patch — VULNERABLE)

The pre-patch `CopyImage` at `0x140039668` (Ghidra decompilation from `clfs-2026-06.sys`, 10.0.26100.8737) acquires the image resource lock, then iterates the metadata block descriptors, encoding each block and copying it to the user buffer via `memmove`. **There is no `Feature_326875449` check, no container context scrubbing, and no save/restore loop** — the entire in-memory image, including live kernel pointers at `container_context + 0x18`, is copied verbatim to user space:

```c
// Pre-patch CopyImage @ 0x140039668 — actual Ghidra decompilation (simplified)
int CClfsBaseFileSnapshot::CopyImage(
        CClfsBaseFileSnapshot *this, uint offset, uint bufsize,
        char *outbuf, uint *bytesRead)
{
    if (bufsize == 0 || outbuf == NULL)
        return STATUS_INVALID_PARAMETER;  // 0xc000000d

    *(uint *)outbuf = 0;  // zero bytesRead output
    cVar4 = ExAcquireResourceExclusiveLite(*(this + 0x20), TRUE);

    // *** NO Feature_326875449 check ***
    // *** NO container context scrubbing ***

    // Iterate metadata blocks and copy to user buffer
    while (blockIdx < *(ushort *)(this + 0x28) && *(uint *)outbuf < bufsize) {
        block = blockDescriptors[blockIdx];
        ClfsEncodeBlock(block, sectorCount << 9, ...);

        // Calculate copy range within this block
        localOffset = offset - blockStart;
        copyLen = min(blockSize - localOffset, bufsize - *(uint *)outbuf);

        // Copy block data to user buffer — LEAKS container_context+0x18
        memmove(outbuf + *(uint *)outbuf,
                blockBase + localOffset,
                copyLen);

        *(uint *)outbuf += copyLen;
        offset += copyLen;
        ClfsDecodeBlock(block, ...);
        blockIdx++;
    }

    CClfsBaseFile::UnlockImage(this);
    return status;
}
```

The `container_context + 0x18` field is embedded in the metadata block image. When the block is copied to user space, the caller can read the leaked kernel pointer directly from the received buffer at a known offset relative to the container context structure within the BLF metadata.

**Pre-patch constructor** (`0x140038da4`) — note the absence of any save-area initialization:

```c
// Pre-patch constructor — no memset, no feature flag, object is only ~0x98 bytes
CClfsBaseFileSnapshot *CClfsBaseFileSnapshot::CClfsBaseFileSnapshot(this) {
    *(uint *)(this + 0x90) = 0x200;
    *(uint *)(this + 8) = 0;
    *(void ***)this = &_vftable_;
    *(uint64 *)(this + 0x10) = 0;
    *(uint *)(this + 0x18) = 0;
    *(uint64 *)(this + 0x20) = 0;
    *(ushort *)(this + 0x28) = 0;
    *(uint64 *)(this + 0x30) = 0;
    *(uint64 *)(this + 0x38) = 0;
    this[0x94] = 0;
    *(uint64 *)(this + 0x98) = 0;
    // *** NO memset(this+0xa0, 0, 0x2000) ***
    // *** NO Feature_326875449 check ***
    return this;
}
```

### CClfsBaseFileSnapshot::CopyImage (Post-Patch — FIXED)

The post-patch `CopyImage` at `0x1400396a0` (`clfs-2026-07.sys`, 10.0.26100.8875) adds a **scrub-copy-restore** pattern gated behind WIL CFR flag `Feature_326875449`:

```c
// Post-patch CopyImage — with scrubbing
ulonglong CClfsBaseFileSnapshot::CopyImage(..., char *outbuf, uint *bytesRead) {
    ExAcquireResourceExclusiveLite(*(this + 0x20), TRUE);

    // *** PRE-PASS: scrub kernel pointers ***
    if (Feature_326875449__private_IsEnabledDeviceUsageNoInline()) {
        for (i = 0; i < 0x400; i++) {
            status = CClfsBaseFile::AcquireContainerContext(this, i, &ctx);
            if (status < 0) {
                this->save_array[i] = 0;
            } else {
                this->save_array[i] = ctx->field_0x18;   // save the pointer
                ctx->field_0x18 = 0;                       // NULL it out
                CClfsBaseFile::ReleaseContainerContext(this, &ctx);
            }
        }
    }

    // Copy blocks to user buffer (now sanitized)
    while (blockIdx < numBlocks && *bytesRead < bufsize) {
        // ... same memcpy loop as before ...
    }

    // *** POST-PASS: restore kernel pointers ***
    if (Feature_326875449__private_IsEnabledDeviceUsageNoInline()) {
        for (i = 0; i < 0x400; i++) {
            if (this->save_array[i] != 0) {
                status = CClfsBaseFile::AcquireContainerContext(this, i, &ctx);
                if (status < 0) {
                    this->save_array[i] = 0;
                } else {
                    ctx->field_0x18 = this->save_array[i]; // restore
                    this->save_array[i] = 0;
                    CClfsBaseFile::ReleaseContainerContext(this, &ctx);
                }
            }
        }
    }

    CClfsBaseFile::UnlockImage(this);
    return status;
}
```

### Constructor Changes

The `CClfsBaseFileSnapshot` constructor gains a `memset` (behind the same feature flag) to zero-initialize the 0x2000-byte save array at `this + 0xa0`:

```c
CClfsBaseFileSnapshot::CClfsBaseFileSnapshot(this) {
    // ... existing field init ...
    *(undefined ***)this = &_vftable_;
    if (Feature_326875449__private_IsEnabledDeviceUsageNoInline()) {
        memset(this + 0xa0, 0, 0x2000);  // 0x400 slots × 8 bytes
    }
    return this;
}
```

---

## Exploitation Scenario

### Step 1 — Create a CLFS Log with Containers

```
CreateLogFile("LOG:\\C:\\Users\\user\\test.blf", ...)
  → returns log handle
AddLogContainer(logHandle, containerSize, "container0.log")
  → kernel allocates _CLFS_CONTAINER_CONTEXT, sets +0x18 to a kernel pointer
```

### Step 2 — Initiate Archival

```
PrepareLogArchive(logHandle, ...)
  → kernel creates CClfsBaseFileSnapshot, snapshots the base-file metadata
```

### Step 3 — Read Archive Metadata (triggers the leak)

```
ReadLogArchiveMetadata(archiveContext, offset=0, buffer, bufferSize)
  → IOCTL 0x80076856
  → CopyImage copies metadata blocks including container_context+0x18 to user buffer
  → User parses the buffer at known offsets to extract the kernel pointer
```

### Step 4 — Use Leaked Address

The leaked kernel pointer breaks KASLR. An attacker can:
- Calculate the base address of `clfs.sys` or the kernel
- Use this with a separate write primitive (e.g., another CLFS vuln, a type confusion, etc.) to achieve full EoP
- Target specific kernel objects at known addresses

### Impact

This is an information-disclosure primitive, not a direct code execution path. Its value is as a **KASLR bypass** — the first step in a two-stage kernel exploit chain. Without a companion write primitive, the leaked pointer alone cannot escalate privileges.

---

## Patch Analysis

### Mechanism

The patch implements a scrub-copy-restore pattern:

1. **Save & NULL**: Before copying, iterate all 0x400 possible container contexts. For each, save `container_context+0x18` into a private array at `this+0xa0` and set the original to NULL.
2. **Copy**: The existing block copy loop runs against the now-sanitized image.
3. **Restore**: After copying, walk the save array and put each pointer back into its container context, preserving runtime state.

### Feature Gating

The entire fix is gated behind `Feature_326875449` using Windows Implementation Library (WIL) Controlled Feature Rollout (CFR). This allows Microsoft to:
- Gradually roll out the fix
- Disable it via kill-switch if regressions are found
- A/B test the change

### Files Changed

| Function | Change |
|---|---|
| `CClfsBaseFileSnapshot::CopyImage` | +294 bytes; pre/post-pass scrub-copy-restore of `container_context+0x18` |
| `CClfsBaseFileSnapshot::CClfsBaseFileSnapshot` | +memset of 0x2000-byte save area at `this+0xa0` |
| `CClfsBaseFileSnapshot::CopyImage::__l1::fin$0` | SEH funclet updated for new container context cleanup path |
| `CClfsLogFcbPhysical::AppendLog` | Refactored (independent change, not security-relevant to this CVE) |
| 4 new WIL functions | Standard CFR plumbing for `Feature_326875449` |

---

## Trigger PoC

A proof-of-concept is available at [`poc/poc_cve_2026_50697.c`](/data/patch_diffs/poc/poc_cve_2026_50697.c). It demonstrates the information disclosure by:

1. Creating a CLFS log file with `CreateLogFile`
2. Adding a container with `AddLogContainer`
3. Preparing a log archive with `PrepareLogArchive`
4. Reading archive metadata with `ReadLogArchiveMetadata`
5. Scanning the returned buffer for non-zero 8-byte values in the kernel address range (`0xFFFF0000'00000000` – `0xFFFFFFFF'FFFFFFFF`)
6. Reporting any leaked kernel pointers

On a **pre-patch** system, the PoC will print leaked kernel addresses. On a **post-patch** system, the container context pointer fields will be zeroed and no kernel addresses appear.

> **Note:** This PoC is a **trigger/detector** only. It demonstrates the info leak but does not chain it into code execution. It is designed for blue teams to validate detection rules.

---

## Detection Rules

### YARA Rule — Detecting PoC Binaries

```yara
rule CVE_2026_50697_CLFS_InfoLeak_PoC {
    meta:
        description = "Detects compiled PoC for CVE-2026-50697 CLFS CopyImage info leak"
        author = "OnlyFm252"
        date = "2026-07-17"
        cve = "CVE-2026-50697"
        severity = "high"
        tlp = "white"

    strings:
        $api1 = "CreateLogFile" ascii wide
        $api2 = "PrepareLogArchive" ascii wide
        $api3 = "ReadLogArchiveMetadata" ascii wide
        $api4 = "AddLogContainer" ascii wide
        $log_prefix = "LOG:\\" ascii wide nocase
        $kernel_range = { FF FF ?? ?? ?? ?? ?? ?? }
        $scan_msg = "kernel" ascii wide nocase
        $blf_ext = ".blf" ascii wide nocase

    condition:
        uint16(0) == 0x5A4D and
        filesize < 500KB and
        $api1 and $api2 and $api3 and $api4 and
        ($log_prefix or $blf_ext) and
        ($kernel_range or $scan_msg)
}
```

### YARA Rule — Detecting Vulnerable clfs.sys (Pre-Patch)

```yara
rule CVE_2026_50697_Vulnerable_CLFS {
    meta:
        description = "Detects pre-patch clfs.sys vulnerable to CVE-2026-50697"
        author = "OnlyFm252"
        date = "2026-07-17"
        cve = "CVE-2026-50697"

    strings:
        $version_pre = "10.0.26100.8737" wide
        $copyimage = "CClfsBaseFileSnapshot::CopyImage" ascii
        $no_feature = { 48 8D ?? A0 00 00 00 }

    condition:
        uint16(0) == 0x5A4D and
        $version_pre and $copyimage and not
        for any of ($no_feature) : (
            # Post-patch has the scrub loop referencing this+0xa0
            true
        )
}
```

### Sigma Rule — CLFS Archive Metadata Access

```yaml
title: Suspicious CLFS Archive Metadata Read (CVE-2026-50697)
id: a7f3b2c1-9e4d-4a8b-b1c5-2d6e8f0a3b7c
status: experimental
description: >
    Detects processes reading CLFS archive metadata, which may indicate
    exploitation of CVE-2026-50697 to leak kernel pointers. The CLFS
    archival API (PrepareLogArchive + ReadLogArchiveMetadata) is rarely
    used by legitimate applications.
author: OnlyFm252
date: 2026/07/17
references:
    - https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-50697
    - https://onlyfm252.starlabs.sg/patch-tuesday/2026-07/cve-2026-50697/
logsource:
    category: process_creation
    product: windows
detection:
    selection_api_imports:
        CommandLine|contains:
            - 'PrepareLogArchive'
            - 'ReadLogArchiveMetadata'
    selection_blf_access:
        CommandLine|contains:
            - '.blf'
            - 'LOG:\\'
    condition: selection_api_imports or selection_blf_access
falsepositives:
    - CLFS-aware backup software (e.g., Windows Server Backup, DPM)
    - Database transaction log management tools
    - Custom CLFS log archival utilities
level: medium
tags:
    - attack.discovery
    - attack.t1082
    - cve.2026.50697
```

### Sigma Rule — Kernel API Tracing

```yaml
title: CLFS Archival API Call Sequence (CVE-2026-50697)
id: b8e4c3d2-0f5e-5b9c-c2d6-3e7f9g1b4c8d
status: experimental
description: >
    Detects the specific API call sequence used to trigger CVE-2026-50697:
    CreateLogFile followed by AddLogContainer and PrepareLogArchive within
    the same process. This sequence is the prerequisite for the info leak.
author: OnlyFm252
date: 2026/07/17
logsource:
    category: api_call
    product: windows
detection:
    selection_create:
        ApiCall: 'CreateLogFile'
    selection_container:
        ApiCall: 'AddLogContainer'
    selection_archive:
        ApiCall:
            - 'PrepareLogArchive'
            - 'ReadLogArchiveMetadata'
    condition: selection_create and selection_container and selection_archive
    timeframe: 60s
falsepositives:
    - Legitimate CLFS archival operations
level: high
tags:
    - attack.discovery
    - attack.t1082
    - cve.2026.50697
```

### Sysmon Configuration

```xml
<!-- Sysmon config addition for CVE-2026-50697 detection -->

<!-- Rule: Detect BLF file creation in user-writable directories -->
<RuleGroup name="CVE-2026-50697" groupRelation="or">

  <!-- FileCreate: .blf files outside system directories -->
  <FileCreate onmatch="include">
    <Rule name="CLFS_BLF_UserDir" groupRelation="and">
      <TargetFilename condition="end with">.blf</TargetFilename>
      <TargetFilename condition="excludes">C:\Windows\</TargetFilename>
    </Rule>
  </FileCreate>

  <!-- ProcessAccess: Process accessing clfs.sys device -->
  <FileCreate onmatch="include">
    <Rule name="CLFS_Container_UserDir" groupRelation="and">
      <TargetFilename condition="end with">.log</TargetFilename>
      <Image condition="excludes">C:\Windows\system32\</Image>
      <Image condition="excludes">C:\Program Files\</Image>
    </Rule>
  </FileCreate>

  <!-- ImageLoad: clfsw32.dll loaded by suspicious process -->
  <ImageLoad onmatch="include">
    <Rule name="CLFS_DLL_Load" groupRelation="and">
      <ImageLoaded condition="end with">clfsw32.dll</ImageLoaded>
      <Image condition="excludes">C:\Windows\</Image>
      <Image condition="excludes">C:\Program Files\</Image>
      <Image condition="excludes">C:\Program Files (x86)\</Image>
    </Rule>
  </ImageLoad>

</RuleGroup>
```

### WDAC Deny Policy

```xml
<?xml version="1.0" encoding="utf-8"?>
<!--
  WDAC supplemental policy to block known CVE-2026-50697 PoC binaries.
  Merge with your base WDAC policy using:
    ConvertFrom-CIPolicy -XmlFilePath .\CVE-2026-50697-Deny.xml -BinaryFilePath .\CVE-2026-50697-Deny.p7b
    citool --update-policy .\CVE-2026-50697-Deny.p7b
-->
<SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy" PolicyType="Supplemental Policy">
  <VersionEx>10.0.0.0</VersionEx>
  <PlatformID>{2E07F7E4-194C-4D20-B7C9-6F44A6C5A234}</PlatformID>
  <Rules>
    <Rule>
      <Option>Enabled:Unsigned System Integrity Policy</Option>
    </Rule>
    <Rule>
      <Option>Enabled:Audit Mode</Option> <!-- Remove for enforcement -->
    </Rule>
  </Rules>
  <FileRules>
    <!-- Block pre-patch clfs.sys (10.0.26100.8737) -->
    <Deny ID="ID_DENY_CLFS_VULN" FriendlyName="clfs.sys pre-patch CVE-2026-50697"
          FileName="clfs.sys"
          MinimumFileVersion="10.0.26100.8737"
          MaximumFileVersion="10.0.26100.8737" />
  </FileRules>
  <SigningScenarios>
    <SigningScenario Value="131" ID="ID_SIGNINGSCENARIO_DRIVERS" FriendlyName="Kernel Mode">
      <ProductSigners>
        <DeniedSigners>
          <!-- Reference to Microsoft Windows Production PCA signer -->
        </DeniedSigners>
      </ProductSigners>
      <FileRulesRef>
        <FileRuleRef RuleID="ID_DENY_CLFS_VULN" />
      </FileRulesRef>
    </SigningScenario>
  </SigningScenarios>
</SiPolicy>
```

---

## Remediation

1. **Apply KB5101650** (July 2026 cumulative update) immediately
2. **Verify patch**: Check `clfs.sys` version is ≥ 10.0.26100.8875
3. **Monitor**: Deploy the Sysmon and Sigma rules above to detect exploitation attempts
4. **Restrict**: Use WDAC to block the pre-patch driver version in enterprise environments
5. **Audit**: Review systems for unexpected `.blf` file creation in user-writable directories

---

## Timeline

| Date | Event |
|---|---|
| 2026-07-08 | Microsoft releases July 2026 Patch Tuesday (KB5101650) |
| 2026-07-17 | This analysis published |

---

## References

- [Microsoft Security Response Center — CVE-2026-50697](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-50697)
- [CLFS Documentation — ReadLogArchiveMetadata](https://learn.microsoft.com/en-us/windows/win32/api/clfsw32/nf-clfsw32-readlogarchivemetadata)
- [CLFS Documentation — PrepareLogArchive](https://learn.microsoft.com/en-us/windows/win32/api/clfsw32/nf-clfsw32-preparelogarchive)
- [ghidriff — Ghidra binary diffing tool](https://github.com/clearbluejar/ghidriff)
- [OnlyFm252 Diff Report](/data/patch_diffs/clfs_sys-kb5101650.md)

---
