Medium CVSS 7 webkit OOB 🔧 Commit mapped

Overview

Medium
Severity
7
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected process crash
ComponentWebCore
Sub-componentWebCore CSS
Bug ClassOOB
Tracker286462
Fix commit575e5800d5bb (WebKit/WebKit) +16/-3
CWECWE-120 (Buffer overflow)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H
CISA KEVNot listed
CreditedFrancisco Alonso (@revskills), and an anonymous researcher
Disclosed2025-03-31

Background

CSS transform fast path
An optimized parser for simple transform values (rotate/translate/scale) that indexes directly into the value string.
Length gate
A minimum-length check that makes a fixed set of indices safe; a longer branch needs its own, larger gate.
argumentStart = 11
The translate branch reads the value at index 11, requiring the string to be at least 12 characters.

Root Cause Analysis

This fixes an out-of-bounds read in the CSS transform fast-path parser. parseSimpleTransformValue first checks that the input has at least 9 characters (shortestValidTransformStringLength, for ‘rotate(0)’), which guarantees pos[0]..pos[8] are safe to read. It then detects the ’translate’ family by inspecting those bytes, and in the isTranslate branch reads further into the buffer — up to pos[11] (argumentStart = 11) and beyond — without any additional length check. Inputs like ’translatez’ (10 chars) or ’translate3d’ (11 chars) satisfy the isTranslate detection but are shorter than the indices the branch accesses, so reading pos[9..11] runs past the end of the buffer — an out-of-bounds read that can crash (or leak adjacent memory).

The fix adds, inside the isTranslate branch, a check end - pos < shortestValidTranslateStringLength (12, for ’translate(0)’) that returns nullptr before the higher-index reads.

The restored invariant is that each transform sub-parser verifies enough remaining length for every index it will access. The regression test sets transform to ’translatez’ and ’translate3d’.

Key insight
The transform fast path validated only the 9-character minimum for ‘rotate(0)’ but the translate branch reads index 11, so short ’translate’ inputs read out of bounds; a per-branch length check fixes it.

Attack Path

  1. Set a short translate value Assign a CSS transform like ’translatez’ or ’translate3d’ (10-11 chars) that passes the 9-char length gate and the isTranslate detection.
  2. Access beyond the buffer The translate branch reads pos[9..11] without checking the string is at least 12 chars.
  3. Out-of-bounds read Reading past the end of the value buffer crashes or reads adjacent heap memory in WebContent.

Impact Assessment

An out-of-bounds read in the WebContent process from a crafted CSS transform value — reachable from any styled page. The advisory rates it a process crash; OOB reads can also leak adjacent memory, though this fast-path read is a comparatively narrow primitive.

Changed Functions

FunctionChangeNotes
if
Source/WebCore/css/parser/CSSParserFastPaths.cpp
modified

Files Changed

  • LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt
  • LayoutTests/fast/css/transform-translate-parsing-crash.html
  • Source/WebCore/css/parser/CSSParserFastPaths.cpp

Audit Directions

  • Same function: per-branch length
    Audit parseSimpleTransformValue’s scale/translate3d/matrix branches for index accesses beyond the 9-char gate lacking their own length checks.
  • Fixed-index string parsers
    Grep CSSParserFastPaths for pos[N] accesses guarded only by an earlier, smaller minimum-length check.
diff --git a/Source/WebCore/css/parser/CSSParserFastPaths.cpp b/Source/WebCore/css/parser/CSSParserFastPaths.cpp
index c692b9543476..abcc2d5b5595 100644
--- a/Source/WebCore/css/parser/CSSParserFastPaths.cpp
+++ b/Source/WebCore/css/parser/CSSParserFastPaths.cpp
@@ -835,12 +835,12 @@ static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigne
     return true;
 }
 
-static constexpr int kShortestValidTransformStringLength = 9; // "rotate(0)"
-
 template <typename CharType>
 static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
 {
-    if (end - pos < kShortestValidTransformStringLength)
+    // Also guarantees indexes up to pos[8] are safe to access below.
+    constexpr auto shortestValidTransformStringLength = 9; // "rotate(0)"
+    if (end - pos < shortestValidTransformStringLength)
         return nullptr;
 
     bool isTranslate = toASCIILower(pos[0]) == 't'
@@ -854,6 +854,11 @@ static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharTy
         && toASCIILower(pos[8]) == 'e';
 
     if (isTranslate) {
+        // Also guarantees indexes up to pos[11] are safe to access below.
+        constexpr auto shortestValidTranslateStringLength = 12; // "translate(0)"
+        if (end - pos < shortestValidTranslateStringLength)
+            return nullptr;
+
         CSSValueID transformType;
         unsigned expectedArgumentCount = 1;
         unsigned argumentStart = 11;
diff --git a/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt b/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt
new file mode 100644
index 000000000000..2985393944b6
--- /dev/null
+++ b/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash
diff --git a/LayoutTests/fast/css/transform-translate-parsing-crash.html b/LayoutTests/fast/css/transform-translate-parsing-crash.html
new file mode 100644
index 000000000000..aa3dd7fa63f2
--- /dev/null
+++ b/LayoutTests/fast/css/transform-translate-parsing-crash.html
@@ -0,0 +1,7 @@
+<div id=t>This test passes if it doesn't crash</div>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+t.style.transform = "translatez";
+t.style.transform = "translate3d";
+</script>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt b/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt
new file mode 100644
index 000000000000..2985393944b6
--- /dev/null
+++ b/LayoutTests/fast/css/transform-translate-parsing-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it doesn't crash
diff --git a/LayoutTests/fast/css/transform-translate-parsing-crash.html b/LayoutTests/fast/css/transform-translate-parsing-crash.html
new file mode 100644
index 000000000000..aa3dd7fa63f2
--- /dev/null
+++ b/LayoutTests/fast/css/transform-translate-parsing-crash.html
@@ -0,0 +1,7 @@
+<div id=t>This test passes if it doesn't crash</div>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+t.style.transform = "translatez";
+t.style.transform = "translate3d";
+</script>
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker.