šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

XSS in React: Where the Automatic Protection Ends

Understand Cross-Site Scripting (XSS) in React: automatic text escaping, its limits, and the javascript: URL attack vector.

⚔ Total XP: 0|šŸ’» react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

XSS fundamentals.

Quick Quiz //

What does React automatically escape by default?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Cross-Site Scripting lets an attacker's JavaScript run inside your page under your site's identity. React's automatic JSX text escaping neutralizes most of this by default — but not all of it. This lesson covers exactly where that protection applies and where it doesn't.

1What Cross-Site Scripting Actually Does

Cross-Site Scripting happens when an attacker gets their own JavaScript to execute inside a page, in a victim's browser, under that site's identity — able to steal cookies, submit forms as the victim, or read page content. It remains one of the most common and dangerous web vulnerabilities.

2React Escapes Text by Default

JSX expressions rendered as text content are automatically HTML-escaped by React. A string containing <script> tags renders as literal, visible text rather than an executable script tag, neutralizing the most common form of injected script without any special handling.

3Where React's Protection Doesn't Reach

React's automatic escaping covers {expression} text content specifically — it does not protect dangerouslySetInnerHTML, a href or src attribute set to a javascript: URL, or data passed unsanitized into a third-party library that renders raw HTML. Knowing these exact boundaries is essential to staying safe.

4The javascript: URL Attack

A link's href set to a user-supplied string can contain a javascript: protocol value instead of a real URL, executing arbitrary code when clicked. Always validate that user-supplied URLs start with an expected protocol before rendering them into href or src attributes.

5Step-by-Step Breakdown

What Cross-Site Scripting Actually Does. Cross-Site Scripting (XSS) happens when an attacker gets their own JavaScript to run inside your page, in your user's browser, under your site's identity — able to steal cookies, submit forms as the victim, or read anything on the page. It's one of the most common and dangerous web vulnerabilities.

React Escapes Text by Default. This is the single most important security fact about React: {expression} in JSX is automatically HTML-escaped. If a value contains <script>, React renders it as the literal text <script> on the page — not as a real script tag — completely neutralizing the attack without you doing anything special.

If a comment string containing <script>alert('hacked')</script> is rendered with <p>{comment}</p>, what happens?

  • →It's escaped and displayed as literal, harmless text — the script never executes
  • →The script tag actually executes, triggering the alert

Where React's Protection Doesn't Reach. React's automatic escaping applies to {expression} text content — it does NOT protect dangerouslySetInnerHTML, a href/src attribute set to a javascript: URL, or data passed unsanitized into a third-party library that renders raw HTML. Knowing exactly where the safety net ends is what keeps you safe.

The javascript: URL Attack. A link's href set to a user-supplied string can contain javascript:alert(document.cookie) instead of a real URL — clicking it executes that code. Always validate that user-supplied URLs start with an expected protocol (https://, mailto:) before rendering them into href or src.

Why is <a href={userSuppliedUrl}> a potential XSS risk, even though {userSuppliedUrl} looks like it's inside a protected JSX expression?

  • →React's text escaping doesn't prevent a malicious javascript: protocol value from being executed on click
  • →This is actually a JSX syntax error that would fail to compile

Mastery Achieved. You now understand XSS in React: what the attack actually accomplishes, why React's automatic text escaping neutralizes most of it by default, and the specific gaps — dangerouslySetInnerHTML and unvalidated URLs — where that protection doesn't reach. Next, you'll go deeper into safe rendering practices generally.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

XSS protection depends on application code, not browser-specific behavior.

FirefoxSupported

Same protections and risks apply.

SafariSupported

Same protections and risks apply.

EdgeSupported

Same protections and risks apply.

Accessibility (A11y)

1Security and Accessibility Reviews Often Touch the Same Risky Patterns

Components using dangerouslySetInnerHTML or custom URL handling deserve both a security review and an accessibility review, since unsanitized or malformed injected content can also break screen reader parsing.

SEO Implications

  • 1

    A Successful XSS Attack Can Lead to Search Engine Blocklisting

    If an attacker uses an XSS vulnerability to inject malicious content or redirects, search engines can flag and blocklist the affected domain, causing severe and lasting SEO damage beyond the immediate security incident.

Best Practices

Default to Plain JSX Expressions for Any User-Supplied Text

Rendering user content with {content} inside JSX gets automatic escaping for free — never manually construct HTML strings from user input for text display.

Validate URL Protocols Before Rendering User-Supplied Links

Check that a user-supplied URL starts with an expected protocol (https://, mailto:) and reject or sanitize anything else, including javascript: and data: URLs, before using it in href or src.

Frequent Bugs

THE BUG

A user-supplied profile link executes arbitrary JavaScript when clicked instead of navigating anywhere.

THE FIX

The href value wasn't validated and contained a javascript: protocol payload. Validate that user-supplied URLs match an expected protocol allowlist before rendering them into href.

THE BUG

Developers assume rendering data with {value} inside JSX is unsafe and manually escape it themselves, adding unnecessary complexity.

THE FIX

This is unnecessary — React already automatically escapes JSX expression text content. Manual escaping on top of React's built-in behavior is redundant and can sometimes cause double-escaping display bugs.

Real-World Examples

Validating a User-Supplied Website Link on a Profile Page

A user profile page lets users add a personal website link, rendered as a clickable <a> tag. Without validation, a malicious user could set their 'website' field to a javascript: URL, which would execute when another user clicked their profile link. Validating the URL's protocol against an allowlist before rendering it into href closes this gap.

function isSafeUrl(url) {
  try {
    const parsed = new URL(url);
    return ['http:', 'https:', 'mailto:'].includes(parsed.protocol);
  } catch {
    return false;
  }
}

<a href={isSafeUrl(user.website) ? user.website : '#'}>{user.website}</a>

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Rendering a user-supplied URL into href without validating its protocol

function isSafeUrl(url) { try { return ['http:', 'https:'].includes(new URL(url).protocol); } catch { return false; } } <a href={isSafeUrl(link) ? link : '#'}>{link}</a>

The Solution //

Parse the URL and check its protocol against an explicit allowlist (http:, https:, mailto:) before rendering it, rejecting anything else including javascript: and data: URLs.

The Error //

Assuming a value is safe simply because it came from your own database

// Still needs the same care, even if it's "your own" data <p>{commentFromDatabase}</p> // safe because JSX escapes it, not because of its source

The Solution //

Data stored in your own database can still contain malicious content if it originated from unsanitized user input at some earlier point — apply the same escaping and validation principles regardless of where data was previously stored.

Lesson Glossary

[01]XSS (Cross-Site Scripting)

An attack where an attacker's JavaScript executes inside a page under that site's own identity.

Code Preview
<script>steal(document.cookie)</script>

[02]Automatic Escaping

React's default behavior of rendering JSX expression text as literal, HTML-escaped content.

Code Preview
<p>{userInput}</p> // always escaped

[03]javascript: URL

A URL protocol that executes JavaScript when navigated to or clicked, a common XSS vector.

Code Preview
href="javascript:alert(1)"

[04]URL Validation

Checking that a user-supplied URL matches an expected protocol before rendering it as a link.

Code Preview
['http:', 'https:'].includes(url.protocol)

Continue Learning