Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in CSS
DescriptionInappropriate implementation in CSS
ComponentCSS
Bug ClassLogic Error
Tracker514485825
Fix commit6675ff91b75f (chromium/src) +5/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/core/css/css_math_expression_node.h
modified

Files Changed

  • third_party/blink/renderer/core/css/css_math_expression_node.h
  • third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
From 6675ff91b75f5c8c49d65fc6dc6f4e480029eed7 Mon Sep 17 00:00:00 2001
From: Rune Lillesveen <[email protected]>
Date: Thu, 21 May 2026 04:13:07 -0700
Subject: [PATCH] Escape idents in random() functions for serialization

Bug: 514485825
Change-Id: If48015cb506fe0d9ffdb5e42db2c623f24b03911
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7858318
Reviewed-by: Munira Tursunova <[email protected]>
Commit-Queue: Rune Lillesveen <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1634169}
---

diff --git a/third_party/blink/renderer/core/css/css_math_expression_node.h b/third_party/blink/renderer/core/css/css_math_expression_node.h
index ca736fc5..e7b19e2f 100644
--- a/third_party/blink/renderer/core/css/css_math_expression_node.h
+++ b/third_party/blink/renderer/core/css/css_math_expression_node.h
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_length_resolver.h"
+#include "third_party/blink/renderer/core/css/css_markup.h"
 #include "third_party/blink/renderer/core/css/css_math_operator.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value.h"
 #include "third_party/blink/renderer/core/css/css_scoped_keyword_value.h"
@@ -1185,7 +1186,7 @@
     String CssText() const {
       StringBuilder result;
       if (ident) {
-        result.Append(ident);
+        SerializeIdentifier(ident, result);
       }
       if (is_element_scoped) {
         if (!result.empty()) {
@@ -1197,7 +1198,7 @@
         if (!result.empty()) {
           result.Append(" ");
         }
-        result.Append(ua_ident);
+        SerializeIdentifier(ua_ident, result);
       }
       return result.ToString();
     }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
index 743b3a56..07fcfa3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
@@ -70,6 +70,8 @@
                           'random(element-scoped ua-width-1, 0px, 100px, 3px)');
 test_valid_value('width', 'random(--foo property-index-scoped element-scoped , 0px, 100px, 3px)',
                           'random(--foo element-scoped ua-width-1, 0px, 100px, 3px)');
+test_valid_value('width', 'random(--\\{ element-scoped, 0px, 100px, 3px)');
+test_valid_value('width', 'random(element-scoped ua-\\{, 0px, 100px, 3px)');
 
 // Test consistent types
 test_valid_value('width', 'random(--foo, 10px, 20%)');
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
index 743b3a56..07fcfa3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/random-serialize.tentative.html
@@ -70,6 +70,8 @@
                           'random(element-scoped ua-width-1, 0px, 100px, 3px)');
 test_valid_value('width', 'random(--foo property-index-scoped element-scoped , 0px, 100px, 3px)',
                           'random(--foo element-scoped ua-width-1, 0px, 100px, 3px)');
+test_valid_value('width', 'random(--\\{ element-scoped, 0px, 100px, 3px)');
+test_valid_value('width', 'random(element-scoped ua-\\{, 0px, 100px, 3px)');
 
 // Test consistent types
 test_valid_value('width', 'random(--foo, 10px, 20%)');
Loading diff…

Original Bug Report

reported by [email protected]

Potential CSS declaration injection via unescaped random() function serialization

Flapjack, 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: A potential CSS declaration injection exists because RandomName::CssText() appends raw identifier strings instead of using SerializeIdentifier. An attacker can use escape sequences to embed payload characters that are serialized raw, breaking out of the function context. This impacts the experimental CSSRandomFunction feature.

Affected files:

  • third_party/blink/renderer/core/css/css_math_expression_node.h

Estimated timestamp from git blame: 2025-11-24

Final Result / Core Issue

A potential CSS declaration injection (mXSS) vulnerability is triggered because RandomName::CssText() in third_party/blink/renderer/core/css/css_math_expression_node.h serializes identifier cache keys raw without escaping.

Potential Trigger Steps

  1. Initial logic and parameters are validated: A CSS payload utilizing escaped identifiers (e.g., width: random(--foo\29 \3b \20 color\3a red\3b , 1px, 2px);) is correctly decoded by the tokenizer, and the unescaped literal string --foo); color:red; is stored in the ident field of the RandomName struct.
  2. Standard AST node allocation and property value cache population applied.
  3. During CSS serialization (e.g., via element.style.cssText), execution jumps directly to RandomName::CssText(), which evaluates result.Append(ident);. This emits the raw payload string without invoking SerializeIdentifier, producing the mutated string random(--foo); color:red;, 1px, 2px).
  4. The subsequent re-parsing of this string prematurely closes the random() context and successfully applies the injected color:red; declaration.

Note: These are suggested/potential steps, as our tooling agent doesn’t yet have the ability to run code.

Suggested Fix

Modify RandomName::CssText() to use SerializeIdentifier(ident, result); (defined in third_party/blink/renderer/core/css/css_markup.h) instead of result.Append(ident);.

Evaluated with Chrome root at commit: b7d0c4d810da1b31400f198c70d9720fc8f0e5a0


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