CVE-2026-11186
Overview
Files Changed
third_party/blink/renderer/core/css/css_image_set_type_value.ccthird_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
Patch
From 4353c3e32cc28617e3867e7247eeaf76501e477c Mon Sep 17 00:00:00 2001
From: Rune Lillesveen <futhark@chromium.org>
Date: Wed, 15 Apr 2026 06:19:36 -0700
Subject: [PATCH] Escape serialization of image-set() type() if necessary
Bug: 502805170
Change-Id: I637c8929b14fa84648190eb045c1d844fc440630
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7758510
Auto-Submit: Rune Lillesveen <futhark@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1615100}
---
diff --git a/third_party/blink/renderer/core/css/css_image_set_type_value.cc b/third_party/blink/renderer/core/css/css_image_set_type_value.cc
index e3b8c8b..b2f64fa 100644
--- a/third_party/blink/renderer/core/css/css_image_set_type_value.cc
+++ b/third_party/blink/renderer/core/css/css_image_set_type_value.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/css_image_set_type_value.h"
#include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "third_party/blink/renderer/core/css/css_markup.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -17,9 +18,9 @@
String CSSImageSetTypeValue::CustomCSSText() const {
StringBuilder result;
- result.Append("type(\"");
- result.Append(type_);
- result.Append("\")");
+ result.Append("type(");
+ SerializeString(type_, result);
+ result.Append(")");
return result.ReleaseString();
}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
index ee57c85..b082da6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
@@ -265,6 +265,10 @@
"image-set(url(example.png) 1x type('image/jpeg'))",
'image-set(url("example.png") 1x type("image/jpeg"))'
);
+ test_valid_value_variants(
+ 'background-image',
+ 'image-set(url("x") 1x type("a\\""))',
+ );
test_invalid_value_variants(
'background-image',
Regression Test / PoC
diff --git a/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
index ee57c85..b082da6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-images/image-set/image-set-parsing.html
@@ -265,6 +265,10 @@
"image-set(url(example.png) 1x type('image/jpeg'))",
'image-set(url("example.png") 1x type("image/jpeg"))'
);
+ test_valid_value_variants(
+ 'background-image',
+ 'image-set(url("x") 1x type("a\\""))',
+ );
test_invalid_value_variants(
'background-image',
Original Bug Report
CSS mXSS via Missing Serialization Escaping in CSSImageSetTypeValue
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 Chrome Security team. Please see go/chrome-ai-generated-security-bugs-faq for more information.
Overview: The serialization logic for CSSImageSetTypeValue fails to escape special characters like double quotes when outputting its .cssText. This breaks the CSSOM round-trip invariant, allowing an attacker to smuggle arbitrary CSS declarations past sanitizers using CSS escape sequences. This constitutes a potential CSS mutation Cross-Site Scripting (mXSS) vulnerability.
Affected files:
third_party/blink/renderer/core/css/css_image_set_type_value.ccthird_party/blink/renderer/core/css/css_image_set_option_value.ccthird_party/blink/renderer/core/css/css_image_set_value.cc
Estimated timestamp from git blame: 2023-03-03
Summary
A potential CSS mutation Cross-Site Scripting (mXSS) vulnerability exists in the CSS serialization logic for the type() component of the image-set() function. The vulnerability allows an attacker to inject arbitrary CSS declarations into a stylesheet by exploiting a serialization flaw that fails to escape special characters.
Technical Details
When a CSS property containing an image-set() function is parsed, the Blink CSS tokenizer correctly decodes CSS escape sequences. For example, \22 is decoded to a literal double quote (") and \29 to a literal closing parenthesis ()).
The parsed string is stored in a CSSImageSetTypeValue object. However, when the CSSOM tree is serialized back to a string (e.g., when a script reads element.style.cssText), the CustomCSSText() method in third_party/blink/renderer/core/css/css_image_set_type_value.cc fails to properly escape this string:
String CSSImageSetTypeValue::CustomCSSText() const {
StringBuilder result;
result.Append("type(\"");
result.Append(type_); // <--- Bug: Raw string appended without escaping
result.Append("\")");
return result.ReleaseString();
}
Unlike other string-based CSS values (such as CSSStringValue), CSSImageSetTypeValue does not use the blink::SerializeString() helper function (defined in css_markup.cc). Because it blindly concatenates the unescaped type_ string, any literal quotes or parentheses injected by the attacker are emitted raw into the serialized output.
Attack Scenario & Potential Impact
This flaw breaks the parse -> serialize -> parse idempotency invariant. Attackers can leverage this to bypass DOM sanitizers (like DOMPurify) or server-side CSS validators that rely on the safety of the browser’s CSSOM serialization.
- An attacker provides a payload like
image-set(url(x) 1x type("a\22 \29 \29 ;color:red;--x:\22 "))to a vulnerable application. - The initial parser decodes the string safely, storing it in the CSSOM.
- A sanitizer reads
.cssTextto validate or sanitize the DOM. The serialized output becomesbackground-image: image-set(url("x") 1x type("a" ) ) ;color:red;--x:" "));. - The sanitizer assigns the “safe” string back to an element.
- Upon reparsing, the literal quotes and parentheses break out of the
type()andimage-set()functions, causing the browser to evaluatecolor:red;as a new, valid CSS declaration.
This can be exploited to inject arbitrary CSS properties, leading to UI redressing or sensitive data exfiltration (e.g., via injected background-image requests based on user interaction).
Suggested Reproduction Steps
Note: These steps demonstrate the logic flaw using browser APIs; our tooling agent cannot execute code to verify the exploit directly.
- Open the browser console.
- Create a div and assign a crafted
image-setpayload:const d = document.createElement('div'); d.style.backgroundImage = 'image-set(url(x) 1x type("a\\22 \\29 \\29 ;color:red;--x:\\22 "))'; - Read the serialized CSS text:
console.log(d.style.cssText); // Output contains literal unescaped characters: background-image: image-set(url("x") 1x type("a" ) ) ;color:red;--x:" ")); - Trigger the round-trip parse by assigning the serialized text back:
d.setAttribute('style', d.style.cssText); - Verify that the injected property was parsed:
console.log(d.style.color); // Expected: "red"
Suggested Fix
Update CSSImageSetTypeValue::CustomCSSText() to use the blink::SerializeString() function, similar to how CSSStringValue handles string serialization. This will ensure that special characters within the MIME type string are correctly escaped.
#include "third_party/blink/renderer/core/css/css_markup.h"
String CSSImageSetTypeValue::CustomCSSText() const {
StringBuilder result;
result.Append("type(");
SerializeString(type_, result);
result.Append(")");
return result.ReleaseString();
}
Evaluated with Chrome root at commit: 661452647ddb2827305122ff3273bd5dea403f09
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.