CVE-2026-49176 Exploit Development: WalletService to SYSTEM 17 July 2026 / 9 min read Updated: 17 July 2026 View more blogs with the tag windows , View more blogs with the tag vulnerability-research , View more blogs with the tag cve , View more blogs with the tag local-privilege-escalation , View more blogs with the tag exploit-development , View more blogs with the tag walletservice Table of Contents A standard user redirects WalletService to an attacker-seeded ESE database, loads a callback DLL as LocalSystem, then moves the resulting SYSTEM token into the active desktop session. TL;DR CVE-2026-49176 is a local privilege-escalation vulnerability in Windows WalletService. The public Wallet API allows a standard user to activate a LocalSystem service. During initialization, WalletService resolves the caller’s FOLDERID_Documents , appends a fixed Wallet component, reverts impersonation, and opens wallet.db with Extensible Storage Engine persisted callbacks enabled. The exploit proceeds as follows: standard user -> create an ESE wallet.db containing a persisted callback -> redirect the user's Documents known folder to the seeded parent -> call WalletManager.RequestStoreAsync and GetItemsAsync -> WalletService opens <Documents>\Wallet\wallet.db as LocalSystem -> ESE opens the mandatory Cards table -> ESE resolves the persisted callback as DLL!Export -> attacker DLL loads inside the SYSTEM service host -> SYSTEM token is moved into the active session -> interactive cmd.exe as NT AUTHORITY\SYSTEM Original vulnerability credit: Microsoft credits Chen Le Qi (@cplearns2h4ck) and Mochi Nishimiya (@MochiNishimiya) , both with STAR Labs SG , for reporting CVE-2026-49176. This post covers my independent root-cause analysis and exploit development, not the original discovery. Microsoft rates the issue Important , with a CVSS 3.1 score of 7.8 . The advisory maps it to CWE-269: Improper Privilege Management and CWE-59: Improper Link Resolution Before File Access . The WalletService attack surface WalletService backs the public Windows.ApplicationModel.Wallet WinRT API. An ordinary user can reach the service through the intended public route: WalletManager.RequestStoreAsync() -> WalletItemStore.GetItemsAsync() -> WalletService activation -> Wallet item manager initialization -> WalletDatabaseESE::Open Direct activation of the private Wallet COM class is capability-gated and returned E_ACCESSDENIED from a standard desktop process. That was not a blocker because the public Wallet API performs the supported activation and reaches the same privileged initialization path. The trust boundary is crossed while the service builds its application-data path. WalletService obtains the caller token, resolves that token’s Documents known folder, then continues after reverting to itself: CoImpersonateClient -> OpenThreadToken -> SHGetKnownFolderPath(FOLDERID_Documents, caller token) -> CoRevertToSelf -> append "\Wallet\" -> open wallet.db as LocalSystem A Windows user can change that user’s Documents mapping with SHSetKnownFolderPath . WalletService then treats the resulting path as trusted service storage, even though the caller controls both the location and any pre-existing Wallet child. The bug is in that handoff. The service uses caller-derived identity state to select a pathname, then crosses back into LocalSystem before deciding what the object at that pathname may contain. What the July patch changed Patch diffing localized the fix to a servicing feature named: Feature_Servicing_WalletServiceRedirectionGuard internal feature ID: 3305877819 The fixed build gates several legacy operations: Function Fixed behavior WalletDatabaseESE::Open Returns before opening the ESE database ServerUtils::HideAndRestrictFolder Skips the legacy folder restriction RestrictFolder Skips replacement of the directory DACL FileUtils::DeleteFiles Skips legacy cleanup deletion WalletDatabaseESE::HandleDatabaseCorruption Skips corruption cleanup The directory is created before the guarded ESE open. That produces a clear patched differential: build 26200.8875 can still leave an empty Wallet directory, but it does not open wallet.db , create ESE files, replace the DACL, or resolve a persisted callback. Proving the filesystem primitive first I initially treated the issue as a privileged filesystem problem rather than assuming it was already code execution. A bounded test redirected a standard user’s Documents folder to a disposable parent where the account had read and execute access but could not create files. On vulnerable build 26200.8737 , GetItemsAsync() caused LocalSystem to create: <chosen parent>\Wallet\ WalletService then replaced the child directory’s DACL with SYSTEM and Administrators full control and created the normal ESE file family: edb.chk edb.log edbres00001.jrs edbres00002.jrs edbtmp.log wallet.db wallet.jfm On fixed build 26200.8875 , the same call created only an empty Wallet directory with inherited access. No ESE files appeared and no re...
CVE-2026-49176 is a local privilege escalation vulnerability in the Windows WalletService where a standard user can redirect the service to load a malicious ESE database file, triggering a persisted callback that loads an attacker DLL with SYSTEM privileges. It has a CVSS 3.1 score of 7.8 (High). Affected versions include Windows 10 1607 prior to 10.0.14393.9339, 1809 prior to 10.0.17763.9020, and 21H2 prior to 10.0.19044.7548, among others listed in the NVD data.