# CVE-2026-24287 — Windows Projected File System `prjflt.sys` Unrestricted User Volume Name in `PrjfPortConnect` → Arbitrary Device Open (External Control of File Path)

---

## Summary

| | |
|---|---|
| **Product** | Windows — `prjflt.sys` (Windows Projected File System / ProjFS minifilter; port connect) |
| **CVE ID** | CVE-2026-24287 |
| **Impact** | Elevation of Privilege |
| **MSRC severity** | Important |
| **CVSS** | 7.8 / 6.8 — `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` |
| **CWE** | CWE-73: External Control of File Name or Path |
| **Delivery** | Local — a crafted `_PRJ_CONNECTION_CONTEXT` to the ProjFS filter port |
| **KB / Fixed build** | KB5079473 — `prjflt.sys` 10.0.26100.8036 (Win11 24H2 x64) |
| **Patch Date** | March 10, 2026 (2026-Mar) |
| **Pre-patch binary** | `prjflt.sys` 10.0.26100.7920 — SHA256 `e31bf9ae1bdff86e6683e469dd56d341c019c02e389d3086608ba61de160949f` |
| **Post-patch binary** | `prjflt.sys` 10.0.26100.8036 — SHA256 `d5afe5fe1f66c520b1b49bf43d8567d80c4dd42a03621cbceb6587bc29a424dc` |
| **Feature flag** | `Feature_78846265` — **the fix is CFR-gated** |
| **Exploitability** | Exploitation Less Likely; not publicly disclosed; not exploited (per MSRC) |

---

## Product Description

`PrjfPortConnect` is the ProjFS minifilter's filter-port connect callback. A client
connecting to the ProjFS communication port passes a `_PRJ_CONNECTION_CONTEXT`:

```c
struct _PRJ_CONNECTION_CONTEXT {
    GUID   virtualizationInstanceID;
    UINT   Version;
    USHORT VolumeLength;
    WCHAR  szVolume[256];      // fully user-controlled
};
```

`PrjfPortConnect` builds a `UNICODE_STRING` `usVolumeName` from `szVolume` /
`VolumeLength` and resolves it via
`PrjfGetInstanceFromVolumeName` → `FltGetVolumeFromName`, which ultimately calls
`ZwCreateFile` with `ObjectAttributes.ObjectName = usVolumeName`:

```
FLTMGR!FltpIoGetDeviceObjectPointer
FLTMGR!FltGetVolumeFromName
prjflt!PrjfGetInstanceFromVolumeName
prjflt!PrjfPortConnect
```

---

## Vulnerability Summary

`usVolumeName` is taken directly from the user-supplied `szVolume`/`VolumeLength`,
so it is fully attacker-controlled, and pre-patch it was **not restricted to a
legitimate volume-device path**. A low-privileged client can therefore supply an
arbitrary object path and make `prjflt` open a device it could not open itself:

> With `usVolumeName = L"\Device\SrvAdmin"`, a normal user causes `prjflt` to open
> `\Device\SrvAdmin` — normally restricted to administrators — and its
> `IRP_MJ_CREATE` routine `SrvNetCreate` (and `SrvNetCleanup`/`SrvNetClose` on
> close) is invoked on the user's behalf.

Because `prjflt` performs the `ZwCreateFile` in kernel context with an
attacker-chosen name, this is external control of a file/device path (CWE-73) that
grants a normal user access to privileged device create/cleanup routines — a local
EoP primitive.

---

## Prerequisites and Constraints

- Local, low-privileged (`PR:L`, `AV:L`, `AC:L`): connect to the ProjFS filter port
  with a crafted `_PRJ_CONNECTION_CONTEXT`.
- Set `szVolume` to an arbitrary object path (e.g. `\Device\SrvAdmin`) rather than a
  real volume.
- Result: `prjflt` opens the specified device and drives its create/cleanup/close
  routines.

---

## Vulnerability Details

### Root Cause

The user-supplied connection volume name was resolved and opened without validating
that it referred to a legitimate global volume path, so any device/object path
under the attacker's control reached `ZwCreateFile`.

### The patch (confirmed — diff, .7920 → .8036)

Gated behind `Feature_78846265`, `PrjfGetInstanceFromVolumeName` now routes the
user name through a **new validator `PrjfValidateAndGetGlobalVolumePath`** before
resolving it, so a name that is not a proper global volume path is rejected:

```c
// PrjfGetInstanceFromVolumeName (10.0.26100.8036) — PATCHED, feature-enabled branch (from our diff)
if (Feature_78846265__private_IsEnabledDeviceUsageNoInline()) {
    iVar1 = FltGetVolumeFromName(Globals, param_1, &local_b8);
    if (iVar1 >= 0)
        iVar1 = FltGetVolumeInstanceFromName(Globals, local_b8, 0, param_2);
    // validate the supplied name is a legitimate global volume path:
    iVar1 = PrjfValidateAndGetGlobalVolumePath(param_1, local_b0, param_3);
}
```

With `PrjfValidateAndGetGlobalVolumePath` confirming the name is a global volume
path, an arbitrary device path such as `\Device\SrvAdmin` no longer resolves,
closing the arbitrary-device-open.

### Patch Completeness Assessment

**CFR-gated behind `Feature_78846265`.** The validation runs only when the flag is
enabled; the original unrestricted path still ships when disabled. Verify
`Feature_78846265` is enabled to confirm the fix is live.

---

## Detection Guidance

**Behavioural.** ProjFS filter-port connections whose `_PRJ_CONNECTION_CONTEXT`
`szVolume` is a non-volume object path (e.g. `\Device\...` device names);
`ZwCreateFile` from `prjflt!PrjfGetInstanceFromVolumeName` targeting privileged
devices on unpatched/flag-disabled builds.

**Config.** The fix is CFR-gated — confirm `Feature_78846265` is enabled.

---

## References

- MSRC advisory — CVE-2026-24287 (Windows Projected File System Elevation of Privilege), released 2026-03-10, KB5079473.
- Full binary diff: `/data/patch_diffs/prjflt_sys-cve-2026-24287-ghidriff.md`
