This is a peephole in one apartment window, not a master key to the whole building
CVE-2026-11299 is an out-of-bounds read in Chrome's Fonts handling. A user has to be lured into rendering attacker-controlled content, and the bug can then disclose data from the affected renderer process. Google shipped fixes in Chrome 149 on 2026-06-02: desktop builds prior to 149.0.7827.53/54 for Windows/macOS and 149.0.7827.53 for Linux are affected; Android 149 carries the corresponding desktop security fixes.
The supplied 6.5 / MEDIUM baseline overstates operational urgency for enterprise patch queues. Google's own Chrome release entry tags this CVE Low, and that matches reality better: this is an information leak, not code execution; it needs UI:R; there is no KEV listing or public exploitation evidence; and Chrome's sandbox, site isolation, and per-renderer memory boundaries keep the likely blast radius narrow.
4 steps from start to impact.
Deliver malicious web content
- Unauthenticated remote reachability to the victim through the web
- Victim uses affected Chrome/Chromium build
- Victim renders attacker-controlled content
- Requires user interaction rather than direct service exploitation
- Enterprise browsing controls, Safe Browsing, URL filtering, and ad blocking reduce reach
- Browser auto-update shrinks the vulnerable population quickly
Trigger the Fonts out-of-bounds read
- The vulnerable code path is reachable from the rendered content
- The exploit stays stable enough to produce useful disclosure
- Modern browser hardening makes memory disclosure less deterministic
- Exploit reliability can vary by platform, build flags, and renderer state
Extract useful secrets from renderer memory
- Sensitive data is present in the same renderer process
- The leak returns attacker-usable bytes rather than noise
- Chrome Site Isolation and process separation reduce what is co-located in one renderer
- Many enterprises already protect session material with short-lived tokens and MFA
Monetize the leak
- Leaked data includes reusable secrets or sensitive content
- Attacker has a practical follow-on use for the disclosed memory
- MFA, device binding, and token scoping often blunt stolen web material
- Per-user blast radius limits enterprise-wide consequences
- Perimeter firewall rules do not solve this; there is no inbound service to shield because the attack arrives through normal user web browsing.
- Network IPS signatures are weak coverage; memory disclosure through crafted browser content rarely yields durable signatures with good precision.
- MFA does not prevent the bug from triggering; it only reduces value if leaked material later includes reusable session data.
The supporting signals.
| In-the-wild status | No public evidence of active exploitation found as of 2026-06-05; not listed in CISA KEV. |
|---|---|
| Proof-of-concept availability | No widely referenced public PoC or weaponized exploit surfaced in the sources reviewed. That sharply lowers urgency versus browser RCEs that get same-day GitHub demos. |
| EPSS | 0.00028 from the prompt intel, which is extremely low expected exploitation probability. Percentile was not confirmed from an authoritative public page in the reviewed sources. |
| KEV status | No. CISA KEV catalog reviewed with no listing for CVE-2026-11299 as of 2026-06-05. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N — easy to trigger once a user lands on content, but UI:R and confidentiality-only impact are the important brakes. |
| Affected versions | Chrome desktop prior to 149.0.7827.53/54 on Windows/macOS and prior to 149.0.7827.53 on Linux. Google published Chrome 149 stable on 2026-06-02. |
| Fixed versions | Upgrade to 149.0.7827.53+ as the safe floor across enterprise inventory; Windows/macOS stable shipped as 149.0.7827.53/54. Distro backports exist; for example, openSUSE maintenance shipped a Chromium fixset including this CVE. |
| Exposure and scanning reality | This is a client-side browser flaw, not an internet-facing daemon. Shodan/Censys/FOFA/GreyNoise are mostly irrelevant; exposure is measured by endpoint browser version inventory, not open ports. |
| Disclosure and reporter | Google's release stream shows the fix on 2026-06-02 and the CVE record surfaced publicly on 2026-06-05. Google credits [email protected], reported 2026-04-14. |
Sources.
Why this verdict
- User interaction is mandatory: the attacker cannot hit a listening service; they need a user to render attacker-controlled content first.
- This is disclosure, not execution: the practical outcome is leaked renderer memory, which is materially less dangerous than Chrome sandbox escape or RCE.
- Real-world population narrows fast: Chrome auto-update plus enterprise browser management compresses exposure far faster than on server middleware.
- No threat intel amplifier: no KEV listing, no public campaign reporting, no obvious public PoC, and an EPSS value close to floor.
Why not higher?
A higher rating would need at least one strong amplifier: active exploitation, a public reliable PoC, a sandbox escape chain, or evidence that the leak routinely exposes reusable enterprise secrets. None of that is present here. On top of that, this is post-lure and per-user, not a broad unauthenticated service compromise.
Why not lower?
It is still a remotely triggerable browser memory disclosure in an extremely widespread product. In a 10,000-host estate, someone will eventually browse hostile content, so this is not ignorable. Sensitive renderer memory leaks can become chainable intelligence for a second-stage attack even when they are weak standalone bugs.
Crowdsourced verification payload.
Run this on the target endpoint or via your software inventory agent to validate the installed Chrome/Chromium version. Invoke with python3 check_chrome_cve_2026_11299.py on Linux/macOS or py check_chrome_cve_2026_11299.py on Windows; standard user rights are usually enough because the script only reads executable metadata.
#!/usr/bin/env python3
# check_chrome_cve_2026_11299.py
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
import os
import platform
import re
import shutil
import subprocess
import sys
from pathlib import Path
SAFE_FLOOR = (149, 0, 7827, 53)
CANDIDATES = {
'Windows': [
r'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
r'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
r'C:\\Program Files\\Chromium\\Application\\chrome.exe',
r'C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe',
r'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
r'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
],
'Darwin': [
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
'/Applications/Chromium.app/Contents/MacOS/Chromium',
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
],
'Linux': [
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable',
'/usr/bin/chromium',
'/usr/bin/chromium-browser',
'/snap/bin/chromium',
'/usr/bin/microsoft-edge',
'/usr/bin/microsoft-edge-stable',
],
}
def parse_version(text):
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_str(v):
return '.'.join(str(x) for x in v)
def is_patched(v):
return v >= SAFE_FLOOR
def run_version(path):
try:
p = subprocess.run([path, '--version'], capture_output=True, text=True, timeout=8)
out = (p.stdout or '') + ' ' + (p.stderr or '')
return parse_version(out)
except Exception:
return None
def find_installs():
sysname = platform.system()
found = []
for p in CANDIDATES.get(sysname, []):
if os.path.exists(p):
found.append(p)
for cmd in ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser', 'msedge', 'microsoft-edge', 'microsoft-edge-stable']:
loc = shutil.which(cmd)
if loc and loc not in found:
found.append(loc)
return found
def main():
installs = find_installs()
if not installs:
print('UNKNOWN - no Chrome/Chromium-family executable found')
sys.exit(2)
results = []
for path in installs:
ver = run_version(path)
if ver is None:
results.append((path, None, 'UNKNOWN'))
elif is_patched(ver):
results.append((path, ver, 'PATCHED'))
else:
results.append((path, ver, 'VULNERABLE'))
# Print per-install result
for path, ver, state in results:
if ver is None:
print(f'{state} - {path} - version unreadable')
else:
print(f'{state} - {path} - {version_str(ver)}')
# Overall state: vulnerable wins, else patched if any patched and none vulnerable, else unknown
if any(state == 'VULNERABLE' for _, _, state in results):
sys.exit(1)
if any(state == 'PATCHED' for _, _, state in results):
sys.exit(0)
sys.exit(2)
if __name__ == '__main__':
main()