This is a peephole in the browser wall, not a door kicked off its hinges
CVE-2026-10979 is an out-of-bounds read in Chrome's ANGLE graphics layer. In plain terms, a malicious webpage can steer the browser into reading memory it should not read and may expose sensitive data from the browser process. The affected range is Google Chrome versions prior to 149.0.7827.53; Google's early stable release notes show 149.0.7827.53/.54 as the fixed desktop train for Windows and Mac.
The vendor baseline of MEDIUM 6.5 is defensible in lab conditions, but it overstates enterprise urgency. The decisive downgrades are practical: the attacker must first win a browser visit to a crafted page, the bug is *information disclosure only* rather than code execution, and there is no reviewed evidence here of KEV listing or active exploitation. In real fleets, this looks much more like a useful exploit-chain primitive than a standalone breach engine.
4 steps from start to impact.
Land the user on a malicious page
ANGLE. The weaponized delivery is just a malicious webpage, not a listening network service, which means the bug is only reachable after a successful lure or redirect.- Unauthenticated remote attacker
- Target user opens attacker-controlled or attacker-influenced web content
- Chrome version is older than
149.0.7827.53
- Requires user interaction (
UI:R) - Enterprise web filtering, safe browsing controls, and ad/script controls reduce reach
- Some users never hit the vulnerable rendering path during normal browsing
Trigger the ANGLE out-of-bounds read
ANGLE code path and causes an out-of-bounds read. The practical weapon here is the browser's own graphics stack; there is no shell, service endpoint, or credential step involved.- Vulnerable Chrome build
- Relevant graphics/renderer code path reachable on the endpoint
- Out-of-bounds read is weaker than out-of-bounds write or use-after-free for attacker impact
- Graphics-path bugs can be sensitive to platform, driver, and runtime differences
- Browser sandboxing and process isolation constrain what the primitive can directly expose
Extract useful memory from the browser process
- The primitive must disclose attacker-useful memory rather than random noise
- The victim session must actually hold valuable material in the affected process
- Modern site isolation and process separation limit blast radius
- Many disclosures leak low-value or unstable memory fragments
- Turning a memory leak into durable business impact usually needs a second bug or a very specific target condition
Chain into something bigger
- Attacker has a compatible second-stage exploit or a very targeted data-theft objective
- No reviewed source here shows an in-the-wild chain using this CVE
- Exploit chaining materially raises attacker cost and narrows the target pool
- EDR, browser isolation, and account controls can still blunt post-leak value
149.0.7827.53/.54 and that update services are functioning. For a LOW verdict there is no formal noisgate mitigation SLA; do this during normal browser hygiene, not as an emergency change.- MFA does not stop the browser from rendering a malicious page or leaking process memory.
- External attack-surface scanning will not find this exposure because Chrome is a client, not an internet-facing service.
- EDR alone is not a reliable control for silent browser memory disclosure; it is more useful against any second-stage payload than against this primitive itself.
The supporting signals.
| In-the-wild status | No confirmed active exploitation in reviewed sources. CVE-2026-10979 is not listed in CISA KEV, and I found no credible campaign reporting tied to this specific CVE. |
|---|---|
| PoC availability | No credible public PoC surfaced in reviewed sources. That does not mean exploitability is impossible; it means there is no obvious commodity weaponization signal yet. |
| EPSS | 0.00035 — extremely low predicted near-term exploitation probability. FIRST EPSS documentation/API supports pulling current score data for published CVEs. |
| KEV status | Not KEV-listed as reviewed against CISA's catalog. No KEV date applies. |
| CVSS vector readout | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N = remote triggerable through web content, but only after user interaction, with confidentiality impact only and no direct integrity/availability hit. |
| Affected versions | Google Chrome prior to 149.0.7827.53. Google's early stable note shows the desktop fixed train as 149.0.7827.53/.54 for Windows and Mac. |
| Fixed versions | Desktop: 149.0.7827.53/.54 on the early stable track for Windows/Mac. For managed fleets, also verify that your channel policy is not pinning endpoints behind the fixed train. |
| Exposure/scanning reality | Shodan/Censys/FOFA data is not meaningful here. This is a client-side browser flaw, not an internet-facing service; external attack-surface tools will not tell you your true exposure. |
| Disclosure timing | There is a date discrepancy across visible sources: your prompt says 2026-06-04, while the reviewed VulDB entry shows MITRE/public visibility on 2026-06-05. Use June 4, 2026 as the vendor disclosure anchor you supplied, but note the public indexing lag. |
| Researcher / reporting | No public researcher attribution found in reviewed sources. Public release notes for this CVE batch did not expose a named reporter in the sources I reviewed. |
Sources.
- Chrome Releases - Early Stable Update for Desktop (149.0.7827.53/.54)
- Chrome Releases homepage
- VulDB entry for CVE-2026-10979
- CISA Known Exploited Vulnerabilities Catalog
- CISA KEV JSON feed
- FIRST EPSS API documentation
- Chrome Enterprise - Manage Chrome updates (Windows)
- Chrome Enterprise - Manage Chrome updates (Mac)
Why this verdict
- User interaction is mandatory: the attacker does not get a blind internet-to-host shot; they need the victim to render a crafted page first, which is a meaningful real-world choke point.
- Impact is confidentiality-only: this is an out-of-bounds read, not a write/UAF/RCE. That sharply reduces standalone blast radius for enterprise endpoints.
- Client-side, not perimeter-exposed: there is no internet-facing service to scan, worm, or mass-spray directly. Exposure depends on browsing behavior, not open ports.
- No reviewed exploitation signal: not KEV-listed, EPSS is 0.00035, and I found no credible public campaign reporting for this CVE. That is strong downward pressure versus Chrome zero-day cases.
- Exploit-chain dependency: to turn this into a workstation takeover or durable access, the attacker usually needs a second vulnerability or a very specific data target. That compounds friction.
Why not higher?
It is not higher because there is no direct code execution, no authentication bypass, no privilege gain, and no evidence in the reviewed sources that defenders are facing live exploitation pressure. The required victim browse step plus the information-disclosure-only outcome keeps this out of the urgent Chrome-emergency bucket.
Why not lower?
It is not lower because Chrome is ubiquitous, the trigger is remote through ordinary web content, and confidentiality bugs in browser internals can absolutely matter in targeted operations. If you run a large fleet, you still want the fixed build broadly deployed; this just does not justify panic-level change management.
Crowdsourced verification payload.
Run this on the target endpoint or in your endpoint management tooling to check the locally installed Google Chrome version. Invoke with python3 check_chrome_cve_2026_10979.py on macOS/Linux or py check_chrome_cve_2026_10979.py on Windows; no admin rights are normally required, though registry access on locked-down Windows builds may benefit from standard user context with local read permissions.
#!/usr/bin/env python3
# check_chrome_cve_2026_10979.py
# Determine whether locally installed Google Chrome is vulnerable to CVE-2026-10979.
# Fixed version threshold: 149.0.7827.53
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN
import os
import platform
import re
import subprocess
import sys
FIXED = "149.0.7827.53"
def normalize_version(v):
parts = re.findall(r"\d+", v or "")
if not parts:
return None
return tuple(int(p) for p in parts)
def compare_versions(a, b):
va = normalize_version(a)
vb = normalize_version(b)
if va is None or vb is None:
return None
maxlen = max(len(va), len(vb))
va += (0,) * (maxlen - len(va))
vb += (0,) * (maxlen - len(vb))
if va < vb:
return -1
if va > vb:
return 1
return 0
def run_cmd(cmd):
try:
cp = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=10)
if cp.returncode == 0:
return (cp.stdout or cp.stderr).strip()
except Exception:
pass
return None
def extract_version(text):
if not text:
return None
m = re.search(r"(\d+\.\d+\.\d+\.\d+)", text)
return m.group(1) if m else None
def get_windows_version():
try:
import winreg
except Exception:
return None
reg_paths = [
(winreg.HKEY_CURRENT_USER, r"Software\Google\Chrome\BLBeacon", "version"),
(winreg.HKEY_LOCAL_MACHINE, r"Software\Google\Chrome\BLBeacon", "version"),
(winreg.HKEY_LOCAL_MACHINE, r"Software\WOW6432Node\Google\Chrome\BLBeacon", "version"),
]
for hive, path, name in reg_paths:
try:
with winreg.OpenKey(hive, path) as key:
val, _ = winreg.QueryValueEx(key, name)
ver = extract_version(str(val))
if ver:
return ver
except Exception:
continue
candidates = [
os.path.expandvars(r"%ProgramFiles%\Google\Chrome\Application\chrome.exe"),
os.path.expandvars(r"%ProgramFiles(x86)%\Google\Chrome\Application\chrome.exe"),
os.path.expandvars(r"%LocalAppData%\Google\Chrome\Application\chrome.exe"),
]
for exe in candidates:
if exe and os.path.exists(exe):
out = run_cmd([exe, "--version"])
ver = extract_version(out)
if ver:
return ver
return None
def get_macos_version():
app = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if os.path.exists(app):
out = run_cmd([app, "--version"])
ver = extract_version(out)
if ver:
return ver
plist = "/Applications/Google Chrome.app/Contents/Info.plist"
if os.path.exists(plist):
out = run_cmd(["/usr/bin/defaults", "read", plist, "CFBundleShortVersionString"])
ver = extract_version(out)
if ver:
return ver
return None
def get_linux_version():
binaries = [
"google-chrome",
"google-chrome-stable",
"/opt/google/chrome/chrome",
"/usr/bin/google-chrome",
"/usr/bin/google-chrome-stable",
]
for b in binaries:
if os.path.isabs(b) and not os.path.exists(b):
continue
out = run_cmd([b, "--version"])
ver = extract_version(out)
if ver:
return ver
return None
def main():
system = platform.system().lower()
version = None
if "windows" in system:
version = get_windows_version()
elif "darwin" in system:
version = get_macos_version()
elif "linux" in system:
version = get_linux_version()
if not version:
print("UNKNOWN - Google Chrome version not found")
sys.exit(2)
cmp_result = compare_versions(version, FIXED)
if cmp_result is None:
print(f"UNKNOWN - Unable to compare detected version {version} to fixed version {FIXED}")
sys.exit(2)
if cmp_result < 0:
print(f"VULNERABLE - Detected Google Chrome {version} (< {FIXED})")
sys.exit(1)
else:
print(f"PATCHED - Detected Google Chrome {version} (>= {FIXED})")
sys.exit(0)
if __name__ == "__main__":
main()