New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 4 users

Issue metadata

Status: Fixed
Not working on Chrome any more
Closed: Nov 29
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: ----
Type: Bug

Blocked on:
issue 788061

Show other hotlists

Hotlists containing this issue:

Sign in to add a comment

Security: Inconsistent CORS implementation regarding CSS and the link element.

Reported by, Oct 17 Back to list

Issue description

In the Google Chrome 61.0.3163.100 we found an issue with write access to cross-origin CSS rules embedded with the link element using CORS .

A normal request (crossorigin attribute not set), even when answered with valid CORS headers, grants write access to cross-origin CSS rules that were embedded using the link element.
Yet, when the link element is used with the crossorigin attribute set (i.e. a CORS request) write access is only granted if the server responds with valid CORS headers. 

Valid CORS headers mean that the Access-Control-Allow-Origin header is set to either the requesting origin or the wildcard value *.
Furthermore, if the crossorigin attribute was set to use-credentials then valid CORS headers include that the Access-Control-Allow-Credentials header is set to the value true.

We think that this behavior is inconsistent since either access should be granted always if access is granted in case of a non CORS request or that access should be denied in case of non CORS request and only granted if a CORS request is answered with valid CORS headers.

Chrome Version: 61.0.3163.100 stable
Operating System: Windows + Linux

We apologize that we do not provide an HTML file to reproduce the issue.
To reproduce the issue please use the test cases for the link element in the framework at
To clearly view the differences displayed in the attachment visit and only display differences as well as colorize.

The attached files highlight the differences as they can be found in the framework.

