This is a broken interior door in a building the attacker already had to break into first
CVE-2026-11223 is an input-validation flaw in Chrome's Network component that affects Google Chrome versions before 149.0.7827.53 on supported desktop platforms. The bug does not give an attacker first-hop code execution by itself; the attacker must already have compromised the renderer process and then use a crafted HTML page to bypass the same-origin policy (SOP), turning one browser compromise into broader cross-origin reach inside that browser session.
The raw 6.5 MEDIUM CVSS number overstates the operational urgency for enterprise patch queues. The decisive friction is the prerequisite: renderer compromise first. That means this is a post-initial-compromise chain amplifier, not a clean unauthenticated remote exploit, and there is no KEV listing, no public exploitation evidence, and a tiny EPSS (0.00027). Chrome's own CNA record labels it Low, and in real fleets that label is closer to reality than the generic CVSS math.
4 steps from start to impact.
Land renderer compromise
- Victim is running Chrome before
149.0.7827.53 - Attacker already achieved renderer-process compromise through a separate bug or implant
- Victim browses attacker-controlled content or content the attacker can influence
- Requires a separate exploit chain before this CVE matters
- Modern browser sandboxing, exploit mitigations, and site isolation raise the bar materially
- No public exploit chain is currently tied to this CVE
Trigger the network-component validation flaw
Network component. The practical objective is to confuse origin enforcement or related trust checks so the compromised renderer can interact across boundaries it normally should not cross.- Compromised renderer can still issue or influence network requests
- Targeted cross-origin resources are reachable from the victim browser context
- The attacker must align browser state, origin context, and reachable target resources
- Enterprise proxies, auth boundaries, and cross-origin protections still constrain what data is worth reaching
Bypass same-origin policy
- Victim has active authenticated sessions of value in the browser
- Target web apps rely on browser-enforced origin separation for part of their trust model
- Impact is bounded to the victim's browser profile/session rather than direct host takeover
- Server-side access controls, anti-CSRF design, and token scoping can still limit useful abuse
Monetize session-level access
- Victim browser contains valuable sessions, cookies, or reachable internal apps
- The attacker has a path to exfiltrate or reuse the resulting data
- Blast radius is user-session scoped, not fleet-wide by default
- No direct sandbox escape or OS-level code execution is attributed to this CVE alone
149.0.7827.53+ during normal maintenance. For a LOW verdict there is no mitigation SLA; treat this as backlog hygiene and fold it into your standard browser-update cadence.- A perimeter firewall rule does not solve this; the vulnerable surface is the client browser processing attacker-controlled web content.
- MFA alone is not enough; if the victim already has an active authenticated browser session, SOP bypass can still abuse that session context.
- A basic authenticated vulnerability scan only proves version exposure, not exploitability. The hard part is the separate renderer compromise prerequisite.
The supporting signals.
| In-the-wild status | No public exploitation evidence found. OpenCVE shows Exploitation: none, and the CVE is not in CISA KEV. |
|---|---|
| PoC availability | No public PoC located in primary sources reviewed. The Chromium issue exists (494800494) but details are access-restricted, which is normal for Chrome security bugs shortly after release. |
| EPSS | 0.00027 from OpenCVE/FIRST enrichment, which is effectively very low near-term exploitation probability. |
| KEV status | Not KEV-listed as of 2026-06-06 review time; no CISA due date applies. |
| CVSS vector meaning | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N scores as 6.5 MEDIUM, but the generic vector misses the biggest real-world constraint: it assumes the attacker can already operate from a compromised renderer. |
| Vendor vs scoring mismatch | Important nuance: the Chrome CNA record text says Chromium security severity: Low, while downstream CISA-ADP enrichment adds the 6.5 Medium CVSS score. For triage, the Chromium label tracks operational reality better. |
| Affected versions | Google Chrome before 149.0.7827.53. OpenCVE shows the CNA lessThan range as < 149.0.7827.53. |
| Fixed version | Upgrade to 149.0.7827.53 or later on Linux and 149.0.7827.53/54 on Windows/macOS per the Chrome stable release post. |
| Scanning / exposure reality | Internet exposure scans are mostly irrelevant here. This is a client browser issue, not a server-side listening service, so Shodan/Censys-style counts do not map to reachable attack surface. Exposure is driven by endpoint version distribution and whether users browse hostile content. |
| Disclosure / reporter | Published 2026-06-04. Public sources reviewed do not name an external reporter for this specific CVE; that likely means Google/internal discovery or a still-restricted issue (inference from available sources). |
Sources.
Why this verdict
- Major downgrade: requires compromised renderer first — attacker position is *not* unauthenticated remote in practice; it implies a prior successful browser exploit or implant, which compounds downward pressure immediately.
- Population narrowing — this only matters on endpoints running Chrome
<149.0.7827.53*and* only when hostile content can be rendered after a precursor compromise; that's a much smaller reachable set than a normal web-to-RCE bug. - Modern controls should stop earlier steps — browser sandboxing, exploit mitigations, EDR, and web isolation products are all aimed at stopping the precursor compromise before this CVE becomes usable.
- Low external pressure — no KEV entry, no public exploitation evidence, and an EPSS of 0.00027 do not support emergency treatment.
- Blast radius is session-scoped — the likely outcome is cross-origin browser abuse within a victim session, not direct host takeover or wormable fleet impact.
Why not higher?
It is not higher because the prerequisite chain is too restrictive. A bug that requires internal browser foothold first is fundamentally different from a bug that gives attackers that foothold. Also, there is no sign of active exploitation, no public PoC, and no evidence this is being used as a dependable intrusion primitive at scale.
Why not lower?
It is not IGNORE because SOP bypasses can still be meaningful once an attacker is inside the browser, especially for high-value users with many authenticated SaaS sessions. Chrome is also ubiquitous, so even a post-compromise chain helper deserves routine remediation and version hygiene, just not front-of-queue treatment.
Crowdsourced verification payload.
Run this on the target endpoint or through your fleet management agent. Invoke it with python3 chrome_cve_2026_11223_check.py on macOS/Linux or py chrome_cve_2026_11223_check.py on Windows; no admin rights are required, but the script must be able to execute the local Chrome binary if present.
#!/usr/bin/env python3
# CVE-2026-11223 local exposure check for Google Chrome / Chromium-based desktop installs
# 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
FIXED = (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 version_to_str(v: Tuple[int, int, int, int]) -> str:
return '.'.join(str(x) for x in v)
def get_candidate_paths():
system = platform.system()
paths = []
if system == 'Windows':
local_app = os.environ.get('LOCALAPPDATA', '')
program_files = os.environ.get('ProgramFiles', '')
program_files_x86 = os.environ.get('ProgramFiles(x86)', '')
paths.extend([
os.path.join(local_app, 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(program_files, 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(program_files_x86, 'Google', 'Chrome', 'Application', 'chrome.exe'),
])
for cmd in ['chrome', 'chrome.exe']:
p = shutil.which(cmd)
if p:
paths.append(p)
elif system == 'Darwin':
paths.extend([
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
os.path.expanduser('~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'),
'/Applications/Chromium.app/Contents/MacOS/Chromium',
])
for cmd in ['google-chrome', 'chromium', 'chromium-browser']:
p = shutil.which(cmd)
if p:
paths.append(p)
else:
for cmd in ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser']:
p = shutil.which(cmd)
if p:
paths.append(p)
paths.extend([
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable',
'/usr/bin/chromium',
'/usr/bin/chromium-browser',
'/snap/bin/chromium',
])
# Deduplicate while preserving order
seen = set()
ordered = []
for p in paths:
if p and p not in seen:
seen.add(p)
ordered.append(p)
return ordered
def get_version(binary: str) -> Optional[Tuple[int, int, int, int]]:
try:
proc = subprocess.run([binary, '--version'], capture_output=True, text=True, timeout=10)
output = (proc.stdout or '') + ' ' + (proc.stderr or '')
return parse_version(output)
except Exception:
return None
def main() -> int:
candidates = get_candidate_paths()
findings = []
for binary in candidates:
if os.path.exists(binary) or shutil.which(binary):
ver = get_version(binary)
if ver:
findings.append((binary, ver))
if not findings:
print('UNKNOWN - Chrome/Chromium binary not found or version unreadable')
return 2
# Prefer Google Chrome if multiple binaries exist
findings.sort(key=lambda x: ('chrome' not in os.path.basename(x[0]).lower(), x[0]))
binary, ver = findings[0]
if ver < FIXED:
print(f'VULNERABLE - {binary} version {version_to_str(ver)} is older than fixed version {version_to_str(FIXED)}')
return 1
else:
print(f'PATCHED - {binary} version {version_to_str(ver)} is at or above fixed version {version_to_str(FIXED)}')
return 0
if __name__ == '__main__':
sys.exit(main())