CSS Tricks

CSS Tricks

October 1, 2020

CSS Tricks #

CSS can be used to trick a user into exposing information such as embedded pixel values by making visual changes that are affected by the embed.

Retrieving user’s history #

Using the CSS :visited selector, it’s possible to apply a different style for URLs that have been visited.
Previously it was possible to use getComputedStyle() to detect this difference, but now browsers prevent this by always returning values as if the link was visited and limiting what styles can be applied using the selector. 1
So, it may be needed to trick the user into clicking an area that the CSS has affected. This can be done using mix-blend-mode. 2
There are also ways to do it without user interaction such as by abusing render timings. This works because it takes time to paint links in a different color. 3
A Proof of Concept to this attack can be found in a Chromium report 4 and it works by having multiple links to increase the time difference.

info

This issue has been known for years and there are multiple open bugs to be fixed in multiple browsers 1 2 3. There are also publicily available proof of concepts, e.g. Whack a mole game 4 that requires user interaction for a successful leak.


  1. Issue 712246: Security: CSS :visited with mix-blend-mode can leak browser history, link ↩︎

  2. Issue 713521: Eliminate :visited privacy issues once and for all, link ↩︎

  3. :visited support allows queries into global history, link ↩︎

  4. Whack a mole game, link ↩︎

Leaking status code #

Tricks to reveal a user’s history provide a way to detect the status code of a response cross-site. Chromium-based browsers will only save responses with OK status codes (e.g. 200) to the user’s history, but won’t add error status codes (e.g. 404). By visiting the target URL in a popup window, it will then either be saved to the history or not depending on the status code. After then placing the same URL on your page with <a href="...">, it is possible to use one of the manual or automatic techniques described above to leak whether this URL was saved to the history or not.

In some XS-Search scenarios, a search with no results will return a 404 error. Cookies marked SameSite=Lax will be sent in popup windows, and this technique allows such scenarios to be exploited. 5

Evil Captcha #

Using CSS, it’s possible to take an embed out of context.
An example of this is pretending it’s a captcha as seen in 6
This works by setting the width and height of an embed so that only the target characters are shown, this may use multiple embeds to change the order of the characters being displayed so that its harder for a user to know what information they’re providing.

Abusing autocomplete #

If a website uses text inputs and does not opt-out of autocomplete using autocomplete="off" it may be possible to leak data such as email addresses by tricking the user into pressing the keys to navigate the autocomplete UI for a javascript focused text input. For Chrome, this requires the user to be tricked into pressing the Up or Down arrow key which opens the dialog and selects a value, then by pressing Enter or Tab the value gets inserted into the page.

let input = document.createElement("input");
input.type = "email";
input.autocomplete = "email";
input.name = "email";
input.size = "1";
input.style = "position:absolute;right:-500px;bottom:-21.9px";
input.onkeypress = e => {
    e.preventDefault();
}
window.onmousedown = e => {
    // ignore mouse clicks
    e.preventDefault();
}
input.onchange = e => {
    alert(e.srcElement.value);
    e.srcElement.value = "";
}
document.body.appendChild(input);
setInterval(() => {
    input.focus({preventScroll: true});
}, 1000);

Custom cursor #

A custom cursor might not leak data directly but it may help trick the user, as a large cursor may overlay the autocomplete dialog and other native UI.

<style>
:root {
  cursor: url('https://www.google.com/favicon.ico'), auto;
}
</style>

Defense #

XFO prevents embeds from being attacked because there’s no visual difference as the content does not get shown. The Retrieving user’s history attack can only be prevented by the user. This can be done by disabling the browser history, or if on Firefox, by setting the option layout.css.visited_links_enabled to false in about:config panel.

SameSite Cookies (Lax)COOPFraming ProtectionsIsolation Policies
✔️

References #


  1. Privacy and the :visited selector, link ↩︎

  2. CSS mix-blend-mode is bad for your browsing history, link ↩︎

  3. Pixel Perfect Timing Attacks with HTML5, link ↩︎

  4. Visited links can be detected via redraw timing, link ↩︎

  5. XS-Leaking flags with CSS: A CTFd 0day, link ↩︎

  6. The Human Side Channel, link ↩︎