<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bramus!</title>
    <description>The latest articles on DEV Community by Bramus! (@bramus).</description>
    <link>https://dev.to/bramus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3652%2Fd928f553-b03a-4a83-8200-7a1f5acce123.jpg</url>
      <title>DEV Community: Bramus!</title>
      <link>https://dev.to/bramus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bramus"/>
    <language>en</language>
    <item>
      <title>Injecting a JavaScript Attack Vector using CSS Custom Properties</title>
      <dc:creator>Bramus!</dc:creator>
      <pubDate>Wed, 23 Dec 2020 12:08:46 +0000</pubDate>
      <link>https://dev.to/bramus/injecting-a-javascript-attack-vector-using-css-custom-properties-133k</link>
      <guid>https://dev.to/bramus/injecting-a-javascript-attack-vector-using-css-custom-properties-133k</guid>
      <description>&lt;p&gt;Earlier this week I saw this tweet by @Sansec float by:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1336614850047381506-425" src="https://platform.twitter.com/embed/Tweet.html?id=1336614850047381506"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1336614850047381506-425');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1336614850047381506&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;This one is pretty nice I must say, and a bit hard to find: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;As &lt;a href="https://www.bram.us/2020/12/09/what-values-can-you-put-in-css-custom-property/" rel="noopener noreferrer"&gt;the syntax for CSS Custom Properties is overly permissive&lt;/a&gt; you can use Custom Properties to store your JavaScript attack vector in.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'Attack!'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you then &lt;a href="https://www.bram.us/2020/03/30/pass-data-from-css-to-javascript-with-css-variables/" rel="noopener noreferrer"&gt;use &lt;code&gt;window.getComputedStyle&lt;/code&gt; to extract the contents out of the Custom Property&lt;/a&gt; and combine it with a function constructor and an IIFE, it’s possible to execute it.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scriptContents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;getPropertyValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scriptContents&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Here’s a pen that loads a remote confetti script using the method described:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/bramus/embed/ZEpJVee?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;To prevent this remote evaluation, you'll need a proper &lt;a href="https://developers.google.com/web/fundamentals/security/csp" rel="noopener noreferrer"&gt;Content Security Policy&lt;/a&gt; to do so. It took me some time to figure out — as I’m no CSP expert — but turns out the &lt;code&gt;unsafe-inline&lt;/code&gt; keyword in the CSP’s source list is enough to block the execution of the JS-IN-CSS.&lt;/p&gt;

&lt;p&gt;As a reminder, &lt;a href="https://developers.google.com/web/fundamentals/security/csp#implementation_details" rel="noopener noreferrer"&gt;here&lt;/a&gt; are the four allowed keywords:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;'none'&lt;/code&gt;&lt;/strong&gt;, as you might expect, matches nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;'self'&lt;/code&gt;&lt;/strong&gt; matches the current origin, but not its subdomains.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;'unsafe-inline'&lt;/code&gt;&lt;/strong&gt; allows inline JavaScript and CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;'unsafe-eval'&lt;/code&gt;&lt;/strong&gt; allows text-to-JavaScript mechanisms like eval.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I first thought &lt;code&gt;unsafe-inline&lt;/code&gt; would be insufficient here as the code does not call eval, but apparently a function constructor is &lt;em&gt;(correctly!)&lt;/em&gt; considered equally harmful, and therefore also blocked.&lt;/p&gt;

&lt;p&gt;Here’s an updated demo that blocks the script evaluation:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/bramus/embed/WNGZdjb?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The CSP used is this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt;
  &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;
  &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"script-src 
    https://cpwebassets.codepen.io
    https://cdpn.io
    https://cdn.jsdelivr.net
    'unsafe-inline'
  ;"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://cpwebassets.codepen.io&lt;/code&gt; and &lt;code&gt;https://cdpn.io&lt;/code&gt; are there for the CodePen demo to work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;https://cdn.jsdelivr.net&lt;/code&gt; is there to allow legitimate loading of scripts — such as a jQuery you might need — from that CDN.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unsafe-inline&lt;/code&gt; is the one that prevents the execution of the JS-IN-CSS defined script by blocking the call to the function constructor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that calls for confetti! 🤪&lt;/p&gt;




&lt;p&gt;&lt;em&gt;💁‍♂️ This post &lt;a href="https://www.bram.us/2020/12/22/injecting-a-javascript-attack-vector-using-css-custom-properties/" rel="noopener noreferrer"&gt;first appeared on my blog bram.us&lt;/a&gt;. Want to stay in the loop? Here's how to do so:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://twitter.com/bramus" rel="noopener noreferrer"&gt;Follow @bramus on Twitter&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://twitter.com/bramusblog" rel="noopener noreferrer"&gt;Follow @bramusblog on Twitter&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://bram.us/rss" rel="noopener noreferrer"&gt;Follow bram.us using RSS&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>customproperties</category>
      <category>javascript</category>
      <category>csp</category>
    </item>
  </channel>
</rss>
