DOJO Challenge #22 Winners!

April 7, 2023

DOM XSS Clobbering challenge

The #22th DOJO CHALLENGE, Butters Adventure v2 aims to exploit a DOM vulnerability using a clobbering technique to overwrite the JavaScript function getElementById().

💡 You want to create your own DOJO and publish it? Send us a message on Twitter!


We are glad to announce the #22 DOJO Challenge winners list.


  • The best write-ups reports were submitted by: Scttpr, CharlB and hamzaavvan! Congrats 🥳

The swag is on its way! 🎁

Subscribe to our Twitter and/or Linkedin feeds to be notified of the upcoming challenges.

Read on to find the best write-up as well as the challenge author’s recommendations.

The challenge

Butters Adventure v2

See the challenge page >

We asked you to produce a qualified write-up report explaining the logic allowing such exploitation. This write-up serves two purposes:

  • Ensure no copy-paste would occur.
  • Determine the contestant ability to properly describe a vulnerability and its vectors inside a professionally redacted report. This capacity gives us invaluable hints on your own, unique, talent as a bug hunter.


We would like to thank everyone who participated. The #22 DOJO challenge provided us with a large amount of high quality reports and everyone did a great job!

We had to make a selection of the best ones. These challenges allow to see that there are almost as many different solutions… as long as there is creativity! 😉

Thanks again for all your submissions and thanks for playing with us!

Scttpr‘s Write-Up

————– START OF Scttpr‘s REPORT ——————

Dojo #22 is vulnerable to DOM clobbering. DOM clobbering is an HTML injection into a page to manipulate its DOM.

The term clobbering comes from the fact that you are “clobbering” a global variable or property of an object and overwriting it with a DOM node or HTML collection instead thus leading to undesired behavior.

When creating the DOM tree, browsers create an attribute for named HTML elements on window and document objects. Named HTML elements are those having an id or name attribute:

<form id="dummyForm"></form>

Browser will here create a property dummyForm in window and document objects thus overriding a possible value for a possible dummyForm global variable.

Only certain elements can use the name attribute to clobber globals, they are: embed, form, iframe, image, img and object.

Clobbering can go deeper with chained attributes but our vulnerability fits to this first behavior.


In this dojo context it is only possible to inject HTML into the value attribute of the inpt input.

This HTML page starts by an HTML body containing some text, an empty pre tag with the id out and a form :

<form id="del" action="#delete">
  <input name="inpt" value="$input"></input>

Then it has a script tag with a try/catch. The risk here is to throw an exception and crash the system in the mishandled catch block. To crash Javascript, we have this only condition:

if ( document.getElementById("del") ) {
  var out = document.getElementById("out")
  out.innerText = "Butters you're grounded!"

This code could crash from at least 2 different points:

  • document does not embed a getElementById function
  • document does not retrieve an HTML element with the out id thus crashes on innerText assignment.

As we are in an HTML injection potential context and with few possibilities to execute Javascript (only with a javascript:script url alike attribute in the HTML. It is highly probable that the first point is the right one as deleting a DOM element will be hardly possible without Javascript.

Then we try to find a way to clobber HTML to override getElementById native function.

As described in the description section, getElementById is a document property, we can try to clobber it with a clobberable tag and a name attribute :

<img name="getElementById">

In order to fit the context and escape unwanted characters, the full payload is:

"></input><img name="getElementById"><input value="

If Javascript crashes it should trigger the catch block:

catch (e) {
  alert("Jippiii, You solved it!!")
  alert("How? -> "+ e)

Thus displaying the error in the second alert. In our case it should throw a TypeError because document.getElementById should not be a function anymore:

How? -> TypeError: document.getElementById is not a function


<span><b id="user" style="color:red">butters@vr</b>:<b style="color:#00BFFF">~</b>$ <b id="cmd">./</b></span>
<pre id="out"></pre>
  <form id="del" action="#delete">
    <input name="inpt" value=""></input><img name="getElementById"><input value=""></input>
try {
  //You probably have an HTML injection, whatever...
  if ( document.getElementById("del") ) {
    var out = document.getElementById("out")
    out.innerText = "Butters you're grounded!"
} catch (e) {
  alert("Jippiii, You solved it!!")
  alert("How? -> "+ e)
  //System is crashing!!

<!-- [The code below is design & popup feature once you solve it *only*. It's not a part of the challenge] -->
<img src="">
<img src="">
/*Design CSS...*/


The risk here is to crash the application. In other contexts it can lead to different unwanted behavior depending on the application code implementation.


According to OWASP cheatsheet on this topic there are 3 mitigation techniques:

  • HTML sanitization where OWASP recommends to use DOMPurify or the Sanitizer API
  • Content-Security-Policy to restrict possible Javascript files execution to avoid malicious code to be executed. Warning: CSP can only mitigate some varints of DOM clobbering attacks, such as when attackers attempt to load new scripts by clobbering script sources, but not when already-present code can be abused for code execution. It is not useful in our case.
  • Freeze DOM Objects to prevent overriding by named DOM elements. This method is painful due to the need to identify each concerned node.

OWASP recommends as well secure code guidelines, quickly listed here:

  • Validate all inputs to DOM tree (linked to sanitization)
  • Use explicit variable declarations, especially the ‘new’ let and const which have cleaner scope behavior
  • Do not manipulate Window and Document global variables
  • Do not trust Document APIs before validation
  • Enforce type checking with instanceof and typeof
  • Use strict mode
  • Apply browser feature detection
  • Limit variable scope
  • Use unique variables names
  • Use encapsulation pattern

————– END OF Scttpr‘s REPORT ——————