⚠️ Authorised Lab Environment Only. All CSRF bypass and token extraction techniques in this lab must be practised exclusively on your own local DVWA installation or authorised platforms. Testing these techniques against production applications without explicit written permission violates computer misuse legislation. Every exercise in this lab targets http://localhost/dvwa/ only.
DVWA CSRF Advanced Lab for 2026 :— Developers add CSRF tokens and believe the problem is solved. It often isn’t. The token prevents a naïve forged form submission because the attacker doesn’t know the token value. But when the same application also has a stored XSS vulnerability — even on a completely unrelated page — that XSS can fetch the CSRF-protected page, read the token out of the HTML, and include it in the forged submission. The CSRF protection is cryptographically sound. The XSS is the bypass. This is why application security cannot be evaluated one vulnerability at a time. Individually, a medium-severity stored XSS and a high-severity CSRF are two separate findings. Chained together, they are a one-click account takeover that a skilled attacker will exploit before the security team’s next sprint review.
🎯 What You’ll Master in Lab 20
Understand how CSRF tokens work and precisely why XSS on the same domain defeats them
Build and deliver a working no-token CSRF attack at Low security
Extract a live CSRF token via XSS fetch and use it in a forged request at Medium security
Identify and exploit Referer header validation flaws at High security
Chain stored XSS with CSRF token bypass for a fully automated account takeover payload
Document the attack chain in a format suitable for a penetration test or bug bounty report
⏱️ 55 min lab · 3 terminal exercises · Localhost DVWA only
📋 Prerequisites — Complete Before Lab 20
Lab 4: DVWA CSRF Basics — understand how a basic CSRF attack without any token protection works before attempting token bypass
Lab 8: DVWA XSS Reflected — the XSS execution context used for token extraction in this lab builds on Lab 8’s techniques
Lab 19: DVWA XSS Cookie Theft — same-domain XSS used to exfiltrate data; Lab 20 applies the same XSS execution to extract CSRF tokens instead of session cookies
Lab 4 established basic CSRF where no token exists and a forged form submits freely. Lab 19 established XSS execution context on the same DVWA domain, showing how JavaScript running inside the victim’s browser can exfiltrate data. Lab 20 connects both: XSS provides the same-origin execution needed to read a CSRF token that cross-origin requests cannot access. Completing this lab completes the client-side attack chain. The DVWA Lab Series then moves to Lab 21’s SQL Injection High Security — a different attack class where security level escalation requires increasingly sophisticated query techniques.
Why CSRF Tokens Are Bypassed When Same-Domain XSS Exists
The CSRF token defence relies on one assumption: that an attacker’s page, loaded in the victim’s browser from a different origin, cannot read the content of the protected application’s pages. This is the Same-Origin Policy at work — cross-origin JavaScript cannot read the response body from a different domain. A forged form on attacker.com cannot fetch victim-app.com/change-password and read the CSRF token from the HTML response because the Same-Origin Policy blocks that cross-origin read.
XSS on the same domain destroys this assumption. When an attacker injects JavaScript into a page on victim-app.com itself — through any XSS vulnerability on any page of the application — that script runs in the victim-app.com origin. It is no longer cross-origin. It can freely make XMLHttpRequest or fetch calls to any other page on victim-app.com and read the full response body, including any CSRF token embedded in a hidden form field. The attacker’s injected script extracts the token, constructs the forged request including the token, and submits it — all within the same trusted origin. From the server’s perspective, the token is valid. The request appears legitimate. The CSRF protection is completely defeated.
This is the core insight of the XSS+CSRF chain: CSRF tokens protect against cross-origin forged requests. They do not protect against forged requests constructed within the same origin by injected JavaScript. If any XSS vulnerability exists anywhere on the application — even on a low-traffic, seemingly unimportant page — it can be weaponised to bypass CSRF protection on any other page of the same application.
Scope Thinking for Bug Bounty: When you find a stored XSS anywhere in an application, immediately ask: what CSRF-protected actions exist on this domain? Password change, email change, privilege grant, payment authorisation? Each of these is potentially reachable via the XSS+CSRF chain. A medium-severity stored XSS combined with a CSRF-protected password change becomes a Critical severity account takeover chain — and the combined finding almost always commands a higher payout than either finding individually.
XSS injected on victim.com/guestbook → fetch(‘victim.com/change-pw’) → ALLOWED: same origin
Reads HTML response → extracts user_token=abc123 → forges request with valid token
Server validates token → accepts request → password changed
📸 The fundamental reason CSRF tokens fail against same-domain XSS. The Same-Origin Policy (SOP) prevents cross-origin reads — attacker.com cannot read victim.com’s CSRF token. But XSS injected on victim.com runs within that same origin, making all fetch/XHR requests same-origin and therefore readable. The CSRF token is cryptographically strong but the SOP protection it relies on has been eliminated by the XSS vulnerability. Both findings must be remediated together to close the chain.
Low Security — Basic CSRF Without Token Protection
At DVWA Low security, the change password form submits without any CSRF token — a direct recreation of the basic vulnerability covered in Lab 4. Revisiting it here serves two purposes: confirming your understanding of how the forged form works before adding complexity, and establishing a baseline to compare against the token-protected Medium security level. The Low security CSRF attack is a straightforward HTML form that auto-submits via JavaScript when loaded by an authenticated victim.
The forged form targets the DVWA password change endpoint directly, including the new password values but no CSRF token because none is required. When an authenticated user loads the attacker’s page, the auto-submit fires, the form POST goes to DVWA, the server processes it, and the password is changed. The attack completes without the victim performing any deliberate action beyond loading the malicious page.
LOW SECURITY — BASIC CSRF FORGED FORM (NO TOKEN)
<!– Save as csrf_low.html and open in a browser while logged into DVWA –>
✅ What you just learned: The Burp intercept comparison between Low and Medium security makes the token’s role concrete. At Low, the GET request has no user_token — any forged form works. At Medium, user_token appears and the server validates it matches the stored session value. The curl command confirms where the token lives in the page HTML: a hidden input field. This is the target for the XSS fetch extraction in Exercise 2. The token changes on every page load, which is why you cannot simply observe one and reuse it — you must extract a fresh one for each forged request.
📸 Screenshot the Burp intercept showing the Low request (no token) and the Medium request (with user_token). Post to #lab-20-csrf-advanced on Discord.
Understanding the DVWA Anti-CSRF Token
Before attempting to bypass the token, it’s worth understanding exactly what it is and why the basic bypass strategies fail. The DVWA anti-CSRF token is a randomly generated 32-character hexadecimal string stored in the PHP session on the server side and embedded in every sensitive form as a hidden input named user_token. When the form is submitted, the server checks whether the submitted user_token matches the one stored in the session. If they match, the request is accepted. If they don’t match or the token is missing, the request is rejected with an “invalid token” response.
This design defeats the naive cross-origin attack because the attacker cannot read the token from a page they don’t control on the victim’s domain. The token is different for every user and every session. Even if an attacker managed to observe their own token, submitting it in a forged request against a different user’s session would fail because the server checks the token against the requesting session, not against a global value. The only way to bypass this is to obtain the victim’s current token — which is only possible if you have same-origin code execution.
CSRF TOKEN STRUCTURE — VIEW PAGE SOURCE AND INSPECT
# View the CSRF page source to find the token in the HTML
# Stale or wrong token = rejected. Must extract a fresh, valid token to proceed.
Medium Security — CSRF Token Extraction via XSS Fetch
The XSS+CSRF bypass exploits the same-origin read capability that XSS grants. When JavaScript injected on victim-app.com makes a fetch request to another page on victim-app.com, the browser treats it as a same-origin request and allows reading the response body. This is fundamentally different from what cross-origin JavaScript can do. The injected script fetches the CSRF-protected page, parses the HTML response to extract the token value, and then constructs a second request — the actual CSRF attack — that includes that fresh, valid token.
In DVWA, the XSS Reflected vulnerability is on the same localhost domain as the CSRF-protected password change form. JavaScript injected through the XSS input can fetch the CSRF page and read its response. The token extraction uses a regex match on the response HTML to find the user_token value, then immediately uses it to construct the forged GET request. The entire chain — fetch token, forge request with token, submit — happens in a single script execution that completes in milliseconds from the victim’s browser.
MEDIUM SECURITY — XSS TOKEN EXTRACTION AND CSRF CHAIN PAYLOAD
# This payload injects via DVWA XSS Reflected — same domain as CSRF endpoint
# Enter this in the XSS Reflected name field (security = medium, use onerror bypass)
← Valid token extracted from Request 1 response — server accepts this
📸 The XSS+CSRF chain as seen in Burp Suite. Two requests fire in rapid succession: Request 1 fetches the CSRF-protected page and the injected JavaScript reads the user_token value from the HTML response body. Request 2 immediately fires with that fresh token in the URL — the server validates it as correct and processes the password change. Both requests carry the victim’s session cookie, making them indistinguishable from legitimate user actions.
⚡ EXERCISE 2 — KALI TERMINAL (20 MIN)
XSS+CSRF Token Bypass — Full Chain at Medium Security
⏱️ 20 minutes · Kali + DVWA + Burp Suite capturing requests
MEDIUM SECURITY — XSS TOKEN BYPASS FULL CHAIN
# Step 1: Confirm current admin password works
# Log in to DVWA: http://localhost/dvwa/login.php
# Credentials: admin / password (default)
# Set security to MEDIUM
# Step 2: Note your current PHPSESSID
# F12 > Application > Cookies > localhost > PHPSESSID value
echo “Current session: [your PHPSESSID here]”
# Step 3: Navigate to XSS Reflected (Medium security)
# Step 6: Reset password back to original for next exercise
# Log in with hacked, go to CSRF page, change back to password
✅ What you just learned: The two-request sequence in Burp makes the XSS+CSRF bypass mechanism completely visible. Request 1 (the token fetch) and Request 2 (the forged CSRF) fire within milliseconds of each other — both carrying the victim’s session cookie, both appearing legitimate to the server. The key technical detail to observe: the user_token value in Request 2 exactly matches the value embedded in the HTML response of Request 1. This proves the extraction worked. This chain is reproducible on any application where: (1) stored or reflected XSS exists, (2) the CSRF-protected page returns a token in its HTML, and (3) the two endpoints share the same origin.
📸 Screenshot the Burp HTTP history showing both requests (token fetch + forged CSRF with token). Post to #lab-20-csrf-advanced on Discord.
High Security — Referer Header Validation and Its Bypass
DVWA High security adds Referer header checking as an additional CSRF protection layer. When the password change form is submitted, the server inspects the Referer header in the HTTP request to verify the request originated from the DVWA application itself. If the Referer doesn’t contain the expected host value, the request is rejected. This is a defence-in-depth measure that many real applications use alongside or instead of token-based protection.
The DVWA High security Referer check uses a string-contains validation — it checks whether the Referer header value contains the host string (typically “127.0.0.1” or “localhost”) anywhere within it. This is a common implementation mistake. A strict check would verify that the Referer exactly matches the application’s origin. A loose contains-check can be satisfied by any Referer URL that has the target string anywhere in it — including in the path or query string of a completely different domain, if the attacker can control those URL components.
The practical bypass in a lab environment: the Referer check passes if the Referer URL contains “127.0.0.1”. If you host your CSRF PoC at a URL like http://attacker.com/127.0.0.1/csrf.html, the path component “127.0.0.1” is present in the Referer string and the loose check passes. Additionally, PHP’s $_SERVER['HTTP_REFERER'] can often be manipulated or stripped by browser privacy settings — some implementations fail open (accept the request) when the Referer header is absent.
HIGH SECURITY — REFERER VALIDATION CHECK AND BYPASS
# Step 1: Check DVWA High source to understand the Referer check
# In DVWA: View Source button shows server-side PHP
# “localhost” appears in the Referer path — loose check passes
# Step 4: In Burp — manually modify Referer header in Repeater
# Intercept password change request
# Right-click > Send to Repeater
# Modify Referer: http://attacker.com/localhost/
# Send — check if password changes successfully
⚠️ Strict vs Loose Referer Validation: The DVWA High bypass works because DVWA intentionally implements a flawed contains-check. Real applications with robust CSRF protection perform exact origin matching using the Origin header (not Referer), which includes only the scheme, host, and port without any path component — making the path-injection bypass impossible. When testing real targets, first check whether the application uses the Origin header or Referer header for CSRF validation, as this determines which bypass techniques are applicable.
The highest-impact version of this attack combines stored XSS with the CSRF token bypass into a fully automated payload. When injected into DVWA’s stored XSS guestbook, every authenticated user who loads the guestbook page automatically has the token extraction and forged request chain fired against them — no phishing link, no interaction required. This is what makes the combined finding genuinely Critical rather than just High.
The stored XSS guestbook payload injects the full fetch-token-then-CSRF chain into the message field. The maxlength restriction needs to be bypassed via DevTools (change from 50 to 500 characters), exactly as done in Lab 19. Once stored, the payload persists. Every user who visits the guestbook has their CSRF token extracted and their password silently changed to the attacker’s chosen value. On a real application, a stored XSS+CSRF chain on a high-traffic page could result in hundreds of account takeovers before the payload is discovered and removed.
# Count = 1: payload persists in guestbook until manually removed
✅ What you just learned: The stored XSS+CSRF chain is the most dangerous client-side attack combination in web application security. No social engineering, no phishing, no victim interaction beyond loading the page. The payload fires automatically for every authenticated user who visits the guestbook. In a real application with high traffic, this single injection could take over thousands of accounts before anyone notices the pattern. This is precisely the impact argument that should accompany a combined XSS+CSRF bug bounty report — not “I found XSS” and separately “I found CSRF,” but “I chained XSS with CSRF to achieve automated account takeover affecting all authenticated users who visit page X.”
📸 Screenshot showing: (1) payload stored in guestbook, (2) your own password changed to ‘owned’, (3) the second victim’s password changed after loading the page. Post to #lab-20-csrf-advanced on Discord with tag #lab20-complete.
Reporting the XSS+CSRF Chain in a Pentest or Bug Bounty Report
A combined XSS+CSRF chain report must communicate two things that individual vulnerability reports often miss: the combined impact is greater than the sum of its parts, and the finding requires a combined fix — patching only the XSS or only the CSRF in isolation leaves the chain exploitable. The report structure should present the chain clearly, demonstrate the full attack from injection to account takeover, and specify remediation for both components.
The title of a chained report should always name the outcome, not the technique: “Stored XSS on /guestbook enables One-Click Account Takeover via CSRF Token Bypass” tells a triager exactly what is at stake before they read a single line of the report. The severity should reflect the worst-case combined impact — in this case, Critical, because all authenticated users who visit the guestbook page are subject to automated account takeover without any additional interaction.
Patching only one component leaves the chain exploitable via the other
📸 Recommended report structure for XSS+CSRF chained findings. The critical point in the remediation section is that both components must be fixed simultaneously — patching only the XSS removes the token bypass path but a future XSS on the same domain restores it. Patching only the CSRF without fixing the XSS means the injection persists and can be chained with any future CSRF-vulnerable endpoint. The finding is Critical precisely because the chain creates impact larger than either vulnerability in isolation.
🧠 QUICK CHECK — Lab 20 CSRF Advanced
A developer fixes the stored XSS vulnerability from your chained report by sanitising the guestbook input. They leave the CSRF token validation as-is. Is the account takeover chain now closed?
📋 Commands Used Today — Lab 20 CSRF Advanced Reference
curl -b “…” http://localhost/dvwa/vulnerabilities/csrf/ | grep user_tokenExtract current CSRF token from DVWA page HTML response
fetch(‘/dvwa/vulnerabilities/csrf/’).then(r=>r.text()).then(html=>{…})XSS payload: same-origin fetch to read CSRF token from protected page
html.match(/user_token.*?value='([^’]+)’/)[1]Regex to extract token value from raw HTML response string
<img src=x onerror=”fetch+token+forged_request”>Medium security: img onerror event handler wraps the full XSS+CSRF chain
You have completed the client-side attack chain: XSS (Labs 8–10, 19) culminating in CSRF token bypass and automated account takeover (Lab 20). Lab 21 covers SQL Injection High Security — bringing the server-side attack complexity up to match the client-side sophistication you’ve built in the last four labs.
Lab 20 is the advanced CSRF lab focusing on bypassing anti-CSRF token protection. It covers three security levels: Low (no token — basic forged form), Medium (token present but bypassed via same-domain XSS fetch extraction), and High (token + Referer header validation with a loose string-match bypass). It builds on Lab 4 (basic CSRF) and Lab 19 (XSS same-domain execution).
Can CSRF tokens be bypassed?
Yes, in specific circumstances — most importantly when a same-domain XSS vulnerability exists. XSS allows JavaScript to run within the target application’s origin, enabling same-origin reads of the CSRF-protected page to extract the token. Other bypass scenarios include predictable tokens, Referer-only validation with loose string matching, and implementations that fail open when the token parameter is omitted entirely.
What is the XSS and CSRF chain attack?
XSS+CSRF uses a Cross-Site Scripting vulnerability on the same domain to fetch the CSRF-protected page, extract the hidden user_token from the HTML response, and submit a forged request including that valid token. The Same-Origin Policy allows the same-domain XSS to read responses from any page on the same domain — the exact capability that makes the CSRF token bypass possible. Both vulnerabilities must be fixed to close the chain.
What is Referer header CSRF bypass?
Applications that validate the HTTP Referer header for CSRF protection can be bypassed when the check is a loose string-contains rather than exact domain matching. Including the target domain string in the path of the attacker’s URL (e.g., attacker.com/localhost/csrf.html) causes the Referer to contain the target string and pass the check. Some browser privacy settings also strip the Referer header, which can cause fail-open implementations to accept the request.
How does DVWA high security CSRF protection work?
DVWA High implements both a user_token in the form and a Referer header check via PHP stripos(). The Referer check verifies the request Referer contains the SERVER_NAME string. The bypass is the loose contains-check — placing the server name anywhere in the Referer URL path satisfies the check. In real applications, Origin header validation with exact matching is significantly stronger than Referer-based checks.
What DVWA labs connect to Lab 20?
Lab 4 (DVWA CSRF basics) introduced the attack without any token protection. Lab 19 (XSS Cookie Theft) established same-domain XSS execution. Lab 20 chains both. Lab 21 (SQL Injection High Security) continues the escalating complexity track. Labs 8, 9, 10, 19, and 20 together form the complete DVWA client-side attack sequence.
← Previous
Lab 19: DVWA XSS Cookie Theft
Next →
Lab 21: SQL Injection High Security
📚 Further Reading
DVWA XSS Cookie Theft — Lab 19— The XSS execution context Lab 20 exploits for CSRF token extraction was established in Lab 19 — completing both in sequence builds the full mental model of same-domain XSS impact.
DVWA CSRF Lab — Lab 4— The foundational CSRF lab with no token protection — revisit it alongside Lab 20 to understand exactly what the token adds and why same-domain XSS defeats that addition.
DVWA Lab Series Hub— Full 30-lab overview — Lab 20 completes the client-side chain; the next phase covers server-side escalation with SQL Injection High (Lab 21) and vulnerability chaining (Lab 22).
PortSwigger CSRF Token Bypass Labs— PortSwigger’s guided CSRF bypass labs covering token validation weaknesses, SameSite cookie bypass, and Referer-based protection flaws in real application contexts.
The XSS+CSRF chain was the finding that first made me understand why vulnerability chaining changes the entire value equation in web security. On a client engagement, I found a stored XSS in a user-profile bio field rated Medium by the automated scanner. The same application had a CSRF-protected account deletion endpoint. I chained them: anyone who viewed an attacker’s profile had their account deleted automatically. Individually, the XSS was Medium and the CSRF was High — both worth reporting but neither world-ending. Chained, it was a single stored payload that would silently delete every account of every user who visited the attacker’s profile. The client’s security team went from “we’ll patch this next sprint” to “we need an emergency deployment today.” That’s the power of demonstrating combined impact rather than individual findings.
Founder of Securityelites and creator of the SE-ARTCP credential. Working penetration tester focused on AI red team, prompt injection research, and LLM security education.