

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: Cross-Site Scripting (XSS)
incomplete
2: Fix Cross-Site Scripting
incomplete
3: Cross-Site Request Forgery (CSRF)
incomplete
4: CSRF Tokens
incomplete
5: Content Security Policy
incomplete
6: Legitimate Inline Scripts
incomplete
7: Sandboxing 'iframe' Elements
incomplete
8: Clickjacking
incomplete
9: Same-Origin and Referrer Policies
incomplete
10: Cross-Origin Resource Sharing
incomplete
11: CORS in Express
incomplete
12: Helmet
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
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, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
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.
The three common variants differ in how the untrusted value reaches the vulnerable renderer:
Bearly Secure reflects the search query into both page text and an HTML attribute. Escape it before rendering.
">
<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.