Cross-Site Scripting (XSS): The Complete Practical Guide

Reflected XSS

How reflected cross-site scripting works: input echoed in the immediate response, delivering it with a crafted link, and why it needs a victim to click.

Published

Reflected XSS is the simplest kind to understand: your input is echoed straight back in the response to the request that carried it, with no encoding, and the browser runs it. Nothing is saved on the server. The payload lives only in the request and the immediate reply, which shapes everything about how you exploit it.

What "reflected" means

A reflected bug takes a value out of the request (a query parameter, a form field, a path segment) and writes it into the response that comes right back. The classic home for it is a search page that prints what you searched for, or an error page that repeats a bad value:

https://shop.example/search?q=laptop   ->   "No results for laptop"

If laptop is written into the page unencoded, so is anything else you put in q. Swap in markup and you find out whether the app treats it as text or as code.

The classic vector

Point a marker at the parameter and look at the response:

https://shop.example/search?q=zz9marker

Find zz9marker in the returned HTML. If it sits in the body as plain text, a new tag will execute:

https://shop.example/search?q=<script>alert(document.domain)</script>
https://shop.example/search?q=<img src=x onerror=alert(document.domain)>

The <img> form is handy because many filters strip <script> but miss event handlers on other tags. Whichever fires, you have proven execution in the site's origin.

Delivering it

Because the payload lives in the request, you have to get the victim to make that request while logged in. In practice that means:

  • A crafted link sent over email, chat, or a comment, with the payload in the query string.
  • A page you host that silently issues the request, for example an auto-submitting form or an <iframe>/<img> pointed at the vulnerable URL.
  • A shortened or disguised URL so the payload is not obvious in the link text.

URL-encode the payload so the link survives being pasted and clicked. The victim opens it, the server reflects your script into their response, and it runs with their cookies and their session.

Why it needs a click

This is the defining limitation. Stored XSS fires for anyone who views the affected page, but reflected XSS only runs for someone who follows your specific request. No click, no execution. That makes delivery and targeting part of the exploit, not an afterthought. A reflected bug on a page an administrator regularly opens, or in a link that looks legitimate, is far more dangerous than the same bug on an obscure endpoint.

Reflected in different contexts

Where your input lands decides the payload. Reflected into the HTML body, you inject a tag. Reflected inside an attribute value, you break out of the quotes or add an event handler without breaking out. Reflected inside a <script> block, you close the JavaScript statement instead of using tags at all. The full set of break-outs is in XSS contexts, and the cheat sheet lists the payload for each.

When it fails

A reflection does not always mean a vulnerability. Your payload will not fire when:

  • The app context-encodes the output, turning < into &lt; so it renders as text.
  • Your input lands in a context where your characters are not special, so there is nothing to break out of.
  • A filter or WAF strips the tag or keyword before it reaches the page, which is where filter and WAF evasion comes in.

Confirm the context first, then pick the payload. Guessing wastes requests and trips filters for no reason.

Reflected XSS is the cleanest place to build the find-context-breakout reflex. Practice it on a free live target, then move on to stored XSS, where the payload fires on its own.

← Back to Cross-Site Scripting (XSS): The Complete Practical Guide