Like leaving a SYSTEM-signed blank check in every user's Documents folder
CVE-2026-49176 is a local privilege escalation in the Windows WalletService present on all supported Windows client and server editions with Desktop Experience. The root cause is an impersonation context switch bug: WalletService resolves FOLDERID_Documents while impersonating the *caller* (standard user), then reverts to LocalSystem before actually opening <Documents>\Wallet\wallet.db. Because a standard user can redirect their Documents folder via SHSetKnownFolderPath and pre-seed a crafted Extensible Storage Engine (ESE) database with a persisted callback column, the service loads an attacker-controlled DLL into its SYSTEM-privileged svchost.exe process. The result is deterministic, race-free code execution as NT AUTHORITY\SYSTEM. Affected builds span Windows 10 1607 through Windows 11 26H1, plus Windows Server 2016, 2019, 2022, and 2025. Microsoft patched it in the July 14, 2026 cumulative updates.
Microsoft rated this Important / HIGH (CVSS 7.8), and that score is well-calibrated. The AV:L prerequisite correctly captures the local-only attack surface, while AC:L and PR:L reflect the trivial exploitation complexity — no heap spray, no race condition, no user interaction. The public PoC from David Carliez and a separate Cobalt Strike Beacon Object File (777erp/CVE-2026-49176_BOF) have turned this into a push-button LPE for any operator with an existing Beacon session. Despite weaponization, the local-access gate prevents a CRITICAL rating. The vendor's 7.8 holds.
5 steps from start to impact.
Seed the malicious ESE database
wallet.db) with the mandatory Cards table. A tagged column is added with the JET_bitColumnUserDefinedDefault flag, storing a persisted callback specification pointing to an attacker-controlled DLL (e.g., C:\Users\<user>\payload\callback.dll!DllMain). The callback DLL is placed in a sibling directory outside the Wallet subdirectory. This requires only standard user file-write permissions — no admin, no UAC prompt.- Standard (non-admin) interactive or Beacon session on the target host
- Ability to write files to user-profile directories
- Requires prior compromise — the attacker must already have code execution as a standard user on the machine
wallet.db outside %LOCALAPPDATA%Redirect FOLDERID_Documents
SHSetKnownFolderPath to redirect their FOLDERID_Documents known folder to a controlled directory containing the seeded Wallet\wallet.db. This is a legitimate Win32 API available to any standard user — no privilege check beyond owning the user profile. The redirection is persisted in the registry under HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders.- User-level access to Shell32 API or PowerShell equivalent
- Some EDR products flag known-folder redirection, though most don't treat it as high-severity
User Shell Folders\Personal; behavioral rule for Documents folder redirection immediately preceding WalletService activityTrigger WalletService via WinRT API
Windows.ApplicationModel.Wallet.WalletManager.RequestStoreAsync() followed by GetItemsAsync(). These are public, documented WinRT APIs accessible from any standard user token — no capability or permission gates. This causes WalletService to start (it runs as Manual by default), impersonate the caller to resolve Documents, then revert to LocalSystem before opening the database.- WalletService must be registered and not disabled
- WinRT Wallet namespace must be accessible (default on all Desktop Experience installs)
- WalletService can be disabled via GPO or registry — but this is not a common hardening step outside mature AD environments
- Server Core installs do not include WalletService
svchost.exe -k WalletServiceGroup start correlated with prior Wallet API calls; ETW WinRT activation tracingESE loads attacker DLL as SYSTEM
wallet.db with JET_paramEnablePersistedCallbacks enabled. When it accesses the Cards table, the ESE engine resolves the persisted callback metadata and calls LoadLibrary on the attacker-specified DLL path — now executing in the svchost.exe process running as NT AUTHORITY\SYSTEM. This is the privilege boundary crossing: a user-created artifact triggers SYSTEM-context code execution with zero race conditions.- The seeded database must be well-formed ESE with valid callback metadata
- The callback DLL must be accessible at the stored path
- Application whitelisting / WDAC policies that block DLL loads from user-writable paths will stop this step
- Some EDR products detect unusual DLL loads into
svchost.exe
svchost.exe (WalletService) loading a DLL from a user-profile path; CrowdStrike/Defender for Endpoint suspicious module injection alertsSYSTEM shell delivery
WinLocalSystemSid, creates a temporary Windows service pointing to a shell broker executable, duplicates the SYSTEM token with the session ID adjusted to the active console session, and spawns cmd.exe on winsta0\default. The temporary service registration is deleted immediately afterward, minimizing forensic artifacts. The attacker now has an interactive SYSTEM shell.- Successful DLL execution in SYSTEM context from step 4
- EDR behavioral detection for SYSTEM-context process creation on interactive desktops
- Service creation/deletion auditing (Event ID 7045/7036)
cmd.exe on interactive desktopHKLM\SYSTEM\CurrentControlSet\Services\WalletService\Start to 4 (Disabled) across your fleet via Group Policy Preferences or SCCM compliance baseline. This completely breaks the attack chain at step 3 — WalletService cannot be triggered if the service is disabled. Microsoft's own fix effectively neuters the service, so disabling it proactively has no operational impact on enterprise workstations or servers. WalletService is used only by the legacy Wallet app, which has no enterprise use case. Deploy within 30 days per the noisgate mitigation SLA for HIGH-severity findings.svchost.exe from loading DLLs out of user-profile directories (C:\Users\*). This blocks step 4 of the chain — even if the attacker seeds the database and triggers WalletService, the ESE callback LoadLibrary call will fail against the WDAC policy. Deploy within 30 days. Note: WDAC DLL enforcement requires careful testing to avoid blocking legitimate user-installed applications.Feature_Servicing_WalletServiceRedirectionGuard which prevents WalletService from opening user-influenced database paths entirely. This is the definitive fix. Target completion within 180 days per the noisgate remediation SLA for HIGH-severity findings. Prioritize RDS/terminal servers and any Server Desktop Experience installs first.HKCU\...\User Shell Folders\Personal with subsequent WalletService (svchost.exe -k WalletServiceGroup) process creation within a 60-second window. Also alert on svchost.exe (WalletService) loading DLLs from user-writable paths. This does not prevent exploitation but provides high-fidelity detection for active exploitation attempts. Deploy within 30 days.- UAC / Admin Approval Mode — the entire chain executes from a standard (medium-integrity) user context. UAC is never triggered because no admin-level operation is requested by the attacker; WalletService itself performs the privileged operations.
- Network segmentation / firewall rules — this is a local privilege escalation with no network component. No amount of network-level controls affect the attack path.
- Credential Guard / LSA Protection — these protect credential stores but do not prevent the WalletService impersonation context switch or ESE callback loading. The attacker gains SYSTEM independently of credential-theft defenses.
- Removing the Wallet app — the vulnerability is in the WalletService *service*, not the UWP Wallet app. Uninstalling the app does not remove or disable the service.
The supporting signals.
| In-the-Wild Status | Weaponized — Cobalt Strike BOF available (777erp/CVE-2026-49176_BOF); Feedly threat intel tags Cobalt Strike as a malware family actively using this. No confirmed mass exploitation campaigns or CISA KEV listing. |
|---|---|
| Proof-of-Concept | Public, multiple implementations. Original PoC by DavidCarliez/CVE-2026-49176_LPE_POC (57 ★, 19 forks, released Aug 10 2026) — includes trigger.ps1, build.ps1, and source. Separate Cobalt Strike BOF by 777erp with standalone and BOF modes. Exploit is deterministic and fully automated. |
| Researchers | Discovered by Chen Le Qi and Mochi Nishimiya of STAR Labs SG (credited in MSRC advisory). Independent exploit development and PoC by David Carliez (blog writeup). |
| EPSS | 0.328% probability of exploitation in next 30 days (15.2nd percentile). Low EPSS likely reflects the local-access prerequisite rather than exploitability. |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — Local access, low complexity, low privilege required, no user interaction, unchanged scope. Full CIA impact on the host. |
| Affected Versions | Windows 10 (1607, 1809, 21H2, 22H2), Windows 11 (24H2, 25H2, 26H1), Windows Server 2016/2019/2022/2025. Essentially all supported Windows with Desktop Experience. Server Core is not affected. |
| Fixed Versions | Win 10 1607: 14393.9339, Win 10 1809: 17763.9020, Win 10 21H2/22H2: 19044.7548/19045.7548, Win 11 24H2: 26100.8875, Win 11 25H2: 26200.8875, Server 2016: 14393.9339, Server 2019: 17763.9020, Server 2022: 20348.5386, Server 2025: 26100.33158. 0patch micropatches available for legacy builds (Win 10 1803–22H2, Win 11 21H2–22H2, Server 2008 R2–2012 R2). |
| Scanning / Exposure | Not remotely exploitable — no Shodan/GreyNoise/Censys exposure surface. This is a local-only vulnerability. Vulnerability scanners (Qualys, Tenable, Rapid7) detect via missing KB/build-number checks. |
| Disclosure Timeline | July 14, 2026 — Microsoft advisory and patch release (Patch Tuesday). Aug 10, 2026 — David Carliez public PoC. Oct 2, 2026 — 0patch micropatches for legacy Windows. |
Sources.
- NVD Detail — CVE-2026-49176
- David Carliez — WalletService to SYSTEM exploit writeup
- DavidCarliez/CVE-2026-49176_LPE_POC (GitHub)
- 777erp/CVE-2026-49176_BOF — Cobalt Strike BOF (GitHub)
- CyberSecurityNews — WalletService Vulnerability PoC Released
- GBHackers — WalletService Flaw Lets Standard Users Gain SYSTEM Privileges
- Strix.ai — CVE-2026-49176 affected versions
- AD Hardening — Disable WalletService on DCs
Why this verdict
- Weaponized with public PoC and Cobalt Strike BOF — exploitation is deterministic, race-free, and fully automated. Any operator with a standard-user Beacon session can escalate to SYSTEM in seconds. This keeps the score at or above the vendor baseline.
- Local access prerequisite is real friction — the attacker must already have code execution as a standard user on the target host. This is a post-initial-access primitive, not an entry vector. It bounds the score below CRITICAL.
- Wide affected surface with no configuration prerequisite — WalletService is registered and set to Manual start on every Desktop Experience install across all supported Windows versions. The attacker triggers it on demand via public WinRT APIs. No exotic feature flag or optional role required.
- Role multiplier: Workstations (>80% of Windows installs) — the chain succeeds trivially. Blast radius is host-level (standard user → SYSTEM). Valuable for lateral movement, credential harvesting, EDR tampering, and persistence. Outcome: host compromise. This supports HIGH.
- Role multiplier: Domain Controllers (~2-3% of Windows Server installs) — WalletService is present on DCs with Desktop Experience (common for Server 2016/2019/2022). The chain technically succeeds if an attacker has any code execution context on the DC. However, standard users do not have interactive logon rights to DCs in properly configured environments, adding significant friction. IF reached, outcome is domain takeover (SYSTEM on a DC = full AD control). This sets the floor at HIGH per the blast-radius rule.
- Role multiplier: RDS/Terminal Servers and VDI hosts — multi-user environments where a compromised standard user can escalate to SYSTEM and access all user sessions, cached credentials, and security tooling. Blast radius: multi-tenant host compromise. Supports HIGH.
- No confirmed mass exploitation or KEV listing — despite weaponization, there are no documented campaigns using this at scale. EPSS at 0.328% reflects low observed exploitation probability. This prevents a bump above the baseline.
Why not higher?
The vulnerability requires local authenticated access — it is not remotely exploitable and cannot be used for initial access. The CVSS Scope is Unchanged (S:U), meaning compromise is contained to the target host. While the DC scenario theoretically enables domain takeover, standard users lack interactive logon rights to DCs in any reasonably hardened environment, and the attacker would need a prior compromise of the DC itself. The absence of KEV listing, mass exploitation campaigns, and the low EPSS score all argue against CRITICAL.
Why not lower?
The exploitation chain is trivially reliable — no race condition, no memory corruption, no heap spray, no user interaction. A public Cobalt Strike BOF means this is now standard post-exploitation tradecraft. WalletService is present on every Desktop Experience install with no opt-in required. On RDS/terminal servers, the blast radius extends beyond a single user. The weaponization into CS BOF format means threat actors with initial access *will* use this. Downgrading below HIGH would understate the real-world risk to any fleet running unpatched Windows.
Crowdsourced verification payload.
Run this script on each target Windows host as any user (no admin required). Execute via powershell.exe -ExecutionPolicy Bypass -File .\Check-CVE-2026-49176.ps1 or paste into a remote PowerShell session. The script checks both the OS build/UBR against fixed versions AND whether WalletService is disabled (compensating control).
#Requires -Version 3.0
<#
Check-CVE-2026-49176.ps1
Checks whether the host is vulnerable to CVE-2026-49176
(Windows WalletService LPE via ESE persisted callbacks).
Exit codes: 1 = VULNERABLE, 0 = PATCHED, 2 = UNKNOWN
#>
$ErrorActionPreference = 'Stop'
try {
$build = [int](Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name CurrentBuildNumber).CurrentBuildNumber
$ubr = [int](Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR).UBR
# Map build families to fixed UBR thresholds
$fixedUBR = switch ($build) {
14393 { 9339 } # Win 10 1607 / Server 2016
17763 { 9020 } # Win 10 1809 / Server 2019
19044 { 7548 } # Win 10 21H2
19045 { 7548 } # Win 10 22H2
20348 { 5386 } # Server 2022
26100 { 8875 } # Win 11 24H2 / Server 2025 (client branch)
26200 { 8875 } # Win 11 25H2
28000 { 2269 } # Win 11 26H1
default { $null }
}
# Check WalletService state
$svcDisabled = $false
try {
$svc = Get-Service -Name WalletService -ErrorAction Stop
if ($svc.StartType -eq 'Disabled') { $svcDisabled = $true }
} catch {
# Service not found (Server Core or removed) - not vulnerable
Write-Host 'PATCHED - WalletService not present (Server Core or removed).'
exit 0
}
if ($null -eq $fixedUBR) {
if ($svcDisabled) {
Write-Host "PATCHED - Build $build.$ubr is not in the known affected range, and WalletService is disabled."
exit 0
}
Write-Host "UNKNOWN - Build $build.$ubr is not in the known affected build family list. Manual review required."
exit 2
}
$patched = $ubr -ge $fixedUBR
if ($patched) {
Write-Host "PATCHED - Build $build.$ubr meets or exceeds fixed UBR $fixedUBR."
exit 0
} elseif ($svcDisabled) {
Write-Host "VULNERABLE (MITIGATED) - Build $build.$ubr is below fixed UBR $fixedUBR, but WalletService is disabled."
exit 0
} else {
Write-Host "VULNERABLE - Build $build.$ubr is below fixed UBR $fixedUBR and WalletService is enabled."
exit 1
}
} catch {
Write-Host "UNKNOWN - Error during check: $_"
exit 2
}