Skip to content

Back to the catalog

OAuth Token Theft Through Microsoft's Front Door | Huntress
huntress.comwriteup

OAuth Token Theft Through Microsoft's Front Door | Huntress

Huntress researcher Andrew Schwartz demonstrates a novel OAuth token-theft technique: a sideloaded AppX package registered via Add-AppxPackage -Register (requiring only Developer Mode, no admin beyond that toggle) can set ContentUriRules WindowsRuntimeAccess="all" so attacker-controlled JavaScript rendered inside the Microsoft-signed WWAHost.exe process gets full WinRT access, including the legacy WebAuthenticationBroker OAuth API. Using Microsoft Office's own client ID and the oob redirect URI, the attacker triggers a genuine login.microsoftonline.com/MFA dialog with no browser chrome, captures the auth code, and exchanges it for an access token plus a long-lived refresh token carrying the full Office delegated Graph scope set (mail, files, Teams, directory, AuditLog.Create) — validated end-to-end against a live Entra ID tenant with MFA and default Conditional Access. The post frames it as a class of vulnerable signed AppX host binaries sharing the same WinRT activation layer, and provides a Sigma rule keyed on the MSAppHost/3.0 EdgeHTML user agent reaching non-Microsoft destinations, plus Sysmon/Event ID and GPO-based mitigations (restricting Developer Mode, Conditional Access, shorter refresh-token lifetimes, CAE).

TL;DR Sideloading an AppX package with WindowsRuntimeAccess="all" turns the signed WWAHost.exe into a genuine-looking Microsoft OAuth login that steals MFA-surviving refresh tokens with full Office Graph scopes — Huntress provides PoC, a Sigma detection rule, and GPO mitigations.
Document

What it is

Huntress researcher Andrew Schwartz's OAuth token-theft technique using WWAHost.exe. The catalog summary already has the core chain (sideloaded AppX + WindowsRuntimeAccess="all" → attacker JS in a Microsoft-signed host → real login.microsoftonline.com dialog → captured Office-scoped refresh token). What the summary omits and this page carries: the exact preconditions and error semantics, the mitigation commands, a broader WinRT abuse surface beyond OAuth, and a detection nuance that materially affects the Sigma rule.

Preconditions

  • Registration fails closed without one of two gates; the error text 0x80073CFF names both: Developer Mode or the enterprise AllowAllTrustedApps sideloading policy. The policy path is the more likely way a managed fleet ends up vulnerable at scale.
  • Enabling Developer Mode requires admin (UAC-gated Settings toggle, or the HKLM registry write). Everything after the toggle runs as standard user — no UAC, no signature check.
  • Common on dev machines, CI/CD runners, cloud VMs; can be pushed fleet-wide by GPO. Not on by default for end users.
  • Office first-party client ID: the page cites d590ed36-52b3-4102-aeff-aad2292ab01c in Step 2 but d3590ed6-52b3-4102-aeff-aad2292ab01c in Figure 8 (an internal inconsistency worth verifying before use). Redirect URI urn:ietf:wg:oauth:2.0:oob.
  • OAuth chain proven on Windows 11 24H2 (build 26100).

Beyond token theft (same WinRT surface, exercised on 22H2, not re-proven on 24H2)

  • CredentialPicker — native OS credential dialog returning plaintext username/password.
  • DataProtectionProvider (DPAPI) — encrypt/decrypt in the user's DPAPI context.
  • Launcher.launchUriAsync — invoked powershell:, cmd:, ms-msdt:, search-ms:, ms-officecmd: (some payloads Defender-blocked, launch mechanism succeeds).
  • WebAuthBroker silentMode — expected to yield PRT-backed tokens with no UI on a domain-joined machine; author explicitly did not confirm this end-to-end.

Detection caveat that the summary hides

The Sigma rule keys on the exfil leg's user agent MSAppHost/3.0 (EdgeHTML) to non-Microsoft hosts. But the sign-in leg is rendered by a different host — Entra logs record ...Trident/7.0; MSAuthHost/1.0; rv:11.0. So the Entra sign-in record looks like a clean Office sign-in (App "Microsoft Office", "Mobile Apps and Desktop clients", credential type None, no CA failure) and the rule will not fire on identity telemetry — only on proxy/network egress. Fixing individual binaries or an EDR rule for wwahost.exe alone is futile; the flaw is in the shared WinRT activation layer, so block the network signature, not the host.

Allow-list tradeoff: broadening the Microsoft-owned domain list cuts false positives but opens evasion via an open redirect / abandoned tenant subdomain / attacker SharePoint site on a Microsoft-owned domain. High-security environments can run the narrow list (.microsoft.com, .microsoftonline.com, .windows.net) and eat the noise.

What to do

Disable the prerequisite via GPO: Computer Configuration > Administrative Templates > Windows Components > App Package Deployment > Allow all trusted apps to install > Disabled (closes both Developer Mode and the enterprise policy path).

Inventory Developer Mode across the fleet:

$devMode = Get-ItemProperty `
  -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" `
  -Name "AllowDevelopmentWithoutDevLicense" -ErrorAction SilentlyContinue
if ($devMode.AllowDevelopmentWithoutDevLicense -eq 1) {
    Write-Host "DEVELOPER MODE ON: $env:COMPUTERNAME"
}

Corroborating IOCs (validated in lab, native — no Sysmon required): AppXDeploymentServer/Operational Event 400 (register success) and 613 (timing only); PowerShell script-block 4104 captures the manifest; WFP Security Event 5156 records the AppX-host process image + destination IP on outbound connections.

Also: CA requiring compliant/managed devices for token issuance (limits refresh-token reuse from unmanaged machines), Token Protection, shorter refresh-token lifetimes, and CAE to shrink the persistence window.

Caveats

Delegated scopes mean effective power is the intersection of the token scope and the victim's own privilege — Directory.Read.All here reads only what that user could read; blast radius scales with the victim's role. Author is deliberate about "proven" (WWAHost token theft, end-to-end) vs merely "available" (namespace resolves) for the wider host class and the extra capabilities above.

Organisations named here

  • AllowAllTrustedApps
  • AuditLog.Create
  • Continuous Access Evaluation
  • Dirk-jan Mollema
  • MSAppHost/3.0
  • MSIX'd Up: Weaponizing the Modern Windows App Packaging Ecosystem
  • Nick Powers
  • Token Protection

Technologies named here

  • Windows 11 24H2
  • Add-AppxPackage
  • Windows 11 22H2
  • WebAuthenticationBroker.authenticateAsync
  • WWAHost.exe
  • kali_listener.py
  • AppX web-host family
  • register_appx.ps1
  • WebAuthenticationBroker
  • exchange_token.py
  • Microsoft Entra ID
  • ApiInformation.IsTypePresent
  • Sysmon
  • Microsoft Office
  • Microsoft Graph API
  • Windows Filtering Platform auditing / Security Event 5156
  • AppXDeploymentServer/Operational Event Log
  • PowerShell Script Block Logging
  • Sigma
  • CredentialPicker
  • DataProtectionProvider / DPAPI
  • Launcher.launchUriAsync
  • askWAM
  • Conditional Access / Continuous Access Evaluation
  • Windows
  • OAuth
  • PowerShell
  • Kali Linux

Techniques named here

  • Signed-binary proxy execution via AppX web host
  • OAuth token theft via WinRT WebAuthenticationBroker
  • Sideloading of malicious AppX package
  • Refresh token persistence / abuse
  • Credential capture via fake-but-real system dialog
  • Protocol handler abuse for code execution
  • Silent/PRT-backed token acquisition
  • Network detection via anomalous EdgeHTML user agent