XSS vs CSRF

Both are client-side attacks, but XSS runs code in the browser while CSRF rides the user's session.

XSSCSRF
Full nameCross-Site ScriptingCross-Site Request Forgery
Attack typeInject and execute JavaScriptForge authenticated HTTP requests
What the attacker getsFull control of the page — steal tokens, keylog, redirectOne action performed as the victim
Requires victim interaction?Victim visits the vulnerable pageVictim visits the attacker's page
Attacker sees response?Yes — the script runs in the victim's browserNo — blind request
Same-origin policyBypassed (script runs in the target's origin)Enforced (attacker can't read the response)
Key defenseOutput encoding, CSPCSRF tokens, SameSite cookies

The short answer

XSS runs the attacker's code in the victim's browser, inside the target's origin. CSRF makes the victim's browser send a request the attacker chose, without being able to read the answer. XSS is a capability; CSRF is a single forged action. That asymmetry is why XSS defeats CSRF defenses and not the other way round.

How to tell which you're looking at

Does attacker-controlled script execute in the target's origin? If yes, it's XSS, and the severity conversation is about what that script can reach — session tokens, the DOM, any authenticated endpoint. If the attack works entirely from a page on a different origin with no script running on the target, it's CSRF.

Can the attacker read the response? This is the cleanest discriminator. XSS can, because the code is executing inside the origin and the same-origin policy is on its side. CSRF cannot — the browser sends the request and attaches the cookies, but the attacker's page is blocked from reading what came back. Any report claiming CSRF that also claims data exfiltration is either describing something else or describing a CORS misconfiguration.

Is a token involved? CSRF is defeated by an unpredictable value the attacker's site cannot obtain. XSS is not, because code running in the origin can simply read the token out of the page before using it. This is the practical relationship between the two: XSS defeats every CSRF defense, which is why fixing XSS takes precedence and why "we have CSRF tokens" is not a mitigating factor in an XSS report.

Worked example: changing a victim's email address

The target application has an email-change endpoint that requires a POST with a CSRF token and the current password.

Via CSRF alone, the attack fails twice over. The attacker's page cannot obtain the token, because reading it would require a cross-origin read the browser refuses. Even with the token, the endpoint requires the current password, which the attacker doesn't have. This is what a reasonable implementation looks like — and it illustrates that CSRF exploitation depends entirely on the endpoint's design.

Via stored XSS, all of that collapses. The attacker's script is running in the origin, so it fetches the settings page, parses the CSRF token out of the DOM, and submits the change with the token attached. The password requirement is a real obstacle — but the script can also register a keylogger on the login form, or wait for the user to re-authenticate, or simply use the existing session to do whatever else the account permits. The account takeover may take a different route, but the CSRF control contributed nothing.

That's the hierarchy in one example: CSRF exploits one endpoint's missing check, XSS exploits the trust the browser places in the entire origin.

Defenses, and which control stops which

XSS: context-aware output encoding, a framework that escapes by default, Content Security Policy to raise the cost of injected script, trusted types to lock down DOM sinks, and sanitizing HTML with a maintained library rather than a hand-written filter. Cookie flags help contain it — HttpOnly keeps script from reading the session cookie — but containment is not prevention.

CSRF: synchronizer tokens, SameSite cookie attributes, origin and referer checks, and requiring a header that a simple cross-origin form cannot set. Since browsers adopted SameSite=Lax as a default, most of this class disappeared; what remains is GET-triggered state changes, cookies deliberately set to None, and non-cookie authentication schemes that SameSite never covered.

Useful test of your own understanding: a CSP will not stop CSRF (the request isn't script, and it originates from a page the policy doesn't govern), and a CSRF token will not stop XSS (the script reads it). Controls that sound adjacent are not interchangeable.

Reporting and severity

XSS reports fail most often on impact rather than proof. An alert box demonstrates execution; it doesn't demonstrate consequence. Show the chain — read a token, drive an authenticated state change, reach account takeover. Stored XSS on an authenticated page consistently pays well precisely because that chain is short.

CSRF reports fail most often on exploitability. Establish that the endpoint genuinely lacks protection under current browser defaults, that the action has real consequence, and that the cookie configuration actually permits the cross-site request — a POST endpoint protected by SameSite=Lax is not exploitable no matter how absent the token is. Full collections: XSS and CSRF.

Common questions

Can XSS be used to perform CSRF?

It can do something strictly better. Script running in the origin reads the CSRF token and issues a fully legitimate request, so the attacker isn't forging anything — the CSRF defense is simply irrelevant. This is why XSS outranks CSRF in severity almost every time.

Do CSRF tokens protect against XSS?

No, and the reasoning is worth being clear about: the token is in the page, and XSS executes in the page. Anything the browser can read, injected script can read.

Is CSRF still worth testing given SameSite defaults?

Yes, but selectively. Look at GET-triggered state changes, cookies explicitly set to SameSite=None for cross-site integrations, bearer-token or Basic authentication that SameSite never covered, and method-override parameters that turn a permitted request into a forbidden one.

Does HttpOnly stop XSS?

It stops script from reading that cookie, which removes one exfiltration path. The script still runs and can make authenticated requests using the cookie the browser attaches automatically. Containment, not prevention.

Which should I fix first?

XSS. It subsumes CSRF's impact, defeats CSRF's defenses, and reaches data that CSRF structurally cannot.

More comparisons: SSRF vs CSRF XSS Types AuthN vs AuthZ IDOR vs BOLA SQLi vs NoSQLi SAST vs DAST Bounty vs Pentest SBOM vs SLSA Validation vs Encoding DAST vs IAST vs RASP SCA vs SAST OAuth vs SAML Pentest vs Red Team WAF vs RASP