Medium CVSS 6.5 webkit Cross Origin 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionA malicious website may exfiltrate data cross-origin
ComponentWebCore CSS
Bug ClassCross Origin
Tracker290992
Fix commit647e80ac22b3 (WebKit/WebKit) +243/-19
CWECWE-352 (CSRF)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedIvan Fratric of Google Project Zero
Disclosed2025-05-12

Background

Origin-clean / CORS-same-origin stylesheet
A stylesheet is origin-clean if it is same-origin or fetched with CORS and CORS-same-origin; only then may script read its rules.
canAccessRules()
The CSSOM guard that decides whether script may read/modify a stylesheet’s rules based on origin.
CSSOM wrapper
The CSSStyleSheet script object wrapping engine StyleSheetContents; created for link, @import and xml-stylesheet sheets.
Same-origin policy (SOP)
The rule that script may not read cross-origin resource contents, including cross-origin CSS rule text.

Root Cause Analysis

CSSOM access to a stylesheet’s rules is gated by CSSStyleSheet::canAccessRules(), which must return false for a cross-origin (not origin-clean) sheet so script cannot read or mutate cross-origin CSS. Two defects made that gate leaky. First, canAccessRules() returned true when ownerDocument() was null: Document* document = ownerDocument(); if (!document) return true;. A CSSStyleSheet wrapper can outlive its owner node / be detached from the document (e.g. the owning element is removed), at which point ownerDocument() is null and the check fell open, granting access to a sheet whose origin can no longer be verified. Second, the origin-clean flag was not propagated correctly when constructing CSSStyleSheet CSSOM wrappers for imported/linked sheets: CSSImportRule::styleSheet(), ProcessingInstruction::setCSSStyleSheet() and HTMLLinkElement::initializeStyleSheet() created wrappers without threading the real CachedCSSStyleSheet::isCORSSameOrigin() value (HTMLLinkElement even had a FIXME and only set originClean when fetch mode was CORS), so a cross-origin sheet could be treated as origin-clean.

The fix (a) makes canAccessRules() return false when there is no owner document, (b) adds explicit canAccessRules() checks to insertRule()/deleteRule() that throw SecurityError for cross-origin sheets, and (c) plumbs the true isCORSSameOrigin/origin-clean flag into CSSStyleSheet::create for import rules, processing instructions and link elements.

The restored invariant is that rule read/write on a stylesheet is permitted only when the sheet is provably same-origin (or CORS-clean), including after it is detached from its document. The added layout test reads a cross-origin sheet after removing it from the document.

Key insight
canAccessRules() fell open (returned true) when a stylesheet had no owner document, and CSSOM wrappers weren’t given the correct origin-clean flag, so cross-origin stylesheet rules became readable — an SOP bypass; the fix denies access when the owner document is gone and propagates the real origin-clean state.

Attack Path

  1. Load a cross-origin stylesheet Reference a stylesheet from another origin without CORS (e.g. <link rel=stylesheet> or @import to a cross-origin URL).
  2. Get its CSSOM wrapper Obtain the CSSStyleSheet object (document.styleSheets / the link’s .sheet), which pre-patch may be wrapped without the correct origin-clean flag.
  3. Detach it from the document Remove the owning link/element so ownerDocument() becomes null, making canAccessRules() fall open (return true).
  4. Read/modify cross-origin rules Access cssRules/insertRule/deleteRule to read the cross-origin CSS text (which can encode sensitive, per-user data) or mutate it — a same-origin-policy bypass / information disclosure.

Impact Assessment

A same-origin-policy bypass allowing script to read (and modify) the rules of a cross-origin stylesheet, particularly after detaching it from the document. This is an information-disclosure primitive — cross-origin CSS can encode user-specific state — with no direct memory-safety component; it executes in the WebContent process. Rated medium.

Changed Functions

FunctionChangeNotes
CSSStyleSheet::canAccessRules
Source/WebCore/css/CSSStyleSheet.cpp
modified Returns false (was true) when ownerDocument() is null, so a detached sheet can no longer be read cross-origin.
CSSStyleSheet::insertRule / deleteRule
Source/WebCore/css/CSSStyleSheet.cpp
modified Now call canAccessRules() and throw SecurityError for cross-origin sheets before mutating rules.
CSSStyleSheet::create / constructor (+ m_isOriginClean)
Source/WebCore/css/CSSStyleSheet.cpp
modified Accept and store an isOriginClean flag for CSSImportRule-owned sheets so the origin-clean state is set correctly.
CSSImportRule::styleSheet
Source/WebCore/css/CSSImportRule.cpp
modified Derives isOriginClean from cachedCSSStyleSheet()->isCORSSameOrigin() and passes it into the wrapper.
ProcessingInstruction::setCSSStyleSheet / HTMLLinkElement::initializeStyleSheet
Source/WebCore/dom/ProcessingInstruction.cpp
modified Pass the CachedCSSStyleSheet::isCORSSameOrigin() value into CSSStyleSheet::create, removing the incomplete CORS-only origin-clean logic (FIXME) in HTMLLinkElement.

Files Changed

  • LayoutTests/http/tests/security/access-cssstylesheet-after-removing-from-document-expected.txt
  • LayoutTests/http/tests/security/access-cssstylesheet-after-removing-from-document.html
  • LayoutTests/http/tests/security/access-imported-cssstylesheet-after-removing-from-document-expected.txt
  • LayoutTests/http/tests/security/access-imported-cssstylesheet-after-removing-from-document.html
  • LayoutTests/http/tests/security/cannot-read-cssrules-redirect-expected.txt
  • LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-request-css-cross-origin.https-expected.txt
  • Source/WebCore/css/CSSImportRule.cpp
  • Source/WebCore/css/CSSStyleSheet.cpp
  • Source/WebCore/css/CSSStyleSheet.h
  • Source/WebCore/dom/ProcessingInstruction.cpp
  • Source/WebCore/html/HTMLLinkElement.cpp

Audit Directions

  • Other fall-open origin checks
    grep WebCore for security predicates that return true on a null document/frame/origin (canAccessRules, canRequest wrappers), where the safe default is deny.
  • Origin-clean propagation
    Audit every CSSStyleSheet::create call site (import, link, xml-stylesheet, constructed sheets) to confirm isOriginClean/isCORSSameOrigin is threaded correctly.
  • Detached-object access
    Review CSSOM/DOM objects that can outlive their owner node for security checks that depend on the now-null owner (ownerDocument/ownerNode).

Original Bug Report

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