I reckon it is pretty safe to mitigate XSS by enforcing no letters/special symbols right after the < bracket. As specified in the HTML spec, the tag name should follow the < to form a valid html element. Is the simple solution able to mitigate XSS?

Assuming create html element is needed in our attack.


This is safe under two assumptions:

  1. Browsers actually follow the spec.
  2. You only insert untrusted data between tags.

As for #1, I tried recent versions of IE, Chrome and Firefox and they all seem to follow it. But back in the day browsers were very forgiving creatures, so there might be old ones around who would kindly assume you mean <script> and not < script>.

As for #2, it is important to remember that XSS is context dependent. Assuming that cleaned() is an implementaiton of your scheme, the following would be safe:

<div><?= cleaned(userdata); ?></div>                         <!-- Between tags. -->

But e.g. the following would not be safe:

<input value="<?= cleaned(userdata); ?>">                    <!-- Inside attribute. -->
<script> let x = "<?= cleaned(userdata); ?>"; </script>      <!-- Inside script. -->
<style> a { color: <?= cleaned(userdata); ?>; } </style>     <!-- Inside style. -->

As always, I recommend the OWASP XSS prevention cheat sheet.

Edit: You say no letters. As per this answer you probably don't want to allow <!, </ or <? either, since they could be used to start comments and close tags. Might not lead to XSS, but could still mess up your page with unexpected consequences.