Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds write in Skia
DescriptionOut of bounds write in Skia
ComponentSkia
Bug ClassOOB
Tracker500071763
Fix commitfa3d352e688f (skia) +5/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
while
src/ports/SkTypeface_mac_ct.cpp
modified
if
src/ports/SkTypeface_mac_ct.cpp
modified

Files Changed

  • src/ports/SkTypeface_mac_ct.cpp
From fa3d352e688f1edc9b8fd4fc4e7b099c35214225 Mon Sep 17 00:00:00 2001
From: Daniel Angulo <angdaniel@google.com>
Date: Thu, 16 Apr 2026 16:59:03 +0000
Subject: [PATCH] added bounds check for glyph access on typeface

quick fix for a  potential security issue

Bug: 500071763
Change-Id: I24a6f4a6a4b58706b792668037011d86da8bd1d4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1210036
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
Auto-Submit: Daniel Angulo <angdaniel@google.com>
---

diff --git a/src/ports/SkTypeface_mac_ct.cpp b/src/ports/SkTypeface_mac_ct.cpp
index f52a5e5..21d6e9c 100644
--- a/src/ports/SkTypeface_mac_ct.cpp
+++ b/src/ports/SkTypeface_mac_ct.cpp
@@ -376,16 +376,17 @@
 // Web fonts added to the CTFont registry do not return their character set.
 // Iterate through the font in this case. The existing caller caches the result,
 // so the performance impact isn't too bad.
-static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
+static void populate_glyph_to_unicode_slow(CTFontRef ctFont, const CFIndex glyphCount,
                                            SkUnichar* out) {
     sk_bzero(out, glyphCount * sizeof(SkUnichar));
+    CFIndex glyphsRemaining = glyphCount;
     UniChar unichar = 0;
-    while (glyphCount > 0) {
+    while (glyphsRemaining > 0) {
         CGGlyph glyph;
         if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
-            if (out[glyph] == 0) {
+            if (glyph < glyphCount && out[glyph] == 0) {
                 out[glyph] = unichar;
-                --glyphCount;
+                --glyphsRemaining;
             }
         }
         if (++unichar == 0) {
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Heap OOB Write in Skia's populate_glyph_to_unicode_slow during PDF generation

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the security team.

Overview: A potential heap out-of-bounds write exists in Skia’s macOS font handling when processing malicious fonts during PDF generation. A compromised renderer can bypass OpenType Sanitizer (OTS) by sending a crafted font to the PrintCompositor, triggering an OOB write when Skia maps Unicode characters to glyphs. This could potentially allow an attacker to achieve Remote Code Execution in the privileged PrintCompositor process.

Affected files:

  • third_party/skia/src/ports/SkTypeface_mac_ct.cpp

Estimated timestamp from git blame: 2020-06-05

Summary

A potential heap-based out-of-bounds (OOB) write vulnerability exists in SkTypeface_Mac::populate_glyph_to_unicode_slow within Skia’s macOS-specific font handling code. When the PrintCompositor utility process deserializes an untrusted font provided by a compromised renderer, it bypasses the standard OpenType Sanitizer (OTS) checks. A maliciously crafted font can cause macOS’s CoreText API to return out-of-bounds glyph IDs, which Skia then uses to index a heap-allocated buffer without verifying the bounds, leading to memory corruption.

Note: The steps and impact described below are based on detailed static analysis. Our tooling does not yet have the ability to run code to provide a fully working Proof of Concept.

Technical Details

The defect is located in third_party/skia/src/ports/SkTypeface_mac_ct.cpp. The function populate_glyph_to_unicode_slow builds a mapping from glyph IDs to Unicode characters.

static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
                                           SkUnichar* out) {
    sk_bzero(out, glyphCount * sizeof(SkUnichar));
    UniChar unichar = 0;
    while (glyphCount > 0) {
        CGGlyph glyph;
        if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
            // VULNERABILITY: No bounds check to ensure glyph < glyphCount
            if (out[glyph] == 0) { 
                out[glyph] = unichar;
                --glyphCount;
            }
        }
        // ...
    }
}

The out array is backed by a std::vector<SkUnichar> allocated in SkPDFFont::GetUnicodeMap. The size of this vector is strictly determined by the font’s reported numGlyphs (from the font’s maxp table). However, the code uses the glyph ID returned by CTFontGetGlyphsForCharacters directly as an index into out. If a malicious font’s cmap table maps a character to a glyph ID exceeding the total glyph count, an out-of-bounds write occurs on the PartitionAlloc heap. A sibling function in the same file, get_plane_glyph_map, correctly implements this check (if (glyphs[0] < glyphCount)).

Potential Attacker Steps

An attacker could potentially trigger this vulnerability by following these steps:

  1. Compromise a Renderer: The attacker gains code execution in a renderer process.
  2. Craft a Malicious Font: The attacker generates an SFNT font blob with a very small maxp.numGlyphs value (e.g., 10), but crafts the cmap table to map a specific Unicode character (e.g., 0x1337) to a large, out-of-bounds glyph ID (e.g., 1000).
  3. Trigger Print Spooling: The compromised renderer initiates a print job, embedding the raw malicious font into the serialized SkPicture data stream sent to the browser.
  4. Bypass OTS: The PrintCompositor utility process receives the stream and deserializes the font via DeserializeOopTypeface. On macOS, this invokes CTFontManagerCreateFontDescriptorFromData directly, entirely bypassing the OpenType Sanitizer (OTS) which would normally catch the cmap/maxp mismatch.
  5. Trigger OOB Write: During PDF generation, SkPDFFont::GetUnicodeMap allocates a tiny 10-element vector. Skia falls back to populate_glyph_to_unicode_slow, iterates over characters, and asks CoreText for the glyph mapping. CoreText returns the malicious out-of-bounds glyph ID (1000). Skia writes the 32-bit Unicode character into out[1000], corrupting memory far beyond the allocated vector.

Impact

This vulnerability provides a strong primitive: a controlled out-of-bounds write of a 16-bit value (zero-extended to 32 bits) at a highly controllable offset on the heap. Exploiting this could allow an attacker to overwrite adjacent objects or pointers (e.g., vtable pointers) to achieve Remote Code Execution (RCE) in the PrintCompositor process.

While PrintCompositor is a sandboxed utility process, it frequently processes cross-origin print jobs (such as OOPIFs). An RCE in this process would allow an attacker to bypass Site Isolation and steal sensitive cross-origin data from printed documents.

Suggested Fix

Add an explicit bounds check in populate_glyph_to_unicode_slow before accessing the out array.

        CGGlyph glyph;
        if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
            if (glyph < glyphCount && out[glyph] == 0) {
                out[glyph] = unichar;
                // ...

Evaluated with Chrome root at commit: f200f57a19490707ff8bc7aa5de3cbc443a3afad


Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker