A cleanup routine in the Win32 App Isolation broker frees its own linked-list head and then keeps walking it
The bug lives in bfs.sys, the Brokering File System mini-filter Microsoft introduced to back Win32 App Isolation (AppSilo containers). During BfsCloseStorage, the driver deallocates the head of the DirectoryBlockList on the first loop iteration and then continues to dereference the freed chunk on subsequent iterations — a textbook use-after-free with a race window. A local, authenticated caller who can obtain a handle with the right AppSilo-flavored token and issue the vulnerable IOCTL against a PolicyEntry whose StorageObject holds multiple DirectoryBlockList entries can groom the pool and land arbitrary kernel writes → SYSTEM. Affected surface is every currently-supported Windows 10, Windows 11, and Windows Server SKU that ships bfs.sys (introduced roughly two years before disclosure, so 22H2 forward on the client side and Server 2022/2025 on the server side).
Microsoft's HIGH / 7.8 is defensible but a touch generous. The AV:L/PR:L/UI:N/C:H/I:H/A:H math correctly captures the *impact* — full kernel-mode compromise — but the practical exploitability is 'Less Likely' by Microsoft's own assessment: a narrow deallocation-to-reuse race, dependent on AppSilo token possession, with no public PoC and an EPSS of 0.18%. Real-world posture: this is a second-stage tool in a post-phish/post-malware chain, not a wormable primitive. We hold it at HIGH because the *target population is 100% of the Windows fleet* and kernel LPEs are the standard rung in every commodity intrusion — but we tick the reassessed score down to 7.0 to reflect the race-window friction.
5 steps from start to impact.
Land unprivileged code execution on the host
- Local execution as any authenticated user
- Ability to open handles and issue IOCTLs
- Requires prior initial access — EDR, AppLocker/WDAC, MOTW, and SmartScreen all sit in front of this step
- Cloud-only workloads with no interactive users remove most delivery vectors
Acquire an AppSilo-capable token
HT3Labs on the earlier bfs.sys UAF family) shows this is typically obtained by spawning or hijacking a process launched under an AppSilo manifest, or by borrowing a token via NtImpersonateThread from an already-isolated app instance (Edge WebView, MSIX-packaged apps, some Store apps).- Presence of at least one AppSilo/AppContainer parent on the host
- SeImpersonatePrivilege *not* required — token duplication via handle inheritance suffices
- Hosts with no Store/AppSilo apps installed have very little AppSilo token surface at rest
- Server SKUs typically don't run isolated Win32 apps
Populate the PolicyTable and DirectoryBlockList
PolicyEntry whose StorageObject carries multiple DirectoryBlockList nodes. This is the setup that makes the loop iterate more than once, which is what causes the freed head to be dereferenced on iteration 2+.- Ability to invoke AppSilo storage registration ioctls
- Kernel pool grooming primitives (standard on modern Windows via
NtCreateSection,NtAllocateVirtualMemory)
- Race window is small — many attempts required, easy for EDR to notice loop patterns
- KVA Shadow, HVCI, and Kernel CFG raise the exploitation bar for the pool spray step
Microsoft-Windows-Kernel-File provider will log unusual ioctl bursts against bfs.sys if verbose auditing is onTrigger BfsCloseStorage and win the race
Pipe Attribute or NamedPipe spray). Winning the race converts the UAF into a controlled kernel write.- Multi-core CPU (trivially met)
- Reliable pool-spray primitive
- Race windows on modern Windows kernels are unreliable — most PoCs need thousands of attempts
- Kernel telemetry from EDR sensors flag crash loops when the race is lost
BAD_POOL_HEADER, KERNEL_MODE_HEAP_CORRUPTION) from failed exploit attempts — CIRT should treat repeated bugchecks on one host as a strong indicatorElevate to SYSTEM and persist
PID 4's (System) token — the standard token-stealing primitive — yielding NT AUTHORITY\SYSTEM. From there: disable EDR (fltmc unload), dump LSASS, install driver-level persistence, or move laterally with the machine account.- Successful step 4
- HVCI blocks arbitrary kernel driver load
- Credential Guard prevents LSASS secret theft even after SYSTEM
The supporting signals.
| In-the-wild status | No confirmed exploitation as of 2026-07-23. Microsoft marks this 'Exploitation Less Likely'. Not on CISA KEV. |
|---|---|
| Public PoC | None specific to CVE-2026-50458. The *sibling* bug CVE-2025-29970 (same driver, same class, disclosed by HT3Labs) has a public technical writeup that maps closely to this bug's primitive. |
| EPSS | 0.00184 (0.18%) — bottom-quartile, consistent with a local-only kernel UAF with no PoC |
| KEV status | Not listed |
| CVSS | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H → 7.8 HIGH. Local, low-priv, no UI, full CIA — the classic LPE-to-SYSTEM shape |
| CWE | CWE-362 (race condition) chained with CWE-416 (use-after-free) |
| Affected versions | Windows 10 22H2, Windows 11 22H2/23H2/24H2, Windows Server 2022, Windows Server 2025 — every SKU carrying bfs.sys |
| Fixed by | July 2026 Patch Tuesday cumulative updates (KB numbers vary by SKU — see MSRC advisory). No standalone hotfix. |
| Internet exposure | Not applicable — local vector. Shodan/Censys/GreyNoise scan data irrelevant; every Windows host in the fleet is affected regardless of network posture |
| Disclosure | 2026-07-14 via MSRC; researcher credit not published in the advisory (bfs.sys UAF class has been tracked by HT3Labs, Angelboy@DEVCORE, and Filip Dragović) |
noisgate verdict.
The single decisive factor is role ubiquity crossed with kernel-mode blast radius: bfs.sys ships on every supported Windows client and server, and a successful chain yields SYSTEM — the canonical LPE outcome that unlocks the rest of every commodity intrusion playbook. Race-condition friction and 'Exploitation Less Likely' pull the reassessed score down inside the HIGH bucket but cannot break the floor: an authenticated local kernel UAF affecting 100% of the Windows fleet stays HIGH until a PoC drops or telemetry says otherwise.
Why this verdict
- Ubiquity multiplier:
bfs.sysis present on every modern Windows SKU — the affected population is effectively the entire Windows install base, not a niche product - Role multiplier: on workstations the chain ends at local SYSTEM (host-scoped blast radius); on domain-joined servers with cached admin tickets, on jump hosts, on Tier-0 admin workstations, and on RDS/AVD session hosts the same SYSTEM primitive is the launchpad for Kerberoasting, LSASS dumping (where Credential Guard is off), and lateral movement — chain succeeds and blast radius reaches domain-scale. Floor is HIGH.
- Friction — race window: UAF requires winning a deallocation-to-reuse race against pool sprays; historically this class of Windows kernel race takes hundreds to thousands of attempts, producing bugchecks that any competent EDR treats as an incident
- Friction — prior compromise required: AV:L/PR:L means the attacker is *already on the box* as a user; this is a second-stage weapon, not an initial-access vector — that's what keeps the score at 7.0 instead of the vendor's 7.8
- Friction — no PoC, no ITW: EPSS 0.18%, Microsoft 'Exploitation Less Likely', KEV clean. Real weaponization pressure is currently low
Why not higher?
Not CRITICAL because there is no unauthenticated network vector, no PoC, no observed exploitation, and the race-window reliability is genuinely poor. Kernel LPEs in the Microsoft catalog only cross into CRITICAL when a working exploit is public or in ransomware toolkits (Nokoyawa's PPL bypass, Lace Tempest's CLFS chain) — this one is neither.
Why not lower?
Not MEDIUM because bfs.sys is on every Windows host in your fleet and the payoff is SYSTEM. Downgrading a ubiquitous kernel UAF to MEDIUM based purely on 'no PoC yet' is how organizations end up patching in the 365-day backlog window and then getting mugged when the exploit lands in Cobalt Strike's BOF library six weeks later.
What to do — in priority order.
- Enable HVCI and Memory Integrity fleet-wide — Hypervisor-protected Code Integrity substantially raises the cost of turning a kernel UAF into arbitrary kernel execution. Push via Intune / GPO under Device Guard. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
- Enforce Credential Guard on all workstations and Tier-1/Tier-0 servers — Even if the attacker reaches SYSTEM via this UAF, Credential Guard denies them cached Kerberos TGTs and NTLM hashes from LSASS — that cuts off the domain-lateral leg of the chain. Deploy within 30 days.
- Set your EDR to alert on unexpected bugchecks — Failed race exploits crash the box with
BAD_POOL_HEADER/KERNEL_MODE_HEAP_CORRUPTION. Two+ bugchecks on one endpoint inside 24h should page the SOC. Tune this rule this week while the patch rolls. - Restrict AppSilo/MSIX app installation via WDAC — The token acquisition step requires an AppSilo-capable parent process. On server SKUs with no legitimate need for isolated Win32 apps, block MSIX/AppSilo package registration outright. Within 30 days.
- Deploy the July 2026 cumulative update ring — Ring-0 → Ring-1 → Ring-2 → fleet. Kernel patches historically ship clean; there is no known regression on the July 2026 CU set. Complete fleet rollout within 180 days per the noisgate remediation SLA for HIGH.
- Perimeter firewalls / IPS rules — the vector is local; no packet traverses the wire
- Least-privilege user accounts — PR:L; a standard user token is already sufficient, removing local admin does nothing
- Application allowlisting alone (AppLocker) — helps against step 1 initial-access, does not stop the kernel primitive if the attacker uses a signed LOLBIN to load their staging code
- Disabling SMB / RDP — unrelated attack surface; bfs.sys ioctls are local kernel calls
Crowdsourced verification payload.
Run on the target Windows host in an elevated PowerShell session (Run as Administrator). The script checks the version of bfs.sys against the July 2026 Patch Tuesday fixed build. Invoke as: powershell.exe -ExecutionPolicy Bypass -File .\Check-CVE-2026-50458.ps1. Requires local admin to read the driver metadata reliably.
#requires -RunAsAdministrator
# Check-CVE-2026-50458.ps1
# noisgate verification for Microsoft Brokering File System UAF (CVE-2026-50458)
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
$ErrorActionPreference = 'Stop'
$driver = Join-Path $env:SystemRoot 'System32\drivers\bfs.sys'
if (-not (Test-Path $driver)) {
Write-Output 'PATCHED (bfs.sys not present on this SKU — not affected)'
exit 0
}
try {
$info = (Get-Item $driver).VersionInfo
$ver = [Version]$info.FileVersion.Split(' ')[0]
Write-Output "bfs.sys version: $ver"
# July 2026 Patch Tuesday fixed build floors (verify against MSRC advisory for your SKU):
# Windows 11 24H2 : 10.0.26100.4500 or later
# Windows 11 23H2 : 10.0.22631.4900 or later
# Windows 10 22H2 : 10.0.19041.5300 or later
# Server 2025 : 10.0.26100.4500 or later
# Server 2022 : 10.0.20348.3200 or later
$build = $ver.Build
$revision = $ver.Revision
$fixed = switch ($build) {
26100 { 4500 }
22631 { 4900 }
22621 { 4900 }
19041 { 5300 }
20348 { 3200 }
default { $null }
}
if ($null -eq $fixed) {
Write-Output "UNKNOWN (unrecognized build $build — check MSRC advisory manually)"
exit 2
}
if ($revision -ge $fixed) {
Write-Output "PATCHED (revision $revision >= fixed floor $fixed for build $build)"
exit 0
} else {
Write-Output "VULNERABLE (revision $revision < fixed floor $fixed for build $build) — apply July 2026 cumulative update"
exit 1
}
} catch {
Write-Output "UNKNOWN (error reading bfs.sys: $_)"
exit 2
}
If you remember one thing.
Sources
- MSRC advisory — CVE-2026-50458
- MSRC advisory — sibling CVE-2026-49162 (same driver)
- GBHackers — bfs.sys UAF technical writeup (CVE-2025-29970 predecessor)
- Cybersecurity News — Brokering File System LPE analysis
- SentinelOne vulnerability database — related bfs.sys CVE
- Rapid7 vuln DB — CVE-2026-58526 (same UAF class)
- CISA Known Exploited Vulnerabilities catalog
- FIRST EPSS model
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.