What's the most malicious thing you can do with an injected HTML heading element?


A bit of a thought experiment - similar to my Minimum Viable XSS and SVG injection investigations.

I recently found a popular website which echoed back user input. It correctly sanitised < to &lt; to prevent any HTML injection.

Except…

It let through <h2> elements unaltered! Why? I suspect because the output was:

<h2>Your search for ... returned no results</h2>

And, somehow, the parser was getting confused. OK, what can we do with this little vector?

The first thought is to use Javascript event handlers like onclick() or onmouseover() - but they were (sensibly) blocked. The <h2> element only has access to the Global Attributes. So we could inject content which use Right-To-Left text, or add some metadata attributes - but that's not particularly useful.

The most useful Global Attribute is style="". Yup! Good old CSS!

The limitation of the style attribute is that it only applies to the specific element it is attached to. So you can't rewrite the entire page. You also can't use the content: property - as that only applies to ::before and ::after directives.

Using normal CSS, we can change the colour and size of our newly injected <h2>, faff around with the background colour, change the font, and move it about the page. Good for a bit of digital graffiti, but not much else.

Except…

What about using background-image? Using that, we can pull in an external resource.

<h2 style="background-image:url('https://evil.site/whatever.png'); width:512px; height:512px;"> ... </h2>

That will load an external picture on the site. It could be an animated GIF saying "You're a winner! Visit www.... to claim your prize!". It wouldn't be clickable, but might catch a few people out.

It is possible to load an SVG. And SVG can contain JS. But - alas and alack - the JS doesn't run in background mode - even if the JS is bundled as Base64.

Changing the content-disposition of the image won't force the browser to download it, either.

And that, I think, is about the limit of it. If Javascript is blocked, the worst you can do is inject a malicious image. Short of finding a zero-day in a browser's codec, all that can happen is a bit of temporary defacement.

But Wait! There's More!

While fuzzing around with the input, I made an interesting mistake. I mistyped <svg> as <sgv>. That invalid element was added to the page's HTML! That means there's a parser somewhere which is stripping out only the elements it knows about. Browsers typically ignore elements they don't understand - so there's no danger to users there. But it points to the idea that there may be some elements the sanitiser doesn't know about.

And, indeed, there were! For example, it happily took the obsolete <plaintext> element, and dumped it into the markup. Which caused the page to break.

It also, delightfully, took the <marquee> element!

I reported the issue immediately, and got an acknowledgement. But, sadly, after a few months the website was still not fixed.

Take a bow, ACM Digital Library!


Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

3 thoughts on “What's the most malicious thing you can do with an injected HTML heading element?”

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">