Low watch CVSS 6.5 chrome OOB 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read in Skia
DescriptionOut of bounds read in Skia
ComponentSkia
Sub-componentSecurity
Bug ClassOOB
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker524864599
Fix commit9468e96cc40f (skia) +6/-0
CWECWE-125 (Out-of-bounds read)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedQuan Huynh x Amaterasu
Reported2026-06-17 (per vendor advisory)
Fix landed2026-07-17 (public git)
Disclosed2026-08-25
Patch gap39 days — fix public in source before the advisory

Background

`SkTextBlob`
the Skia object that holds one or more runs of positioned glyphs together with optional metadata such as UTF-8 text and per-glyph cluster indices.
Cluster index
an entry in the buf->clusters array that maps a glyph back to a byte offset within the run’s UTF-8 text buffer, and so must always fall within the text’s size.
`MakeFromBuffer`
the Skia deserialization entry point that reconstructs an SkTextBlob from an untrusted serialized buffer via a reader.

Root Cause Analysis

When deserializing an SkTextBlob, the code path in src/core/SkTextBlob.cpp read the run’s UTF-8 text (buf->utf8text, of length textSize) and its cluster array (buf->clusters) directly from the buffer without validating the cluster values against textSize. Cluster indices are supposed to be byte offsets into the textSize-byte UTF-8 text, so the invariant that every buf->clusters[i] is strictly less than textSize must hold, but nothing enforced it on deserialization. A compromised renderer could therefore supply cluster indices that overflow or underflow relative to textSize, causing later code that indexes the text using those clusters to read out of bounds.

The fix adds a loop over all glyphCount glyphs that rejects the blob (returns nullptr) if any buf->clusters[i] is >= textSize (compared as uint32_t), so an oversized or wrapped index can no longer be accepted. Because the comparison is unsigned and against the exact textSize, both the overflow (too-large index) and underflow (wrapped negative treated as a huge unsigned value) cases described in the advisory are caught before the blob is used.

Key insight
The single mistake was trusting attacker-controlled cluster indices from a serialized buffer as valid offsets into the UTF-8 text without any range check; the fix restores the missing invariant by validating every buf->clusters[i] against textSize and returning nullptr on any out-of-range value.

Attack Path

  1. Compromise the renderer An attacker first gains code execution or memory control in a Chrome renderer process, the source of the serialized data the advisory assumes is malicious.
  2. Craft a malicious text blob The attacker builds a serialized SkTextBlob in which a run declares a UTF-8 text of textSize bytes but sets one or more buf->clusters[i] entries to a value >= textSize (or a wrapped/underflowing value).
  3. Trigger deserialization The malformed buffer is passed to MakeFromBuffer in src/core/SkTextBlob.cpp, which (before the patch) accepts the out-of-range cluster indices without validation.
  4. Out-of-bounds read Downstream code that uses the cluster indices to index the textSize-byte text buffer reads past its bounds, producing the out-of-bounds read the advisory reports. (inferred) The exact sink that dereferences buf->clusters[i] against buf->utf8text is not shown in the diff.

Impact Assessment

An attacker who already controls a renderer gains an out-of-bounds read in Skia, in whatever process performs the deserialization, with the precondition that a maliciously crafted SkTextBlob buffer reaches MakeFromBuffer. The advisory classifies this as an out-of-bounds read in Skia (bug class OOB) and states no exploited-in-the-wild status, so none is claimed here. (inferred) Any use of the leaked memory for information disclosure or as a step toward further escalation goes beyond what the patch itself demonstrates.

Changed Functions

FunctionChangeNotes
for
src/core/SkTextBlob.cpp
modified

Files Changed

  • src/core/SkTextBlob.cpp

Audit Directions

  • Unvalidated deserialized indices
    Review other Skia MakeFromBuffer/reader paths where array indices or offsets (like buf->clusters) are read from an untrusted buffer and later used to index a separately sized buffer without a bounds check.
  • Signed/unsigned length comparisons
    Look for places that compare buffer-derived indices against a size without an explicit uint32_t (or matching-width) cast, since underflowed or sign-mismatched values can slip past a naive check.
  • Cross-field size invariants
    Audit structures where one deserialized field’s size (such as textSize) constrains the valid range of another field’s contents (such as cluster or offset arrays), ensuring the dependent field is validated against the declared size on every load path.
From 9468e96cc40f6c18e62caf9a4b4a0a700fa7f24a Mon Sep 17 00:00:00 2001
From: Alexis Cruz-Ayala <alexisdavidc@google.com>
Date: Fri, 17 Jul 2026 09:55:43 -0400
Subject: [PATCH] [Security] Added checks to MakeFromBuffer for Cluster size

If a renderer is compromised, an OOB cluster index can be provided, which would then lead to an OOB memory read if it underflows / overflows.

The solution is to check each glyph within the clusters array (buf->clusters) when deserializing such taht all cluster indices are not greater than textsize. Otherwise return nullptr.

Bug: b/524864599
Change-Id: Ib30a36a42ff4509533297eabd4eadfd6168f349a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1295057
Reviewed-by: Florin Malita <fmalita@google.com>
Commit-Queue: Alexis Cruz-Ayala <alexisdavidc@google.com>
---
diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
index 6695a39..c95badb 100644
--- a/src/core/SkTextBlob.cpp
+++ b/src/core/SkTextBlob.cpp
@@ -778,6 +778,12 @@
                 !reader.readByteArray(buf->utf8text, textSize)) {
                 return nullptr;
             }
+
+            for (int i = 0; i < glyphCount; ++i) {
+                if (buf->clusters[i] >= static_cast<uint32_t>(textSize)) {
+                    return nullptr;
+                }
+            }
         }
     }
 
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.