(Self) XSS at Mozilla's internal Phonebook

This is a short summary about a goofy XSS/CSRF exploit on an internal web page at Mozilla.

A few weeks ago I discovered that our "phonebook" supports a limited wiki-syntax in the profile descriptions (i.e. [link text http://example.com]). Despite proper sanitizing to forbid all markup injections into HTML tags and attributes it allowed linking to javascript URLs. Liking the rich capabilities that come with JavaScript, I naturally had to insert some script into my profile. So I started with a small script that changes the background color randomly. Like this:

Click me, I dare you

Source:

void(setInterval("document.body.style.backgroundColor='#'+(Math.random()*10e16).toString(16).substr(0,6)",500))

What it does? Well, let's start simple. setInterval(…,500) runs the code supplied in the first argument every 500ms. The code itself is an assignment to the document's background color. So we change it quite often. The rest is a quick way to generate a random six digits hex string, i.e. an RGB color value: Math.random() gives a float with a lot of random digits after the floating point. Multiplying by 10e16 (that is a 10 followed by 16 zeros) makes it a long integer without decimals. toString(16) transforms it into a hex string and substr cuts after six digits. Et violà! void makes sure the code doesn't have a return value, which means that the browser stays on the current web page. I have manually shortened the code to work without spaces, so it does not break the wiki-syntax.

Well that was the first revision. I left it for a while and I guess people clicked on it. I don't know how many, but surely somebody found it. That was part one. I came back to this a few weeks later and had to realize that changing the background color is quite boring. What else can we do? Right. We can try to change other people's profiles.

This is where the fun starts:1

javascript:i=document.createElement("iframe");i.src="edit.php";i.style.display="none";document.body.appendChild(i);void(setTimeout('f=(i.contentDocument.forms[0\x5D);f[atob("bmFtZVtd")\x5D.value+="\x20\uD83D\uDC35";f.submit()',20e2))

Again, this link came with the same "I dare you" text. Let's dissect the source code. First we create an invisible iframe that loads the "Edit Profile" page.

i=document.createElement("iframe");
i.src="edit.php";
i.style.display="none";
document.body.appendChild(i);

Now let's fill out the form and submit. The frame takes some time to load, so we will prepare a piece of source code in a string and defer execution with setTimeout: The code finds the form in the iframe, DOM navigation is quite easy since the input fields have proper name attributes, which exposes them to JavaScript as attributes of the form element. The source code uses atob, \x5D and \x20 so we don't break wiki-syntax. The escape sequence \uD83D\uDC35 is the unicode monkey face 🐵.

payload = 'f=(i.contentDocument.forms[0\x5D);f[atob("bmFtZVtd")\x5D.value+="\x20\uD83D\uDC35";f.submit()'

Once the payload is prepared we just execute it after a certain delay:

void(setTimeout(payload,20e2))

So to recap: If you click this link you will add a monkey face to your name in the background, but it's quite subtle.

So let's search for the monkey face in the phonebook: Search results

At least 12 people have a monkey in their profile 🐵2

This isn't strictly a self-xss as discussed in these three very interesting blog posts (1, 2, 3) but I'd argue that the average Mozillian should be careful enough not to click links that start with javascript: ;)


  1. I have modified a few bits so the exploit doesn't properly apply to the phonebook. Script kiddie protection. 

  2. I swear it was only 11 when I started writing this blog post. Also, modulo a false positive: One person had a monkey in their description before I started this. 


If you find a mistake in this article, you can submit a pull request on GitHub.

Other posts

  1. How Firefox gives special permissions to some domains (Fri 02 February 2024)
  2. Examine Firefox Inter-Process Communication using JavaScript in 2023 (Mon 17 April 2023)
  3. Origins, Sites and other Terminologies (Sat 14 January 2023)
  4. Finding and Fixing DOM-based XSS with Static Analysis (Mon 02 January 2023)
  5. DOM Clobbering (Mon 12 December 2022)
  6. Neue Methoden für Cross-Origin Isolation: Resource, Opener & Embedding Policies mit COOP, COEP, CORP und CORB (Thu 10 November 2022)
  7. Reference Sheet for Principals in Mozilla Code (Mon 03 August 2020)
  8. Hardening Firefox against Injection Attacks – The Technical Details (Tue 07 July 2020)
  9. Understanding Web Security Checks in Firefox (Part 1) (Wed 10 June 2020)
  10. Help Test Firefox's built-in HTML Sanitizer to protect against UXSS bugs (Fri 06 December 2019)
  11. Remote Code Execution in Firefox beyond memory corruptions (Sun 29 September 2019)
  12. XSS in The Digital #ClimateStrike Widget (Mon 23 September 2019)
  13. Chrome switching the XSSAuditor to filter mode re-enables old attack (Fri 10 May 2019)
  14. Challenge Write-up: Subresource Integrity in Service Workers (Sat 25 March 2017)
  15. Finding the SqueezeBox Radio Default SSH Password (Fri 02 September 2016)
  16. New CSP directive to make Subresource Integrity mandatory (`require-sri-for`) (Thu 02 June 2016)
  17. Firefox OS apps and beyond (Tue 12 April 2016)
  18. Teacher's Pinboard Write-up (Wed 02 December 2015)
  19. A CDN that can not XSS you: Using Subresource Integrity (Sun 19 July 2015)
  20. The Twitter Gazebo (Sat 18 July 2015)
  21. German Firefox 1.0 ad (OCR) (Sun 09 November 2014)
  22. My thoughts on Tor appliances (Tue 14 October 2014)
  23. Subresource Integrity (Sun 05 October 2014)
  24. Revoke App Permissions on Firefox OS (Sun 24 August 2014)
  25. (Self) XSS at Mozilla's internal Phonebook (Fri 23 May 2014)
  26. Tales of Python's Encoding (Mon 17 March 2014)
  27. On the X-Frame-Options Security Header (Thu 12 December 2013)
  28. html2dom (Tue 24 September 2013)
  29. Security Review: HTML sanitizer in Thunderbird (Mon 22 July 2013)
  30. Week 29 2013 (Sun 21 July 2013)
  31. The First Post (Tue 16 July 2013)