Earlier this week I saw this tweet by @Sansec float by:
This one is pretty nice I must say, and a bit hard to find:
-
As the syntax for CSS Custom Properties is overly permissive you can use Custom Properties to store your JavaScript attack vector in.
:root { --script: console.log('Attack!'); } -
If you then use
window.getComputedStyleto extract the contents out of the Custom Property and combine it with a function constructor and an IIFE, it’s possible to execute it.
const scriptContents = window.getComputedStyle(document.documentElement)?.getPropertyValue('--script'); new Function(scriptContents)();
Here’s a pen that loads a remote confetti script using the method described:
To prevent this remote evaluation, you'll need a proper Content Security Policy to do so. It took me some time to figure out — as I’m no CSP expert — but turns out the unsafe-inline keyword in the CSP’s source list is enough to block the execution of the JS-IN-CSS.
As a reminder, here are the four allowed keywords:
-
'none', as you might expect, matches nothing. -
'self'matches the current origin, but not its subdomains. -
'unsafe-inline'allows inline JavaScript and CSS. -
'unsafe-eval'allows text-to-JavaScript mechanisms like eval.
I first thought unsafe-inline would be insufficient here as the code does not call eval, but apparently a function constructor is (correctly!) considered equally harmful, and therefore also blocked.
Here’s an updated demo that blocks the script evaluation:
The CSP used is this one:
<meta
http-equiv="Content-Security-Policy"
content="script-src
https://cpwebassets.codepen.io
https://cdpn.io
https://cdn.jsdelivr.net
'unsafe-inline'
;"
>
It works as follows:
-
https://cpwebassets.codepen.ioandhttps://cdpn.ioare there for the CodePen demo to work -
https://cdn.jsdelivr.netis there to allow legitimate loading of scripts — such as a jQuery you might need — from that CDN. -
unsafe-inlineis the one that prevents the execution of the JS-IN-CSS defined script by blocking the call to the function constructor.
Now that calls for confetti! 🤪
💁♂️ This post first appeared on my blog bram.us. Want to stay in the loop? Here's how to do so:
Top comments (1)
I'm not sure if this is intentionally clickbaitey, but there's nothing new or particularly special about this attack vector. If an attacker can inject the code containing the
evalorFunction, they already own your site. The fact the payload happens to be stored in a CSS custom property has nothing to do with it.