Never Trust Your Input – A WordPress Case

 Although this post isn’t about Security, the title still holds true about everything you do with input, but whatever you do, never trust it. :)

While I was manually editting the last post about SQL I encountered a bug in WordPress. This is not a big deal, probably because it’s not a security bug, but it’s really annoying when the browser freezes while you’re trying to edit your post. So I switched to FireFox and the same bug happened again. In the beginning I thought something was wrong in the internals of the browsers, but both browsers have the same internal bug? That doesn’t make much sense. Looking at the Task Manager I saw that both IE and FF chew up memory and CPU at 50% (this is because I have two cores, otherwise it would be 100% on a single processor…). So immediately I understood that there’s an infinite loop running, hence the 50% CPU usage and it allocates memory in a way (eventually by strings). Next thing I did was to isolate the code of WordPress somehow, I wasn’t even sure what caused this bug to surface in the beginning. All I knew was that it has something to do with my post. Therefore I needed to take a look at my raw post’s text, since it contained some HTML tags. So eventually I saw that I had an unbalanced PRE tag. Unbalanced means that I add an opener tag but didn’t close it. So left only a “<pre>” in my post and saw that the browsers freeze. Now what? Digging into WordPress code I understood there is a special class for a textarea input. I realized I have to search for a “pre” string in the JS files (which originated from .php files). And eventually after a few trials and errors of uncommenting code I found this chunk:

var startPos = -1;
while ((startPos = content.indexOf(‘<pre’, startPos+1)) != -1) {
    var endPos = content.indexOf(‘</pre>’, startPos+1);
    var innerPos = content.indexOf(‘>’, startPos+1);
    var chunkBefore = content.substring(0, innerPos);
    var chunkAfter = content.substring(endPos);
    var innards = content.substring(innerPos, endPos);

   innards = innards.replace(/\n/g, ‘<br />’);
   content = chunkBefore + innards + chunkAfter;
  }

This is ripped from the tiny_mce_gzip.php file. The ‘content’ variable holds the text of my post, which is “<pre>”. Now notice the first line in the block:

var endPos = content.indexOf(‘</pre>’, startPos+1);

Which renders endPos to be -1, since there’s no close tag. And more over, there is no check for the return value, the programmer assumed it will always find a match. :(
Now let’s analyze the block to see why it becomes an infinite loop that chews up memory:

endPos = -1, innerPos = 4, chunkBefore = “<pre”, chunkAfter = “<pre>”, innards = “<pre>”;

Notice that ‘innards’ contain the whole content, since evaluating a substring with an input of -1 returns the input untouched… We can ignore the replace, which doesn’t really affect the loop in any way here. And be hold, ‘content’ is being reassigned to hold the whole new string but now it looks like: “<pre<pre><pre>”.

And the loop stop condition of ‘startPos’ returns true and again endPos gets -1… And bam, you’re browser is frozen.

The fix is pretty straight forward. It’s a shame they have a stupid bug like this. What I had to do at my end was to use phpMyAdmin to edit the SQL tables and change the post so it won’t lock my browser yet again. Although I could have fixed this bug on the server, for some reason I didn’t do it…

Anyway I sent an email to WordPress and hopefully they will fix it immediately, though it’s nothing urgent.

Leave a Reply