What Is Cross-Site Scripting (XSS)? Plain-English Guide

By Bug Circuit Security Team
What Is Cross-Site Scripting (XSS)? Plain-English Guide

Cross-site scripting (XSS) is a security bug that lets an attacker sneak their own code into a page your visitors trust, so it runs inside their browser as if your site wrote it — quietly stealing login sessions, redirecting payments, or planting fake forms. It's one of the oldest and still most common web vulnerabilities, and it doesn't require breaking into your server — just finding one spot on your site that echoes back user input without cleaning it up first.

This is for owners of WordPress sites, Shopify stores, indie SaaS apps, or small business sites who've heard the term "XSS," maybe seen it flagged by a scanner, and want to know in plain English what it actually does and whether their contact or comment form is a target. By the end, you'll know how to test for it yourself and what a real fix looks like.

The short version: how XSS actually works

Every web page is a mix of your content and, sometimes, content your visitors typed in — a comment, a search term, a name field, a support ticket. Your site's job is to display that input back safely, as plain text.

XSS happens when your site instead treats that input as code and runs it. If someone types <script>steal_your_cookies()</script> into a form and your page prints it straight into the HTML without encoding it, the browser doesn't see text — it sees an instruction to execute. The script isn't hosted on some attacker's server pretending to be you; it runs directly inside your page, in the visitor's browser, with full access to whatever your page can see.

OWASP, the nonprofit that maintains the standard reference for web vulnerabilities, defines XSS as an injection attack where malicious scripts are injected into otherwise trusted, benign websites — and it's serious enough to be folded into the OWASP Top 10's Injection category, a list of the most critical risks to web applications.

The three flavors of XSS (and why the difference matters)

Not all XSS behaves the same way, and the type affects who's at risk and how urgently it needs fixing.

TypeWhere the malicious script livesHow it usually gets deliveredReal-world risk
Stored (persistent) XSSSaved in your database — a comment, review, forum post, profile bioAttacker submits it once through a formEvery visitor who later views that page runs the script automatically — the most dangerous variant
Reflected XSSBounced back in the page's response, never savedA crafted link with the script in the URL, sent via email or adOnly affects someone who clicks the malicious link
DOM-based XSSInjected entirely in the browser by client-side JavaScriptPage JavaScript reads something like the URL fragment and writes it into the page without checking itCan happen even if your server-side code is perfectly clean

Stored XSS is the one to worry about most on a small site, because a single successful comment-form submission can quietly compromise every visitor who reads that page afterward — no clicking required.

What an attacker can actually do once their script runs

Once a script executes in a visitor's browser on your domain, it inherits whatever trust that visitor has placed in your site. Concretely, that means an attacker can:

  • Hijack a logged-in session. Read the session cookie or auth token and reuse it to log in as that user — including an admin — without ever knowing the password.
  • Inject a fake payment form. Overlay a convincing "update your card details" box on your real checkout or account page, capturing card numbers that go straight to the attacker instead of your payment processor.
  • Redirect or phish. Silently forward the visitor to a lookalike login page, or pop a fake "session expired, log in again" prompt that harvests credentials.
  • Log keystrokes or grab form data before it's even submitted.
  • Deface or spread. On stored XSS, the payload can rewrite the page for every subsequent visitor, or worm through comment sections automatically.

None of this requires the attacker to find a way into your hosting account or database directly — the browser does the work for them.

Is your contact or comment form actually exposed?

Any place your site takes text from a stranger and later displays it back — to that same visitor or to anyone else, including your own staff — is a candidate. Common spots on small sites:

  • Comment sections and product reviews
  • Contact forms that echo the name back on a "Thanks, {name}!" confirmation page
  • Search boxes that show "No results for {your search}"
  • Support/ticket forms an admin later opens in a dashboard
  • User profile fields (bio, display name, website URL)
  • Any WordPress plugin or theme that hasn't been updated in over a year

If your site is on WordPress, outdated plugins are the single most common source — vulnerable versions get published with fixes in the changelog, so an attacker just needs to know your plugin version. Not sure where you stand? Our free website security check flags exposed input points and out-of-date software without needing a login or card.

How to check it yourself (safely)

You can do a basic, non-destructive test on your own site — never test a site you don't own or have permission to test.

  1. Find a form field that gets displayed back somewhere (comment box, contact form, search).
  2. Submit a harmless test string: <script>alert('test')</script> or, if angle brackets get stripped, try "><img src=x onerror=alert(1)>.
  3. Load the page where that input is displayed back.
  4. If a popup box appears saying "test" or "1" — your input isn't being encoded, and that field is vulnerable.
  5. If the text shows up literally as <script>alert('test')</script> on the page (not as a popup), the field is encoding it correctly.

