This is finding a loose panel inside the vault after the robber is already locked in the lobby
CVE-2026-11235 is an insufficient policy enforcement flaw in Chrome Compositing affecting Google Chrome versions prior to 149.0.7827.53. The key clause is the whole story: the attacker must have already compromised the renderer process first, and only then can a crafted HTML page be used to gain arbitrary code execution inside a sandbox. That makes this a post-compromise browser-chain primitive, not a one-bug remote workstation takeover.
The published 8.8 HIGH CVSS overstates enterprise urgency if you are scheduling patches across a real fleet. Chrome's own CVE text labels the underlying Chromium security severity as Low, and that lines up better with reality: this bug assumes a prior exploit stage, preserves sandbox confinement, has no known KEV entry, and has extremely low EPSS. It matters to exploit developers building multi-bug chains; it is not the thing that gets an attacker into your environment by itself.
3 steps from start to impact.
Compromise the renderer first
- Victim uses a vulnerable Chrome build earlier than
149.0.7827.53 - Attacker has a separate working renderer-compromise exploit
- Victim reaches attacker-controlled web content
- This CVE is unusable without a prior browser exploit stage
- Modern browser hardening, exploit mitigations, and EDR raise the cost of landing reliable renderer compromise first
- No public one-click PoC for this CVE was found
Trigger the Compositing policy flaw
- Renderer execution already achieved
- Attacker can deliver crafted HTML to the same browser session
- The bug appears to stay within sandbox boundaries rather than breaking out to the OS
- Reliable exploitation likely depends on browser state and exploit choreography, not just simple page delivery
Try to turn sandboxed code execution into real impact
- Successful execution inside the sandbox
- A second post-exploitation path to host-level or identity-level impact
- Sandbox confinement is the biggest downward pressure on risk
- Many enterprises can absorb isolated browser-process compromise better than host compromise
- Additional stages increase failure points and detection opportunities
- A WAF does not materially help; this is client-side browser logic, not your web app's input path.
- Perimeter internet exposure scanning does not answer the question; Chrome is an endpoint application, so Shodan-style visibility is irrelevant.
- Relying on email filtering alone is weak here because any web delivery path can host the crafted HTML once another renderer exploit exists.
The supporting signals.
| In-the-wild status | No public evidence of active exploitation found, and not listed in CISA KEV at the time of assessment. |
|---|---|
| Proof-of-concept availability | No public GitHub PoC or turnkey exploit repo located for CVE-2026-11235; exploitation appears to require a custom chain. |
| EPSS | 0.00078 from the prompt intel — extremely low expected near-term exploitation probability. |
| KEV status | Not KEV-listed. CISA's KEV catalog does not show this CVE. |
| CVSS vector reality check | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H assumes a clean remote path, but the CVE text itself says the attacker must have already compromised the renderer process. That prerequisite is major real-world friction. |
| Affected versions | Google Chrome prior to 149.0.7827.53. |
| Fixed versions | Desktop stable update shipped as 149.0.7827.53 for Linux and 149.0.7827.53/54 for Windows and Mac. Android release notes state they carry the same desktop security fixes unless otherwise noted. |
| Exposure / scanning reality | This is a client-side browser flaw, not an internet-listening service. Shodan/Censys-style exposure counts are not meaningful; your exposure is your managed Chrome install base. |
| Disclosure date | 2026-06-04. |
| Reporter / source | Public record names Chrome/Google as the source. The linked Chromium issue is restricted, so public researcher attribution is not currently visible. |
Sources.
Why this verdict
- Requires prior compromise: the CVE text explicitly requires the attacker to have already compromised the renderer process, which implies a separate exploit stage and is strong downward pressure from the
8.8baseline. - Still sandboxed: successful exploitation yields arbitrary code execution *inside a sandbox*, not a clean host escape. That sharply limits stand-alone business impact.
- No exploitation signal: no KEV listing, no public exploitation evidence found, and the supplied EPSS
0.00078is tiny. - Exposure is broad but not reachable in the same way as a server bug: Chrome is everywhere, but this is not an unauthenticated internet-facing service that attackers can mass-scan and smash directly.
- Detection opportunity compounds across stages: a real attack needs renderer compromise first and likely a follow-on sandbox escape or credential theft second, creating more breakpoints for browser protections and EDR.
Why not higher?
A HIGH or CRITICAL verdict would fit a browser bug that gives unauthenticated remote code execution on first contact or breaks out of the sandbox directly. This one does neither. Its own description bakes in a prior exploit requirement and leaves the attacker sandboxed, which is exactly the kind of friction that should crush a vacuum-severity score.
Why not lower?
It is still a real security boundary failure in a massively deployed client, and it could be useful in a chained campaign. If an attacker already has a renderer foothold, this CVE may help stabilize or extend that position. That keeps it above IGNORE and worth normal patch hygiene.
Crowdsourced verification payload.
Run this on the target endpoint or via your software-distribution/EDR remote execution channel. Invoke it as python3 check_cve_2026_11235.py on Linux/macOS or py check_cve_2026_11235.py on Windows; no administrative privileges are required if the Chrome binary is in a standard location.
#!/usr/bin/env python3
# check_cve_2026_11235.py
# Detects whether local Google Chrome version is vulnerable to CVE-2026-11235.
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
import os
import platform
import re
import shutil
import subprocess
import sys
from typing import Optional, Tuple, List
THRESHOLD = (149, 0, 7827, 53)
def parse_version(text: str) -> Optional[Tuple[int, int, int, int]]:
m = re.search(r'(\d+)\.(\d+)\.(\d+)\.(\d+)', text)
if not m:
return None
return tuple(int(x) for x in m.groups())
def run_and_get_version(cmd: List[str]) -> Optional[Tuple[int, int, int, int]]:
try:
p = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
except Exception:
return None
out = (p.stdout or '') + '\n' + (p.stderr or '')
return parse_version(out)
def candidate_commands() -> List[List[str]]:
system = platform.system().lower()
cmds: List[List[str]] = []
if system == 'windows':
env = os.environ
candidates = [
os.path.join(env.get('ProgramFiles', 'C:\\Program Files'), 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(env.get('ProgramFiles(x86)', 'C:\\Program Files (x86)'), 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(env.get('LocalAppData', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'),
]
for path in candidates:
if path and os.path.exists(path):
cmds.append([path, '--version'])
for exe in ['chrome', 'chrome.exe']:
found = shutil.which(exe)
if found:
cmds.append([found, '--version'])
elif system == 'darwin':
candidates = [
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
os.path.expanduser('~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'),
]
for path in candidates:
if os.path.exists(path):
cmds.append([path, '--version'])
found = shutil.which('google-chrome')
if found:
cmds.append([found, '--version'])
else:
for exe in ['google-chrome', 'google-chrome-stable', 'chrome', 'chromium', 'chromium-browser']:
found = shutil.which(exe)
if found:
cmds.append([found, '--version'])
for path in [
'/opt/google/chrome/chrome',
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable',
]:
if os.path.exists(path):
cmds.append([path, '--version'])
# Deduplicate while preserving order
unique = []
seen = set()
for cmd in cmds:
key = tuple(cmd)
if key not in seen:
seen.add(key)
unique.append(cmd)
return unique
def main() -> int:
versions = []
for cmd in candidate_commands():
ver = run_and_get_version(cmd)
if ver:
versions.append((cmd[0], ver))
if not versions:
print('UNKNOWN - Google Chrome not found or version unreadable')
return 2
# Prefer the highest discovered version if multiple copies exist
path, ver = sorted(versions, key=lambda x: x[1], reverse=True)[0]
ver_str = '.'.join(str(x) for x in ver)
threshold_str = '.'.join(str(x) for x in THRESHOLD)
if ver < THRESHOLD:
print(f'VULNERABLE - {path} version {ver_str} is older than fixed version {threshold_str}')
return 1
else:
print(f'PATCHED - {path} version {ver_str} is at or newer than fixed version {threshold_str}')
return 0
if __name__ == '__main__':
sys.exit(main())