Cross-site scripting
classGetting a browser to execute script you supplied, in someone else's session.
01Find the reflection first
Where does your input land, and what is it sitting inside?
Before any payload: send a canary and read the response source, not the rendered page. The context you land in decides every payload afterwards, and skipping this is why people fire two hundred payloads and get nothing.
| HTML body | Between tags. Inject a whole element. |
| Attribute value | Break out of the quote first, or use an event handler on the existing tag. |
<script> block | You are already in JS. Break out of the string, no tags needed. |
| URL attribute | href, src, action. Needs a javascript: scheme, not a tag. |
| JS string | Inside quotes inside a script. Close the quote, not the tag. |
Encoded on the way in is not the same as safe. If < comes back as < in the body but raw inside an attribute, you have an attribute-context XSS and a body-context dead end. Check every reflection separately.
02HTML body context
Your input lands between tags, so inject a complete element.
03Attribute context
You are inside a quoted attribute value. Escape it, or don't bother.
onclick.If the quote comes back encoded but the value is used in an event-handler attribute, you don't need to break out at all — you're already inside executable JavaScript.
04Script and JS string context
var x = INPUT; becomes valid arithmetic that still calls the function.</script> inside a quoted JavaScript string still ends the script element. Nothing in the JS language can protect you from that, which is why templating engines have to encode it and why a payload list must never let anything parse its own contents.
05Blind XSS
Fires somewhere you can't see — an admin panel, a log viewer, a support ticket.
Put these in every free-text field you meet — names, user agents, referrers, ticket bodies — and forget about them. The value of blind XSS is that it pays out days later.
06Filter bypasses
alert never appears in the request.ale/**/rt does not work. Comment-splitting separates SQL tokens because the SQL lexer treats a comment as whitespace; in JavaScript it produces two identifiers and a syntax error. Use the unicode escape or the computed property instead.