We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Fix Cross-Site Scripting

The safest default is a template engine with automatic output escaping. If you build HTML strings directly, every untrusted value needs to be encoded before interpolation:

export function escapeHtml(value: string): string {
  return value
    .replace(/&/g, "&")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

This simple function works for HTML text and quoted values in ordinary attributes, but it does not make attacker-controlled attribute names, event handlers, CSS, JavaScript, or URLs safe. Those contexts need their own defenses.

On the client side, prefer textContent over innerHTML whenever you're writing plain text to the DOM:

output.textContent = userInput;

The textContent property can't turn its value into active markup. You should only use innerHTML when you actually need HTML and the value has been sanitized with a maintained library like DOMPurify.

XSS Variants

The three common variants differ in how the untrusted value reaches the vulnerable renderer:

  • Reflected XSS: request input is immediately reflected into the response, like a search query shown above its results.
  • Stored XSS: input is saved and rendered later, like a product review or profile bio.
  • DOM-based XSS: client-side JavaScript reads an untrusted value and writes it into the page through an unsafe DOM API.

Assignment

Bearly Secure reflects the search query into both page text and an HTML attribute. Escape it before rendering.

  1. ">
    <script>
      document.body.insertAdjacentHTML(
        "afterbegin",
        '<p style="background: #b91c1c; color: black; padding: 1rem">Search XSS executed</p>',
      );
    </script>
    

    Two red Search XSS executed banners should appear.

With Bearly Secure still running, run and submit the CLI tests from the project root.