Cross-site scripting explained with a comment box

Cross-site scripting is when text a visitor submitted runs as code in other browsers. How a comment becomes an attack, and the two defences.

3 minread 669words last updated

The short answer

A comment box takes text from one visitor and shows it to every later visitor. If the site displays that text exactly as typed, a visitor can type not a comment but a small script, and every browser that loads the page runs it, with full access to the page: what the visitor types, their session, the content they see. That is cross-site scripting, XSS, and comments are only the classic example. Any place a site shows text that came from a user is a candidate.

Two defences stop it: neutralising text when it is displayed, and a policy that blocks scripts from unexpected sources even if one gets through.

How a comment becomes an attack

  1. A visitor submits a comment containing a script instead of words.
  2. The site stores it like any other comment.
  3. Another visitor opens the page. The site inserts the stored comment into the HTML as-is.
  4. That visitor’s browser runs the script, because it cannot tell a script the site wrote from a script a commenter wrote.
  5. The script does what it was written to do: read form fields, steal the session, redirect to a phishing page, quietly send data elsewhere. Under your domain, with your padlock.

Where the risk lives on an ordinary business site

PlaceHow user text reaches the page
Search results”Showing results for …” echoes the search term
Form error pagesThe form re-displays what was entered
Reviews, comments, questionsStored and shown to everyone
Account and profile areasNames and details shown back
URL parametersValues from the address shown in the page
Support and chat transcriptsMessages displayed to staff or other users

The two defences

Escape on output, everywhere. Everything that came from a user is treated as text when displayed. Modern templating does this by default; the review is of the places where the default was overridden. Where formatted input is genuinely needed, a strict allowlist of harmless formatting replaces “trust the input”.

A Content Security Policy. A header that tells the browser which sources scripts may come from, and whether code written straight into the page may run at all. Where the policy does not permit inline code, an injected script from a comment does not run even if the escaping was missed. Where it contains 'unsafe-inline', which is the common case, that safety net is not there. It is the second line under the first defence, and its value depends on that one setting.

What this means for you

Cross-site scripting is not about comment boxes; it is about every place your site shows text it did not write. Ask for the places where escaping is bypassed to be listed and reviewed, and for a Content Security Policy to be set. On a static business site the list is short and the policy is a few lines, and together they close a category of attack rather than a single hole.

Written by the CivSec S.M.A.R.T team

We build and run websites, software and AI systems for businesses. We write about what we see in that work, in plain language, and we update articles when things change.

Last checked . Spotted something outdated? Tell us.

Frequently asked questions

Our site has no comments. Are we safe?

Look for anywhere user-supplied text is shown back: a search results page that says 'results for ...', a form that re-displays what was entered after an error, a name shown in an account area, a review, a product question. Each is a place where escaping must happen. Fewer places is better, and a static site has very few.

What is the difference between escaping and filtering?

Filtering tries to remove dangerous input on the way in and always misses something. Escaping neutralises output on the way out: the characters that would start a script are converted so the browser shows them as text. Escaping is the defence; filtering is a bonus.

Does a Content Security Policy replace escaping?

No. It is the second layer: if a script does get injected because escaping was missed somewhere, a policy that does not permit inline code stops the browser from running it. A policy containing 'unsafe-inline' does not, and that is the first thing to check. Both together make the class of attack very hard. Either alone leaves a gap.

Sources

  1. OWASP Cheat Sheet: Cross Site Scripting Prevention (accessed 2026-09-11)
  2. MDN Web Docs: Content Security Policy (accessed 2026-09-11)