76.7 KB View Download
153 KB View Download
Components: Blink>SecurityFeature>SameOriginPolicy
Thanks for the report. Is the Usenix paper ( yours, or are you reporting the output of another researcher's tool?

Unfortunately, it's challenging to interpret this report as the repro is not minimized and it's not immediately obvious what "write access" means, how it is determined, and what the security impact of such access would be.

It's unclear whether there's an actual security issue here, a functional issue, or whether everything is behaving as expected. 

The HTML5.1 spec ( simply notes: "The crossorigin attribute is a CORS settings attribute. It is intended for use with external resource links." It does not further specify the behavior of enabling CORS mode on a stylesheet.

My initial read of this issue suggests that it could be resummarized as: "If the HTML markup sets a |crossorigin| attribute on a LINK element pointed at a stylesheet, then that stylesheet is not applied unless the server agrees to CORS semantics using appropriate Access-Control-Allow headers."

If that's the case, then I believe everything is working as expected.
The Usenix paper is not mime, but I'm currently writing my Bachelor Thesis and the author of the paper is my supervisor. During my thesis I extended the framework. Therefore, I think it's our tool.

First, no "If the HTML markup sets a |crossorigin| attribute on a LINK element pointed at a stylesheet, then that stylesheet is not applied unless the server agrees to CORS semantics using appropriate Access-Control-Allow headers." is not what I mean.

Write access is defined as being able to change the embedded CSS.
Therefore, I think you are right this is not a security issue. I was simply suggested to report it as an security issue to keep it from public for now. 

It is more like a functional issue since we can change the embedded CSS in the cross-origin case without CORS but when using CORS we can only change it if the appropriate Access-Control-Allow headers are returned.

As I intended to clarify, this is simply inconsistent. It should either always allow "write access" or simple deny "write access" when not using CORS.
Can you elaborate on what, specifically, you mean when you say that you can "change the embedded CSS"? A stylesheet fetched via a LINK with a |crossorigin| attribute is *ignored* unless the server sends headers that pass the "CORS check" ( Hence, there's not really anything to "change".

The Fetch spec ( calls for this behavior
"If CORS flag is set and a CORS check for request and response returns failure, then return a network error."


In Chrome's Developer Tools console, you'll find: Access to CSS stylesheet at '' from origin '' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '' is therefore not allowed access.

Firefox behavior matches Chrome.

Is there some reason you want to "keep it from public for now"?
Ok, erm when I say change the embedded CSS is mean modifying the CSS loaded.
To verify if we can modify the CSS loaded we do something like this:

var styles = document.styleSheets[0];
styles.insertRule('h1 {color: blue !important}', 1);
var h1 = document.getElementById("h1");
var cssColor = window.getComputedStyle( h1, null).getPropertyValue("color");
if (cssColor == "rgb(0, 0, 255)") {
    set(id, 'yes', "CSS is applied to element.");
} else {
    set(id, 'no', "CSS is not applied to element.");

In short we add something to the embedded CSS.

Regarding which cases I refer. I know that the CORS behavior is actually correct as it is currently implemented.
What I wish to point out is the behavior in which Firefox disallows write access but Chrome and others allow write access.
This is basically that Chrome allows write access to cross-origin CSS even though no CORS is used at all. 

I personally have no reason to keep it from public.
I simply followed the advice of my supervisor.

When the stylesheet is blocked because it fails the CORS check, it is empty. 

JavaScript can add rules to the empty sheet (e.g. push the button on although, because the sheet is empty you must adjust the insertRule call to pass 0 rather than 1.

JavaScript can also add rules to a sheet that's empty because it does not exist:

Ok so it's intended to be able to add rules to a remote CSS.

That means it's also intended to add rules to remote CSS that was included without the crossorigin attribute.

If so then please close the ticket. 
after you pointed out that a link element using the crossorigin attrbiute does not load the CSS at all if it fails the CORS check I had a look at the framework again and discovered an issue with some of the link test cases leading to incorrect results.

As of now I fixed this issue an will soon have it at

But I'd still like to point out that e.g. Firefox does not grant write access to a cross-origin CSS file that was loaded without CORS.
I thought that this behavior is more in line with the idea behind CORS since CORS is supposed to lessen the restrictions employed by the SOP.

Yet, I agree that it is possible to add CSS rules to an empty CSS sheet using 0 instead of 1 in the parameter.
But we used 0 because we wanted only write access if the CSS was actually loaded.

I hope I could make my point clear :)
Edit: typo above, we used 1 because we wanted only write access if the CSS was actually loaded not 0. 
Components: Blink>CSS
Indeed, Firefox refuses to permit manipulation of a cross-domain stylesheet without the |crossorigin| attribute, throwing "SecurityError: The operation is insecure."

What's less clear is why this is deemed a security-sensitive operation in Firefox, as inserting a rule into the sheet does not seem to leak any information and it is allowed in Chrome, Edge, and IE.
Firstly I think we shouldn't compare with Edge/IE since those two always allow read and write access to CSS regardless of the CORS settings. (even non CORS requests)

I think that Firefox denies access because this is in line with normal behavior, e.g. comparing with an iframe. It's cross-origin -> you can't read or write its content.

Same-Origin-Policy is more subtle than that. There are accessible (e.g. read/write and write-only) properties on cross-origin frames, for instance. 

If Chrome or another browser offered a direct way to read from a cross-origin file without CORS directives, that would be surprising and interesting. Writing into a stylesheet originally loaded from a cross-origin source does not seem interesting. 
Labels: -Type-Bug-Security -Restrict-View-SecurityTeam Type-Bug
Status: Assigned
I agree with Eric that I don't see much risk here, as it both requires script access to the page, and we're not actually exposing the CSS file's content.

That said, this behavior does violate the CSSOM spec (step 1 of We should probably be calling `CSSStyleSheet::CanAccessRules()` at the top of `CSSStyleSheet::insertRule()`, and throwing a `SecurityException` accordingly.

Throwing //core/css/OWNERS into `` makes the lucky winner! Would you mind triaging this specific issue (and probably skimming through the rest of the `origin-clean flag` requirements at the same time)? 

Opening this up as a non-security, correctness bug. Thanks very much for the report!
Thank you very much for your patience and sorry for any misleading or unclear explanations on my side.
Labels: Update-Monthly
I just want to add something regarding Comment 11: "Writing into a stylesheet originally loaded from a cross-origin source does not seem interesting." is actually just half true. You can still do "Scriptless Attacks" that are *sometimes* very similar to XSS:
"Scriptless attacks" are interesting insofar as they can trigger behaviors traditionally thought to require script. 

The scenario described here is to use JavaScript to manipulate a Stylesheet DOM. If the attacker already has the ability to execute script in order to manipulate the stylesheet, they've already achieved script execution and need not bother with trying to mimic script execution with a scriptless attack.
Labels: Hotlist-Interop
 Issue 650534  has been merged into this issue.
Labels: Hotlist-EnamelAndFriendsFixIt
Boris noted this again in meade@, do you think someone on the style team can take a look at aligning our cross-origin behavior with the spec (and Firefox)?
Hi mkwst, I have a CL up for this (, but I'm struggling a bit to update the tests...
Blockedon: 788061
Project Member

Comment 23 by, Nov 29

The following revision refers to this bug:

commit a4ebe08c91e29140e700c7bae9b94f27a786d1ca
Author: Eddy Mead <>
Date: Wed Nov 29 04:46:24 2017

Update behavior of CSSStyleSheet to match spec for Security origin

Spec is here:

Updated: the following methods now throw a SecurityError if the
style sheet is not accessible:
- cssRules() / rules()
- insertRule()
- deleteRule()

Bug:  775525 
Change-Id: I409d486df0f0fdced4684b19e3fae4c3a0ec2868
Commit-Queue: meade_UTC10 <>
Reviewed-by: nainar <>
Cr-Commit-Position: refs/heads/master@{#520005}

Status: Fixed
One issue with this change is how to detect that the stylesheet isn't accessible from within the javascript.  Before this change cssRules would return null and that provided a simple check for skipping sheets that either were empty or were inaccessible.  There doesn't seem to be a way to check that now without comparing the href having all info about allowed origins.

Is the only option to wrap the read of cssRules in a try/catch?

This bugfix caused a bug in our application.  Full story here:

Fixing the security issue is obviously top priority, but I'm wishing for a couple things that would have made this change more developer-friendly, helped us debug faster and maybe have caught the issue before it happened.

1. Advertising the change.  I couldn't find mention of this change in any change logs, including the "New in Chrome 64" or "Chrome 64 deprecations" blog posts.  I eventually discovered the change through a link to the Chromium commit on this Dojo Toolkit bug:

2. The error message,

Uncaught DOMException: Failed to read the 'rules' property from 'CSSStyleSheet'

does not immediately make it clear that the problem is a CORS violation.  The referenced spec ( says a SecurityError exception will be thrown.  I don't know how you pick an exception type in this case, but something called SecurityError might be a little clearer about what's going wrong.

Just my two cents.  Thanks!

Sign in to add a comment