Finding Security Problems
20 minIntermediateHTML · CSS · JS
In this lesson
- ▸Explain how inserting user input with
innerHTMLenables cross-site scripting (XSS), and render it safely - ▸Know that everything sent to the browser is public, including "hidden" keys
- ▸Validate on the server, because client-side checks can be skipped
The big idea
Generated code is optimised to work for the person who asked. Security is about what happens when someone else uses it on purpose in a way you didn't intend.
The guestbook in the editor works perfectly for honest visitors. Now think like a dishonest one. This lesson covers three problems that show up again and again in generated web code. It's a starting point, not a full security course.
1. User input + innerHTML = XSS
innerHTML parses a string as HTML. If that string contains what a visitor typed, the visitor is writing your page's HTML. A message like <img src=x onerror="…"> becomes a real image whose onerror runs their JavaScript in other visitors' browsers — that's cross-site scripting (XSS). It can read what the page shows, act as the logged-in user, or redirect them.
What the assistant wrote
list.innerHTML += `<li><strong>${name}</strong>: ${message}</li>`;What a reviewer ships
const li = document.createElement("li");
const strong = document.createElement("strong");
strong.textContent = name; // text, never parsed as HTML
li.append(strong, ": " + message); // strings become text nodes
list.appendChild(li);textContent, append("…") and createTextNode treat input as text. React escapes text in JSX the same way — but dangerouslySetInnerHTML brings the problem back.
2. Secrets in frontend code
Every file the browser downloads can be read by anyone: View Source, DevTools, or just fetching your JavaScript bundle. A secret key in frontend code is a published key. It must live on a server (loaded from an environment variable, with .env files kept out of git), and the browser should only receive the result of using it. If a real key has ever been shipped or committed, rotate it.
Some providers issue keys that are designed to be public (often called publishable or client keys) with limited permissions. Check the provider's documentation — and if a key is called "secret", it never belongs in the browser.
3. Trusting client-side validation
maxlength="140" and an if in the submit handler are good for user experience. They are not security: an attacker can edit the page in DevTools, or skip your page entirely and call the API with a tool like curl. The server must check every input as if no form existed.
Asking for a security review
It's worth asking an assistant: "Review this for XSS, exposed secrets, missing server-side validation and authorisation checks. Point to exact lines." Treat the answer as leads to verify, not a clean bill of health — and never paste real secrets while asking.
Post a comment with this message and watch what appears:
<img src=x onerror="document.body.style.background='red'">
Then fix the submit handler in script.js so names and messages are always shown as text: build the <li> with createElement and textContent (or append) instead of innerHTML.
Checks
- HTML typed by a visitor doesn't become real elements
- Normal comments still appear
Check understanding
What you learned
- ✓Render user input with
textContent/createElement, never by building HTML strings forinnerHTML. - ✓Everything in frontend code is public. Secrets live on the server; leaked keys get rotated.
- ✓Client-side validation is UX; server-side validation is security.
Console output from your code appears here.