I came across an cross-site scripting (XSS) exploit in some React components in our codebase. This was surprising because I used to think that the only way to do dangerous stuff in React was the obvious “dangerouslySetInnerHTML
”. But, I was wrong.
React doesn’t escape or sanitize “href” props in URLs. If you allow a user to create custom URLs on your website somehow, there’s a high chance your website can be exploited like this. Let’s say you have a field on your website for your user’s blog. The user can enter a link to their blog and you show it on the user’s profile page on your site. The code could look like this:
const UserBlogLink = (link) => {
return (
<a href={link}>Blog</a>
);
}
This component is not safe from XSS. React doesn’t do any sanitization of the “href” prop here. A user could put in “javascript:alert(0)”
or something worse as their blog and your website would execute it.
So how do we avoid these bugs? Well, the first thing you want is a good CSP policy. Things like these pop up every once in a while. While you can try to avoid XSS bugs by trying to safely render and validate all data, it’s nice to have defense in depth in case something does get missed (which it will). Then, the only way to fix this specific bug is to validate that the url is an actual HTTPS or HTTP link, not Javascript. Vue and Angular do this for you out of the box.