CVE: CVE-2026-69446
MSRC Cases: 114396 (EdgeUpdater), 122314 (Microsoft To Do)
Severity: Elevation of Privilege
Affected: Microsoft Edge for macOS (EdgeUpdater), Microsoft To Do for macOS
Credit: Maliq Barnard
Two products, one vulnerability class
Microsoft ships multiple macOS binaries without the code signing flags that prevent dylib injection. I found it in two of them — EdgeUpdater and Microsoft To Do — each with a different exploitation depth. Both are grouped under CVE-2026-69446.
The root cause is the same: missing CS_RESTRICT and library-validation in production binaries. On macOS, without CS_RESTRICT, dyld does not strip DYLD_INSERT_LIBRARIES from the environment. Without library-validation, dylibs signed by any identity — including ad-hoc — are loaded. Set one environment variable, inject arbitrary code.
This is the same vulnerability class as CVE-2024-42220 through CVE-2024-42227, where Cisco Talos received eight separate CVEs for the same issue across eight different Microsoft macOS apps. I found two more products still affected.
Part 1: EdgeUpdater — root escalation through install.sh
Every binary in Edge for macOS ships with hardened code signing except EdgeUpdater. Here is what the flags look like across Edge 147.0.3912.72:
| Binary | Flags | CS_RESTRICT | Library Validation | CS_KILL | SDK |
|---|---|---|---|---|---|
| Microsoft Edge | 0x12a00 | Yes | Yes | Yes | 26.2.0 |
| Microsoft Edge Helper | 0x12a00 | Yes | Yes | Yes | 26.2.0 |
| Edge Helper (GPU) | 0x10a00 | Yes | No | Yes | 26.2.0 |
| Edge Helper (Renderer) | 0x10a00 | Yes | No | Yes | 26.2.0 |
| EdgeUpdater | 0x10000 | No | No | No | 15.2.0 |
| updater_oneds.so | 0x10000 | No | No | No | 15.2.0 |
EdgeUpdater is built against macOS 12 SDK (Runtime Version 15.2.0) while everything else targets macOS 26 SDK. A component compiled years ago and never brought forward.
The escalation to root goes through install.sh, shipped at Microsoft Edge Framework.framework/Resources/install.sh. This script runs with bash -p to preserve EUID=0 and directly executes EdgeUpdater with --install --system at line 136. It sanitizes $PATH but does not sanitize DYLD_* environment variables. If DYLD_INSERT_LIBRARIES is set when the script runs as root, the injected dylib executes as root inside EdgeUpdater.
The PoC injected a dylib into EdgeUpdater and accessed 208 keychain items, including Safari Forms AutoFill Encryption Key, ProtectedCloudStorage entries, and Apple assistant certificates. Both the parent process and its spawned child were injected. EdgeUpdater also disables App Transport Security entirely (NSAllowsArbitraryLoads = true), giving the injected code unrestricted network access.
Part 2: Microsoft To Do — OneAuth token theft
Microsoft To Do (v2.169, com.microsoft.to-do-mac) ships with com.apple.security.cs.disable-library-validation=true in its production entitlements. Same injection vector, but the exploitation goes much deeper because To Do loads the full OneAuth/MSAL authentication framework.
The chain, all steps live-verified on macOS 26.6:
- Code injection — unsigned dylib loaded via
DYLD_INSERT_LIBRARIES, constructor runs inside the App Sandbox (PID 5823).
- Keychain theft — 225 keychain items enumerated, including Chrome Safe Storage key, Safari Forms AutoFill Encryption Key, ChatGPT private access tokens, Cursor/Codex safe storage keys, and AirPlay server identity.
- Cross-app keychain access — all Microsoft shared keychain groups accessible:
UBF8T346G9.com.microsoft.identity.universalstorage,com.microsoft.adalcache,com.microsoft.edgemac.devicetrust,com.microsoft.edgemac.webauthn.
- OneAuth OAuth redirect bypass — called
+[MSAIMSIDRedirectUriVerifier msidRedirectUriWithCustomUri:clientId:bypassRedirectValidation:error:]withbypassRedirectValidation:YES. Returned a validMSAIMSIDRedirectUriobject. This enables redirecting OAuth token flows to attacker-controlled endpoints.
- MSAL token cache API — instantiated
MSAIMSIDDefaultTokenCacheAccessorwithMSAIMSIDMacKeychainTokenCacheas the data source. CalledallTokensWithContext:error:— succeeded. On a machine with a signed-in Microsoft account, this returns access tokens, refresh tokens, ID tokens, and Primary Refresh Tokens for all Microsoft services.
- 435 MSAL classes loaded — the full OneAuth framework is callable from injected code, including
MSAIMSIDAccessToken,MSAIMSIDRefreshToken,MSAIMSIDIdToken,MSAIMSIDPrimaryRefreshToken, andMSAIMSIDFamilyRefreshToken. Token classes expose.accessToken,.refreshToken,.rawIdToken, and.sessionKeyproperties.
The key difference from EdgeUpdater: To Do runs inside the App Sandbox, so the injected code inherits all of the app's sandbox entitlements and keychain access groups — including the identity groups shared across every Microsoft app on the Mac. That makes this a credential theft chain, not just code execution.
The fix
Microsoft confirmed the EdgeUpdater behavior on June 11, 2026, and the To Do chain on July 15, 2026. CVE-2026-69446 was published August 11, 2026. The fix adds the missing code signing flags and removes the disable-library-validation entitlement from production builds.
Timeline
| Date | Event |
|---|---|
| April 24, 2026 | EdgeUpdater submitted to MSRC (VULN-184326) |
| April 24, 2026 | Case 114396 opened |
| June 11, 2026 | Microsoft confirmed EdgeUpdater behavior |
| June 13, 2026 | To Do chain submitted to MSRC (VULN-195217) |
| June 15, 2026 | Case 122314 opened |
| July 15, 2026 | Microsoft confirmed To Do chain |
| August 11, 2026 | CVE-2026-69446 published |
Notes
The thing that connects these two findings is a single check: run codesign -d --verbose on every binary in a bundle and diff the flags. EdgeUpdater stood out because it was the only Edge binary without CS_RESTRICT. To Do stood out because disable-library-validation is an explicit opt-out that shows up in the entitlements XML.
Once you are inside To Do, the 435-class MSAL framework turns a code injection into a credential theft operation. The bypassRedirectValidation:YES parameter is the kind of thing that exists for internal testing and should never be callable from production code. It was.