# CVE-2026-32074 — Windows Projected File System `prjflt.sys` Double Free of the Negative-Path-Cache Hash Table in `PrjfCreateUnionContext`

---

## Summary

| | |
|---|---|
| **Product** | Windows — `prjflt.sys` (Windows Projected File System / ProjFS minifilter) |
| **CVE ID** | CVE-2026-32074 |
| **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-415: Double Free |
| **Delivery** | Local — force the negative-path-cache hash-table allocation to fail during ProjFS union-context creation |
| **KB / Fixed build** | KB5083769 — `prjflt.sys` 10.0.26100.8246 (Win11 24H2 x64) |
| **Patch Date** | April 14, 2026 (2026-Apr) |
| **Pre-patch binary** | `prjflt.sys` 10.0.26100.8115 — SHA256 `51d12b128e33bc0110344cea5c6374192d525c9f918666c9886a57c5486e5d3d` |
| **Post-patch binary** | `prjflt.sys` 10.0.26100.8246 — SHA256 `6eeb5961eb44704a1515a3df15bbf02ce4e63c55b46fb00158a5d65c7b4fd555` |
| **Feature flag** | `Feature_440600889` — **the fix is CFR-gated** |
| **Exploitability** | Exploitation Less Likely; not publicly disclosed; not exploited (per MSRC) |

---

## Product Description

`prjflt.sys` is the Windows Projected File System (ProjFS) minifilter.
`PrjfCreateUnionContext` builds a per-virtualization `_PRJ_UNION_CONTEXT`; when
`PRJ_FLAG_USE_NEGATIVE_PATH_CACHE` (Flags bit 0) is set, it initializes a negative
lookup hash table (`UnionContext->NegtiveHashTable`) via `RtlCreateHashTableEx`
(default initial size `0x2000`).

---

## Vulnerability Summary

The double free arises from an ownership/cleanup interaction:

1. `PrjfCreateUnionContext` calls `RtlCreateHashTableEx` → `RtlpCreateHashTable`.
   For an initial size `> 0x80`, that allocates a `Directory` (`ExAllocatePool2`)
   and then per-bucket `SecondLevelDir`s. If a `RtlpAllocateSecondLevelDir` fails,
   it jumps to `RtlDeleteHashTable(HashTable)` and returns `false`.
2. **`RtlDeleteHashTable` frees `HashTable->Directory` (and the second-level dirs)
   but does not set `Directory` to NULL.** The hash-table struct still points at the
   freed `Directory`.
3. `RtlCreateHashTableEx` returning `false` makes `PrjfCreateUnionContext` take its
   error path and call `PrjfReleaseUnionContext(UnionContext)`.
4. `PrjfReleaseUnionContext`, seeing `(UnionContext->Flags & 1) != 0`, calls
   `RtlDeleteHashTable(&UnionContext->NegtiveHashTable)` **again** — freeing the
   already-freed `Directory` a **second time** (CWE-415 double free).

An unprivileged local user can reach `PrjfCreateUnionContext` through ProjFS
virtualization and induce the second-level-dir allocation to fail (pool pressure),
triggering the double free of a kernel pool allocation → exploitable EoP.

---

## Prerequisites and Constraints

- Local, low-privileged (`PR:L`, `AV:L`, `AC:L`); reach ProjFS union-context
  creation with `PRJ_FLAG_USE_NEGATIVE_PATH_CACHE` set.
- Force `RtlpAllocateSecondLevelDir` to fail (memory pressure) after `Directory`
  is allocated, so `RtlCreateHashTableEx` fails *after* the first `RtlDeleteHashTable`.
- Result: `PrjfReleaseUnionContext` frees the same `Directory` again → double free.

---

## Vulnerability Details

### Root Cause

`RtlDeleteHashTable` leaves a dangling `Directory` pointer in the hash-table struct
after freeing it, and `PrjfCreateUnionContext`'s failure path unconditionally calls
`PrjfReleaseUnionContext`, which (because `Flags & 1` is still set) deletes the same
hash table a second time.

### The patch (confirmed — diff, .8115 → .8246)

Gated behind `Feature_440600889`, `PrjfCreateUnionContext` **clears the
`PRJ_FLAG_USE_NEGATIVE_PATH_CACHE` bit** on the hash-table-creation-failure path, so
`PrjfReleaseUnionContext`'s `(Flags & 1)` guard is false and it does **not** call
`RtlDeleteHashTable` a second time:

```c
// PrjfCreateUnionContext (10.0.26100.8246) — PATCHED, feature-enabled branch (from our diff)
// on RtlCreateHashTableEx failure:
if ( Feature_440600889__private_IsEnabledDeviceUsage() )
    UnionContext->Flags = UnionContext->Flags & 0xFFFFFFFE;   // *** clear PRJ_FLAG_USE_NEGATIVE_PATH_CACHE ***
...
// later, PrjfReleaseUnionContext only deletes the hash table when (Flags & 1) != 0
```

With bit 0 cleared, the negative-path-cache teardown in `PrjfReleaseUnionContext`
is skipped, so the already-freed `Directory` is not freed again.

### Patch Completeness Assessment

**CFR-gated behind `Feature_440600889`.** The flag-clearing runs only when the CFR
flag is enabled; the original double-free path still ships when disabled. Verify
`Feature_440600889` is enabled to confirm the fix is live.

---

## Detection Guidance

**Behavioural.** ProjFS union-context creation under pool pressure that fails hash-
table allocation; double-free / pool-corruption bugchecks (`BAD_POOL_CALLER`) in
`prjflt!PrjfCreateUnionContext` / `PrjfReleaseUnionContext` → `RtlDeleteHashTable`
on unpatched/flag-disabled builds.

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

---

## References

- MSRC advisory — CVE-2026-32074 (Windows Projected File System Elevation of Privilege), released 2026-04-14, KB5083769.
- Full binary diff: `/data/patch_diffs/prjflt_sys-cve-2026-32074-ghidriff.md`
- Related same-KB ProjFS fix: CVE-2026-32078 (`PrjfScheduleExpansionWorkItem`).
