Bug 69433

Summary: cloneNode and CSP don't like each other
Product: WebKit Reporter: Ulfar Erlingsson <ulfar.erlingsson>
Component: DOMAssignee: Adam Barth <abarth>
Status: RESOLVED WONTFIX    
Severity: Normal CC: abarth, sam
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 53572    

Description Ulfar Erlingsson 2011-10-05 09:17:30 PDT
My Chrome extension runs with CSP, and I'm getting "Refused to apply inline style because of Content-Security-Policy."  This is Chrome 14.0.835.186, webkit 535.1.

Everything is safe, so no errors should be being generated.

The culprit is the compound padding initializer I'm using (see below).  What is strange is that the error doesn't get generated unless I do a cloneNode, by uncommenting the last two lines in the snippet below.  Doing the initial initialization works just fine, without generating any error.

Probably the cloneNode goes through the same code path that the parser goes though when making new style objects.  But there should be a flag or something to indicate that the source comes from already-CSP-approved data.

  var legendDiv = document.createElement('div');                                                                                                                                     
  legendDiv.style.padding= '5px 5px 5px 5px';                                                                                                                                        
  document.body.appendChild(legendDiv);                                                                                                                                              
//  var legendDiv2 = legendDiv.cloneNode(true);                                                                                                                                      
//  document.body.appendChild(legendDiv2);
Comment 1 Adam Barth 2011-10-13 12:45:50 PDT
Will investigate.
Comment 2 Adam Barth 2011-10-13 14:23:58 PDT
Repro:

<meta http-equiv="X-WebKit-CSP" content="default-src 'none'; script-src 'unsafe-inline'">
<body>
<script>
var legendDiv = document.createElement('div');
legendDiv.style.padding= '5px 5px 5px 5px';
document.body.appendChild(legendDiv);
var legendDiv2 = legendDiv.cloneNode(true);
document.body.appendChild(legendDiv2);
</script>
Comment 3 Adam Barth 2011-10-13 14:44:19 PDT
This also triggers the check:

var legendDiv = document.createElement('div');
legendDiv.setAttribute('style', 'padding: 5px 5px 5px 5px');
Comment 4 Adam Barth 2011-10-13 14:50:25 PDT
So, our behavior here is actually correct.

We allow setting style information via CSSOM under the theory that doing so isn't using any "inline" style, but we forbid setting the "style" attribute via the DOM, for much the same reason that we don't allow you to load scripts that violate CSP via the DOM.

The question, then, boils down to whether we should block style attributes created via cloneNode.  IMHO, cloneNode is part of the DOM, so we should block it, just the way we'd block setting the style attribute via walking the attribute Node tree.  (It's certainly not CSSOM.)

If Firefox doesn't block cloneNode, we should probably ask them to block it as well.

Thanks for the report.  Hopefully this doesn't cause too much of a problem for you.  Depending on what you're doing, you might consider using an external stylesheet and then using class names to alter the presentation of your DOM rather than using CSSOM.
Comment 5 Ulfar Erlingsson 2011-10-13 17:06:20 PDT
I'd already done something like your proposed workaround a few days ago.

The implication is that CSP works as outlined below:
1) CSP requires you to define all styles in a separate, static CSS file.
2) There is a slight exception for (1), if you are setting styles from static, CSP-approved JavaScript code.
3) Relying on (2) will not always work (e.g. for cloneNode) so you're better off coding as if only (1) was true.

I didn't understand that CSP worked this way. It seems worth communicating that clearly, to avoid confusion, and to steer people to just coding as if only (1) was true.
Comment 6 Adam Barth 2011-10-13 17:09:50 PDT
Yeah, there's an argument that we should block CSSOM too.
Comment 7 Adam Barth 2011-10-13 17:19:21 PDT
BTW, the distinction between the two is that one invokes the CSS parser, whereas the other doesn't.  That's roughly how we distinguish the unsafe-eval cases too: if some code invokes the JavaScript parser, then that code is considered equivalent to eval.