High chrome Integer Overflow 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInteger overflow in Skia
DescriptionInteger overflow in Skia
ComponentSkia
Bug ClassInteger Overflow
Tracker513973560
Fix commit7c9ffcb347d4 (skia) +17/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-05-27

Changed Functions

FunctionChangeNotes
if
src/pathops/SkPathWriter.cpp
modified
for
src/pathops/SkPathWriter.cpp
modified

Files Changed

  • src/pathops/SkPathWriter.cpp
From 7c9ffcb347d4169fdca223d21cc62c2c0420db66 Mon Sep 17 00:00:00 2001
From: Kaylee Lubick <[email protected]>
Date: Tue, 19 May 2026 15:07:23 +0000
Subject: [PATCH] Avoid overflow and timeout in SkPathWriter::assemble

I was unable to make a test case that caused an overflow
and didn't timeout, but I think the possibility exists
for both.

This removes that, adds a few defensive asserts, and
makes one assert actually checked at runtime, just to be safe.

Change-Id: I4ce112624cb346ac7597466ac9c78402c5061e1c
Bug: 513973560
Fixed: 513973560
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1239556
Reviewed-by: Thomas Smith <[email protected]>
---

diff --git a/src/pathops/SkPathWriter.cpp b/src/pathops/SkPathWriter.cpp
index 6577d9d..b374f9c 100644
--- a/src/pathops/SkPathWriter.cpp
+++ b/src/pathops/SkPathWriter.cpp
@@ -56,6 +56,7 @@
 }
 
 bool SkPathWriter::deferredLine(const SkOpPtT* pt) {
+    SkASSERT(pt);
     SkASSERT(fFirstPtT);
     SkASSERT(fDefer[0]);
     if (fDefer[0] == pt) {
@@ -78,6 +79,7 @@
 }
 
 void SkPathWriter::deferredMove(const SkOpPtT* pt) {
+    SkASSERT(pt);
     if (!fDefer[1]) {
         fFirstPtT = fDefer[0] = pt;
         return;
@@ -161,6 +163,7 @@
 // if last point to be written matches the current path's first point, alter the
 // last to avoid writing a degenerate lineTo when the path is closed
 SkPoint SkPathWriter::update(const SkOpPtT* pt) {
+    SkASSERT(pt);
     if (!fDefer[1]) {
         this->moveTo();
     } else if (!this->matchedLast(fDefer[0])) {
@@ -180,6 +183,7 @@
 }
 
 bool SkPathWriter::changedSlopes(const SkOpPtT* ptT) const {
+    SkASSERT(ptT);
     if (matchedLast(fDefer[0])) {
         return false;
     }
@@ -214,7 +218,15 @@
     SkOpPtT const* const* runs = fEndPtTs.begin();  // starts, ends of partial contours
     int endCount = fEndPtTs.size(); // all starts and ends
     SkASSERT(endCount > 0);
-    SkASSERT(endCount == fPartials.size() * 2);
+    SkASSERT(endCount == (int)fPartials.size() * 2);
+
+    // Limit the number of partial contours to avoid O(N^2) complexity and integer overflows.
+    // 10,000 partial contours results in 20,000 ends and ~200,000,000 distance entries.
+    constexpr int kMaxPartialContours = 10000;
+    if (endCount > kMaxPartialContours * 2) {
+        return;
+    }
+
 #if DEBUG_ASSEMBLE
     for (int index = 0; index < endCount; index += 2) {
         const SkOpPtT* eStart = runs[index];
@@ -364,7 +376,10 @@
                 if (forward) {
                     next = contourPts.empty() ? SkPoint{0, 0} : contourPts.front();
                 } else {
-                    SkASSERT(!contourPts.empty());
+                    if (contourPts.empty()) {
+                        SkDEBUGFAIL("unexpected empty contour");
+                        return;
+                    }
                     next = contourPts.back();
                 }
                 if (*prior != next) {
Loading diff…

Original Bug Report

reported by [email protected]

Heap memory corruption in PrintCompositor via Skia PathOps integer overflow

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: An integer overflow in Skia’s PathOps engine can be triggered by providing highly complex path geometry during PDF printing. This flaw leads to out-of-bounds memory access in the PrintCompositor utility process, potentially allowing for Site Isolation bypass or Remote Code Execution.

Affected files:

  • third_party/skia/src/utils/SkClipStackUtils.cpp
  • third_party/skia/src/pdf/SkPDFDevice.cpp
  • third_party/skia/src/pdf/SkPDFGraphicStackState.cpp
  • components/services/print_compositor/print_compositor_impl.cc
  • printing/common/metafile_utils.cc

Estimated timestamp from git blame: 2019-12-20

Potential Root Cause

A vulnerability has been identified in the Skia PathOps engine, specifically within the SkPathWriter::assemble() function in third_party/skia/src/pathops/SkPathWriter.cpp. This function is responsible for joining “partial contours” (open path segments) that remain after complex boolean operations (like Simplify or Op).

The function calculates the number of potential endpoint pairs using 32-bit signed integer arithmetic:

const int entries = endCount * (endCount - 1) / 2;

If endCount (the number of endpoints) is approximately 46,342 or greater, the product endCount * (endCount - 1) overflows the maximum value for a 32-bit signed integer (INT_MAX). This results in entries becoming negative or incorrectly small.

Technical Details

When this overflow occurs, the following memory corruption primitives are triggered:

  1. Skipped Initializations: The loop that populates the distance and link arrays (for (rIndex = 0; rIndex < entries; ++rIndex)) is skipped if entries is negative. This leaves the sLink and eLink arrays populated with their default value of SK_MaxS32 (2,147,483,647).
  2. Massive Out-of-Bounds Read: In the subsequent assembly loop, the code uses these default values as indices: eIndex = eLink[sIndex]. If sIndex is SK_MaxS32, this performs an enormous out-of-bounds read from the heap.
  3. Heap Memory Corruption: The resulting eIndex (likely containing arbitrary heap data) is then used to index into the fPartials array (a collection of SkPathBuilder objects). The subsequent call to fPartials[rIndex].snapshot() results in the engine treating arbitrary heap memory as a valid SkPathBuilder object, leading to memory corruption.
  4. Out-of-Bounds Write: Additionally, the cumulative row offset rRow used to index distLookup can also overflow, causing negative indices to be stored and later used to trigger out-of-bounds writes in the linkOne or linkTwo arrays.

Attack Vector and Reachability

An attacker who has already compromised a renderer process could potentially trigger this sink by:

  1. Generating a malicious SkMultiPictureDocument (MSKP) containing thousands of self-intersecting SkPath objects designed to create high complexity in PathOps.
  2. Submitting this document to the browser via the printing flow, which forwards the content to the PrintCompositor utility process for PDF conversion.
  3. As the PrintCompositor process replays the drawing commands, the complex geometry triggers the PathOps engine and the overflow in SkPathWriter::assemble().

Note that these are potential steps identified through code analysis; our current environment does not support executing proof-of-concept code.

Impact

The PrintCompositor service is a critical component for Site Isolation, as it aggregates content from multiple cross-origin renderer processes for printing. Compromising this process would allow an attacker to bypass Site Isolation and read cross-origin printed data.

Suggested Potential Fix

The calculations for entries and rRow in SkPathWriter::assemble should be updated to use 64-bit integers (int64_t) or Chromium’s base::CheckedNumeric to prevent overflows. Furthermore, a reasonable limit should be placed on the number of partial contours processed to mitigate both memory corruption and potential Denial of Service attacks via resource exhaustion.

Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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