Is React protected against malicious user inputs?

March 28, 2023


In the React docs, there's this page which has been the source of much confusion over the last few years. Here, React claims that JSX is by default protected against XSS attacks. What does this mean?

What you should understand: React prevents most XSS attacks by default (if used in the standard way). There are still some attack vectors open, but they need you to do something special.

  1. If you use an escape hatch like dangerouslySetInnerHtml, and you try to set user input to this, then you are asking for trouble. If you really need to do this (for eg, you want to show the preview of user provided HTML template), use a library like dom-purify to escape stuff. Note: even dom-purify is not foolproof, so if you really need to do this, I suggest digging into the issues (they have provided a way to escape properly too`).
  2. If you allow user inputs to define arbitary props keys (by spreading user inputs on a component for eg), then they can easily inject a prop like dangerouslySetInnerHtml, and you are open to attacks.
  3. Another case when it might be an issue is when doing server side rendering. You often need to to do a JSON.stringify when doing SSR, and that is open to attacks (because it's outside React). In that case, use a library like serialize-javascript on the server, instead of doing JSON.stringify.
  4. Another issue could occour when you are passing user input directly to an anchor element's href prop, so a user can potentially use something like javascript:alert('123') as a href, which will lead to script execution. If you need to do this, make sure you escape stufff, by doing .replace(/^(javascript\:)/, ""); for eg, (and also check for encoding etc). You would rarely need to do something like this, but if you, it's best to look up more resources here.
  5. This goes without saying, but just leaving it here – don't touch the DOM directly in React, unless you know what you are doing. If you do that, all React XSS gurantees are out the window.

An interesting point to note: Angular does escape all URLs by default, which ensures that dynamically-created URLs are safe to use in the application. React does not do this, so if you are passing user input directly to href, you need to do this yourself.

One solution for the href issue is to use a <SafeLink> component as mentioned in the tweet here:

Further reading: