This is a booby-trapped revolving door, not an unlocked loading dock
CVE-2026-10906 is a use-after-free in Chrome WebAuthentication affecting Google Chrome before 149.0.7827.53 on Linux and before 149.0.7827.53/54 on Windows and macOS, disclosed on 2026-06-04. In plain English: a malicious site can drive Chrome into reusing freed memory during a WebAuthn flow, creating a path to renderer compromise or crash if the victim is steered through the right interaction sequence.
Google rated it HIGH (7.5), which is defensible in a lab because browser memory corruption is serious. In enterprise reality, that overstates near-term patch urgency: the chain needs web delivery, user interaction, and a sufficiently reliable exploit against modern Chrome mitigations, and the browser sandbox sharply reduces blast radius unless the attacker also has a follow-on escape. With no KEV listing, no public PoC located, and a very low EPSS, this looks more like a patch-on-schedule browser bug than an emergency fleet event.
4 steps from start to impact.
Land the victim on attacker-controlled WebAuthn content
- Unauthenticated remote reach to a user via the web
- Victim uses Chrome below 149.0.7827.53
- Target visits attacker-controlled content
- This is client-side, so there is no direct internet-facing service to mass-scan and hit at will
- Enterprise web filtering, Safe Browsing, mail security, and user behavior all reduce delivery success
Trigger the vulnerable WebAuthentication path
- Page runs in a supported WebAuthn origin context
- User performs the required interaction sequence
- Exploit reliably reaches the vulnerable code path
- The vendor CVSS already says AC:H and UI:R; that matters here
- WebAuthn flows are more interaction-heavy than a simple drive-by page load
- Some enterprises restrict or rarely use passkeys/security keys, reducing reachable population
Convert memory corruption into code execution
- Attacker has exploit engineering capability
- Target build and platform line up with the exploit assumptions
- Chrome mitigations are bypassed well enough for stable execution
- No verified public PoC or exploit kit tie-in found
- Browser exploitation reliability is fragile across builds and platforms
- A crash is much easier than controlled execution
Break out of the renderer sandbox for meaningful host impact
- Initial code execution occurs in a sandboxed renderer or similarly constrained process
- Attacker has a second-stage escape or valuable in-browser objective
- Chrome's sandbox and site isolation are explicit downward pressure on impact
- Single-bug chains in modern Chrome are materially harder to monetize than vendor CVSS suggests
- A network IPS signature is not a dependable control here because the exploit is embedded in normal browser content and pivots on client-side memory state, not a clean protocol pattern.
- Perimeter vuln scanning does not meaningfully solve this; there is no listening Chrome service to census like a VPN or appliance.
- MFA is largely irrelevant to the exploitation step. It may reduce follow-on identity abuse, but it does not stop the WebAuthn memory-corruption trigger.
The supporting signals.
| In-the-wild status | No verified active exploitation found in the sources reviewed, and not listed in CISA KEV as of this assessment. |
|---|---|
| Proof-of-concept availability | No public PoC located via public GitHub/Exploit-DB checks. That does *not* mean exploit development is impossible; it means there is no obvious commodity starting point. |
| EPSS | 0.00084 from the user-supplied intel, which is roughly 0.084% modeled 30-day exploitation probability. That is low and supports de-prioritizing against actively exploited browser bugs. |
| KEV status | Not KEV-listed. No CISA date added or due date applies. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H — remote and no auth help the score, but high attack complexity plus required user interaction are real operational brakes. |
| Affected versions | Google Chrome prior to 149.0.7827.53 on Linux and prior to 149.0.7827.53/54 on Windows/macOS. |
| Fixed versions | Patch level is 149.0.7827.53 (Linux) and 149.0.7827.53/54 (Windows/macOS). Enterprises on Extended Stable should validate whether their downstream channel has incorporated the fix rather than assuming major-version parity. |
| Exposure / scanning reality | This is not a scan-the-internet service exposure. Shodan/Censys-style internet census data is largely irrelevant here because the reachable surface is the browser endpoint population, not a listening daemon. *Inference from attack model, not from a server census.* |
| Disclosure timeline | Chrome 149 stable shipped on 2026-06-02; the CVE was publicly disclosed in release materials on 2026-06-04. |
| Researcher / reporting credit | Reported by Weipeng Jiang (@Krace) of VRI on 2026-04-17, per Google's release note. |
Sources.
Why this verdict
- User-driven chain: the attacker does not get a one-packet hit; they need the victim in a crafted WebAuthn flow, which is meaningfully narrower than generic browse-to-own bugs.
- High-complexity exploit: the vendor vector's
AC:Hmatters. Reliable browser memory-corruption exploitation on modern Chrome is specialist work, especially without a public PoC. - Contained initial blast radius: Chromium explicitly treats compromised renderers as a threat case and uses sandboxing and Site Isolation to limit damage, so the first win is often not the final enterprise-impacting win.
- No active exploitation signal: not in KEV, no verified campaign use, and the supplied EPSS is extremely low.
- Ubiquity prevents a LOW: Chrome is everywhere, delivery is over the web, and if someone does build a stable exploit, reach is broad.
Why not higher?
Because this is not a server-side pre-auth RCE with broad unaided reach. Every extra prerequisite pushes down: the attacker needs user interaction, a WebAuthn-capable interaction path, reliable memory-corruption exploitation, and likely a second bug for system-level outcomes. That is too much friction for HIGH in a 10,000-host prioritization queue absent exploitation evidence.
Why not lower?
Because Chrome is a massive endpoint population and browsers are exposed to hostile content all day. A real memory-safety bug in a ubiquitous browser still deserves disciplined patching even when the current threat telemetry is quiet.
Crowdsourced verification payload.
Run this on the target endpoint or through your EDR/live-response tool. Invoke it with python3 check_cve_2026_10906.py on Windows, macOS, or Linux; no admin rights are required unless your environment blocks access to browser binaries or app metadata.
#!/usr/bin/env python3
# check_cve_2026_10906.py
# Detect whether the local Google Chrome installation is vulnerable to CVE-2026-10906
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
import os
import platform
import plistlib
import re
import subprocess
import sys
from pathlib import Path
FIXED = (149, 0, 7827, 53)
def parse_version(text):
if not text:
return None
m = re.search(r'(\d+)\.(\d+)\.(\d+)\.(\d+)', text)
if not m:
return None
return tuple(int(x) for x in m.groups())
def ver_to_str(v):
return '.'.join(str(x) for x in v) if v else 'unknown'
def is_vulnerable(v):
return v is not None and v < FIXED
def candidates_windows():
paths = []
envs = [os.environ.get('PROGRAMFILES'), os.environ.get('PROGRAMFILES(X86)'), os.environ.get('LOCALAPPDATA')]
suffixes = [
r'Google\Chrome\Application\chrome.exe',
r'Chromium\Application\chrome.exe'
]
for base in envs:
if not base:
continue
for suf in suffixes:
p = Path(base) / Path(suf)
paths.append(p)
return paths
def candidates_macos():
return [
Path('/Applications/Google Chrome.app'),
Path.home() / 'Applications/Google Chrome.app',
Path('/Applications/Chromium.app'),
Path.home() / 'Applications/Chromium.app'
]
def candidates_linux_cmds():
return [
['google-chrome', '--version'],
['google-chrome-stable', '--version'],
['chromium-browser', '--version'],
['chromium', '--version']
]
def get_windows_versions():
found = []
for p in candidates_windows():
if p.exists():
try:
out = subprocess.check_output([str(p), '--version'], stderr=subprocess.STDOUT, text=True, timeout=5)
v = parse_version(out)
found.append((str(p), v))
except Exception:
found.append((str(p), None))
return found
def get_macos_versions():
found = []
for app in candidates_macos():
plist = app / 'Contents' / 'Info.plist'
if plist.exists():
try:
with open(plist, 'rb') as f:
data = plistlib.load(f)
v = parse_version(data.get('CFBundleShortVersionString', '') or data.get('CFBundleVersion', ''))
found.append((str(app), v))
except Exception:
found.append((str(app), None))
return found
def get_linux_versions():
found = []
for cmd in candidates_linux_cmds():
try:
out = subprocess.check_output(cmd, stderr=subprocess.STDOUT, text=True, timeout=5)
v = parse_version(out)
found.append((' '.join(cmd[:-1]), v))
except Exception:
continue
# de-duplicate by path/label
uniq = []
seen = set()
for item in found:
if item[0] not in seen:
uniq.append(item)
seen.add(item[0])
return uniq
def main():
system = platform.system().lower()
if 'windows' in system:
installs = get_windows_versions()
elif 'darwin' in system:
installs = get_macos_versions()
elif 'linux' in system:
installs = get_linux_versions()
else:
print('UNKNOWN')
print('Unsupported platform:', platform.system())
sys.exit(2)
if not installs:
print('UNKNOWN')
print('No Chrome/Chromium installation found')
sys.exit(2)
vuln = []
patched = []
unknown = []
for name, ver in installs:
if ver is None:
unknown.append((name, ver))
elif is_vulnerable(ver):
vuln.append((name, ver))
else:
patched.append((name, ver))
for name, ver in installs:
print(f'{name}: {ver_to_str(ver)}')
print(f'Fixed threshold: {ver_to_str(FIXED)}')
if vuln:
print('VULNERABLE')
sys.exit(1)
if patched and not vuln:
print('PATCHED')
sys.exit(0)
print('UNKNOWN')
sys.exit(2)
if __name__ == '__main__':
main()