Delete your test comment afterward. This manual check only catches the obvious cases — automated scanners and a trained eye catch far more, including DOM-based XSS that never touches your server logs at all, which is one reason a manual review typically finds more than automated scanning alone.

How to actually fix it

The fix depends on where the bug lives, but the core principle from OWASP's Cross-Site Scripting Prevention Cheat Sheet is simple: never let untrusted input become code.

  • Encode output, don't just filter input. Escape special characters (<, >, ", ', &) whenever user data is written into HTML, so <script> renders as text, not code. Every modern templating framework (React, Vue, Twig, Blade) does this automatically by default — don't bypass it with functions like dangerouslySetInnerHTML or v-html unless the content is sanitized first.
  • Sanitize rich text properly. If you must allow some HTML (e.g., a WYSIWYG comment box), run it through a real sanitizer library like DOMPurify — don't hand-write a regex filter, which almost always misses an edge case.
  • Set a Content-Security-Policy header. This tells the browser which sources of script it's allowed to run, so even an injected <script> tag gets blocked. A reasonable starting policy: Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'. See MDN's CSP reference for the full syntax. You can check what headers your site currently sends with our security headers scanner.
  • Lock down cookies so a successful XSS can't be turned into a session hijack. Set Set-Cookie: sessionid=<value>; HttpOnly; Secure; SameSite=StrictHttpOnly stops JavaScript from reading the cookie at all, which blunts the most common XSS payoff even if a script does slip through.
  • Keep CMS/plugins current and remove unused ones. On WordPress, update core, theme, and every plugin promptly, and consider a web application firewall plugin (e.g., Wordfence or Sucuri) as a second layer, not a replacement for fixing the actual code.

None of these fixes require a rebuild — most are a template change, one HTTP header, and a cookie flag.

Key takeaways

  • XSS lets an attacker's script run inside your visitors' browsers on your own domain — it doesn't require hacking your server directly.
  • Stored XSS (comments, reviews, profile fields) is the highest-risk type because it hits every visitor automatically, not just people who click a bad link.
  • Watch any field that echoes user input back — contact forms, search boxes, comments — and test with a harmless <script>alert(1)</script> payload on your own site only.
  • Fix it with output encoding, a Content-Security-Policy header, and HttpOnly/Secure/SameSite cookie flags — not a hand-rolled filter.
  • Automated scanners miss a lot of real-world XSS, especially DOM-based cases; that's the gap a manual review is built to close.

If you'd rather have a person check for this instead of guessing from a checklist, that's exactly what Circuit is: a $49 one-time manual audit where a real security engineer tests your forms, comments, and inputs by hand and hands you a written report with exact fixes — not just a scanner printout. If you're not sure your site's been affected already, our guide on signs your website might be hackable is a good next read.

Want certainty, not guesswork?

A real human security engineer audits your whole site by hand and sends a full report — every issue, its severity, and the exact fix. From $49, with a 14-day money-back guarantee.

See pricing

Common questions

What is cross-site scripting (XSS)?
Cross-site scripting is a web vulnerability that lets an attacker inject their own JavaScript into a page, which then runs in a visitor's browser as if your site had written it. It's used to steal session cookies, redirect payments, or show fake login and payment forms, and it's one of OWASP's most commonly reported injection flaws.
Is XSS dangerous for a small website?
Yes — a small site is often an easier target than a large one because it's less likely to have a Content-Security-Policy header or sanitized comment forms. Stored XSS in particular can silently affect every visitor to a page, including admins, until it's found and removed.
Can XSS steal login sessions or passwords?
It can steal session cookies (letting an attacker act as a logged-in user without a password) if the cookie lacks the HttpOnly flag, and it can present fake login or payment overlays that capture whatever a visitor types. Setting HttpOnly, Secure, and SameSite on your session cookies blocks the most common version of this.
How do I know if my contact or comment form is vulnerable to XSS?
Submit a harmless test string like <script>alert('test')</script> into the field on your own site, then view the page where that input is displayed back. If a popup box appears, the field isn't encoding input safely; if the text shows up as literal characters instead, it's handled correctly.
Does a Content-Security-Policy header stop XSS?
It significantly reduces the damage even if a script gets injected, by telling the browser which script sources are allowed to run — but it's a safety net, not a substitute for properly encoding output in the first place. Both should be in place together.

Keep reading

See what attackers see — free

Run the free passive check on your domain. No login, no impact on your site, results in seconds.

Passive recon only. No login, and no impact on your site. Deeper testing needs domain verification.

Ready for the full manual audit? See transparent pricing →

Published by Bug Circuit. Written with AI assistance and reviewed for accuracy before publishing.