MiddleWeb

What is XSS, and how do you render user-written Markdown without opening the door to it?

The interviewer wants to know whether you understand XSS as untrusted content being run by the browser as code, and whether you know the places it gets in from, rather than only having memorized the name.

XSS (cross-site scripting) happens when user data is put into a page in a way the browser reads as HTML or code instead of as text. The attacker can then run code in your page, with the permissions of the person viewing it: read cookies, call APIs on their behalf, change what the page shows.

With Markdown, the main risk comes from three places:

  1. Raw HTML. Markdown allows HTML, so libraries pass it through to the output verbatim, including tags like <img onerror=...>. A <script> tag inserted through innerHTML doesn't run, but many other tricks still do.
  2. Links and images with dangerous protocols. [see](javascript:...) runs code when clicked.
  3. A misconfigured filter. An allow-list that is too wide, or a hand-written regex filter, is very easy to bypass.

There are two approaches worth mentioning. The first is to convert Markdown to HTML and then filter it with a dedicated sanitize library using an allow-list (DOMPurify, sanitize-html), keeping only the tags and attributes you need. The second is not to produce an HTML string at all: parse the Markdown into typed blocks and build the page with a framework like React, where text is set as the content of an element and so is escaped automatically. With the second approach you still have to check the addresses of links and images yourself, accepting only http, https and paths inside the site.

An important point to make: don't use dangerouslySetInnerHTML (or innerHTML) for content that hasn't been filtered, and every path that puts content on a page, including the preview box in an admin page, has to go through the same safe processing.

Bonus points: mention Content Security Policy as a second line of defense that limits where code may run, and note that a safety condition deserves a test, for example tests for javascript: and data: addresses.