Cross Site Request Forgery (CSRF) in DVWA

Introduction
Cross-Site Request Forgery (CSRF) is a web vulnerability that allows attackers to perform unauthorized actions on behalf of an authenticated user, often without the victim ever realizing it.
This post demonstrates how a CSRF vulnerability in the Damn Vulnerable Web Application (DVWA) can be exploited to manipulate application functionality and compromise user accounts.
CSRF occurs when a web application processes a request without verifying whether it was intentionally initiated by the user. Because browsers automatically include session cookies with every request, an attacker can trick a victim into unknowingly sending a malicious request that appears legitimate to the server.
Unlike Cross-Site Scripting (XSS), CSRF does not rely on injecting code into the application. Instead, it exploits the trust between the user’s browser and the web application.
Successful CSRF attacks may allow an attacker to:
Perform actions on behalf of the victim
Modify account data (e.g. passwords or email addresses)
Execute unauthorized transactions
Ultimately compromise user accounts
This analysis evaluates the vulnerability across three DVWA security levels: Low, Medium, and High.
A screencast demonstrating the attack process can be viewed below:
https://www.youtube.com/watch?v=-3ABYpt5tfI
Attack Overview
| Parameter | Description |
|---|---|
| Target application | DVWA |
| Vulnerability class | Cross-Site Request Forgery (CSRF) |
| CWE | CWE-352: Cross-Site Request Forgery |
| OWASP Top 10 | A01:2025 Broken Access Control |
| Attack vector | Network (via crafted requests and XSS chaining) |
| Security levels tested | Low, Medium, High |
| Tools used | Browser Developer Tools, Burp Suite, Kali Linux |
| Impact | Unauthorized state-changing actions (password reset), potential account takeover |
Lab Environment
| Component | Configuration |
|---|---|
| Virtualization platform | Oracle VirtualBox |
| Attacker system | Kali Linux |
| Target system | Ubuntu Server 24.04 LTS |
| Application stack | Apache2, PHP 8.3.x, MariaDB |
| Vulnerable application | Damn Vulnerable Web Application (DVWA) |
| Network configuration | Host-only isolated network |
Vulnerability description
The vulnerability exists because the application processes sensitive state-changing requests while relying on the browser session to identify the user, but without sufficiently verifying whether the request was intentionally made by that user.
In the CSRF module, the password change functionality updates the password for the currently authenticated user. Because browsers automatically include session cookies with requests, the server treats the request as legitimate as long as it is received in the context of an authenticated session.
At the Low security level, no protection is implemented, which allows the attack to be carried out using a crafted URL alone.
At the Medium security level, the application attempts to validate the HTTP_REFERER header. However, this is insufficient because requests executed from within the application itself satisfy the check. This makes it possible to bypass the protection by chaining the vulnerability with reflected XSS.
At the High security level, the application introduces a session-bound anti-CSRF token. This significantly improves the protection, as the attacker must now obtain a valid token before a forged request can succeed.
Figure 1: DVWA attack entry point.
Low Security Level
At the Low security level, the application is vulnerable to Cross-Site Request Forgery (CSRF) because it performs a state-changing action based solely on user-controlled input, without verifying the legitimacy of the request.
When a password change is submitted, the application reads the new password directly from the URL parameters and applies the change to the currently authenticated user. The user is identified through the session:
$current_user = dvwaCurrentUser();
This means the application trusts the active session and does not validate whether the request was intentionally made by the user.
Additionally, the application:
Uses the GET method for a sensitive operation
Does not include a CSRF token
Performs no origin or referrer validation
Does not require re-authentication
Because of this, any request sent from the victim’s browser while they are authenticated will be treated as legitimate.
In a real CSRF attack, the attacker does not need direct access to the application. Instead, they trick the victim into visiting a malicious page.
When the victim loads this page, their browser automatically sends a forged request to the vulnerable application (for example, via an <img> tag). Since the victim is already logged in, their session cookie is included automatically.
As a result, the server processes the request as if it were initiated by the user, leading to unintended actions such as a password change.
Attack steps
- Submit a password change request through the application.
2. Observe that the request is sent using the HTTP GET method, with the new password values exposed in the URL, see Figure 2.
Figure 2: The request showing that the password values are exposed in the URL.
3. Copy the generated URL and identify the required parameters: password_new, password_conf, and Change.
4. Modify the request to include attacker-controlled values:
http://192.168.56.3/DVWA/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change
5. While authenticated, access the crafted URL and verify that the password is successfully changed.
Figure 3: The modified request showing attacker-controlled values in the URL.
6. Create a malicious HTML page that automatically triggers the same request:
<html>
<body>
<img src="http://192.168.56.3/DVWA/vulnerabilities/csrf/? password_new=hacked&password_conf=hacked&Change=Change">
</body>
</html>
7. When the page is loaded by an authenticated user, the browser automatically sends the forged request using the user’s session.
Result
The password is changed without the user intentionally submitting the password change form. This demonstrates that the application accepts state-changing requests without CSRF protection and is therefore vulnerable to CSRF.
Medium Security Level
At the Medium security level, the application attempts to mitigate Cross-Site Request Forgery (CSRF) by validating the HTTP_REFERER header:
if( stripos( \(_SERVER[ 'HTTP_REFERER' ] ,\)_SERVER[ 'SERVER_NAME' ]) !== false )
This check is intended to ensure that the request originates from the same application by verifying that the referer contains the server name.
However, this approach is fundamentally flawed. The HTTP_REFERER header is a client-controlled value and should not be relied upon as a security mechanism.
While this mitigation may block basic CSRF attacks from external websites, it does not provide robust protection. The application does not enforce strict origin validation, but instead performs a simple substring check, which can be bypassed under certain conditions.
Unlike the Low security level, where a CSRF attack can be performed directly from an external page, the Medium level requires the request to appear as if it originates from the application itself.
One reliable way to bypass this restriction is by leveraging a Cross-Site Scripting (XSS) vulnerability within the application.
By injecting JavaScript into the application, the attacker can execute code in the context of the trusted domain. Any requests generated by this script will automatically include a valid referer header and satisfy the server-side validation.
Attack steps
1. Navigate to the reflected XSS module.
Figure 4: The Reflected XSS module where user input is reflected and can be exploited.
2. Craft a payload that leverages the XSS vulnerability to trigger a CSRF request:
<ScRiPt>document.location='/DVWA/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change'</ScRiPt>
3. Submit the payload through the reflected XSS functionality.
4. When the payload is executed, the browser automatically redirects to the CSRF endpoint and submits the password change request. The request is executed in the context of the authenticated user’s session.
5. Because the request originates from the same domain, the referer-based validation is satisfied and the request is accepted as legitimate.
Figure 6: CSRF request successfully triggered via reflected XSS.
Result
The password is successfully changed without the user's explicit interaction with the password change functionality.
This demonstrates that referer-based protection is insufficient and can be bypassed by executing requests within the application's own origin, for example via XSS.
High Security Level
At the High security level, the application implements a proper anti-CSRF mechanism by requiring a valid, session-bound token (user_token) for all state-changing requests.
The token is validated server-side:
checkToken( \(token, \)_SESSION[ 'session_token' ], 'index.php' );
This ensures that only requests originating from the legitimate application workflow and containing the correct token are accepted.
Unlike the Medium level, which relies on referer validation, the High level introduces a synchronizer token pattern.
A valid request must include:
password_newpassword_confChangeuser_token(valid and session-specific)
This prevents attackers from crafting arbitrary requests, as the token cannot be predicted or reused across sessions.
Attempted Exploitation
A reflected XSS vulnerability was used to execute JavaScript within the application context.
The following payload was tested:
<img src=x onerror="document.location='/DVWA/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked&Change=Change'">
However, the attack failed because the request did not include a valid user_token.
Result
The password was not modified.
The server rejected the request due to the missing or invalid CSRF token. This demonstrates that token-based protection effectively mitigates basic CSRF attacks.
Why XSS Alone Is No Longer Sufficient
Although XSS allows execution of arbitrary JavaScript within the application, simple payloads are not sufficient to bypass CSRF protections.
A successful attack would require:
Requesting the CSRF page
Extracting the
user_tokenfrom the responseCrafting a valid request including the token
Sending the request using the victim’s session
Practical Limitation in This Lab
In this lab environment, the reflected XSS context limits payload complexity. While basic JavaScript execution is possible, more advanced payloads required for token extraction and request chaining are not reliably executed.
As a result, a full exploit chain could not be successfully implemented.
Attack Methodology
This section maps the attack process to the Cyber Kill Chain model.
Reconnaissance
During analysis of the DVWA application, the password change functionality was identified as a potential attack surface.
Sensitive operations triggered via predictable HTTP requests are commonly associated with CSRF vulnerabilities.
By observing request behavior, it was determined that:
User identity is derived from the session
Input is taken directly from request parameters
At higher security levels, additional controls were observed:
Medium: referer validation
High: anti-CSRF tokens
Weaponization
To test the vulnerability, malicious requests were prepared that attempted to change the password of the currently authenticated user.
At the Low security level, the attack used a crafted URL and an HTML page containing an <img> element to trigger the request automatically.
At the Medium security level, the attack was combined with reflected XSS in order to execute JavaScript within the context of the application and bypass the referer-based protection.
At the High security level, exploitation required a more advanced chain involving token extraction and reuse.
Delivery
The payload delivery varied by security level:
Low: Direct link or malicious HTML page
Medium: Delivered via reflected XSS within the application
High: Would require XSS capable of executing multi-step JavaScript
Exploitation
When the victim loaded the malicious page or payload while authenticated, the browser issued the forged request together with the active session cookie.
At the Low level, this was sufficient to change the password.
At the Medium level, the request was accepted because it originated from the same domain and therefore satisfied the referer validation.
At the High level, the request failed without a valid anti-CSRF token, demonstrating that the protection significantly increased the complexity of exploitation.
Installation
No persistence was established in this attack.
The malicious action occurred only when the forged request was executed in the victim’s browser session.
Command and Control
This step was not applicable in this context. However, if combined with XSS, an attacker could establish communication with an external server to exfiltrate data such as tokens or session information.
Actions on Objectives
The attacker successfully changes the password of the authenticated user (Low and Medium levels). This represents a compromise of account integrity and could lead to full account takeover.
Impact Analysis (CIA)
The vulnerability primarily compromises integrity, as it allows an attacker to perform unauthorized state-changing actions on behalf of the victim.
In this lab, the demonstrated impact is a forced password change, which directly modifies account data without the user’s consent. In real-world scenarios, similar attacks could be used to change email addresses, update account settings, submit transactions, or perform other unauthorized actions.
Confidentiality can also be impacted indirectly. If an attacker successfully changes a victim’s password, this can lead to account takeover and unauthorized access to sensitive information associated with the account.
The impact on availability is generally limited and indirect. CSRF does not directly affect system uptime or infrastructure. However, unauthorized changes such as password resets may lock users out of their accounts, effectively denying access and creating a secondary availability impact.
Severity Assessment (CVSS v3.1)
The severity of this vulnerability was assessed using the Common Vulnerability Scoring System.
| Metric | Value |
|---|---|
| CVSS Version | CVSS v3.1 |
| Base Score | 6.8 (Medium) |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | Required |
| Scope | Unchanged |
| Confidentiality Impact | Low |
| Integrity Impact | High |
| Availability Impact | Low |
Mitigation strategies
The vulnerability demonstrated in this lab exists because the application accepts sensitive state-changing requests without verifying that they were intentionally initiated by the authenticated user.
Preventing CSRF requires the server to validate both the authenticity of the request and the context in which it is made.
Several defensive measures can significantly reduce the risk of CSRF vulnerabilities:
Use anti-CSRF tokens that are unique, unpredictable, and tied to the user’s session. Tokens should ideally be generated per request or per form submission.
Avoid using HTTP GET for state-changing operations. Instead, use POST requests with appropriate content-type validation.
Perform strict server-side validation of requests. Do not rely on client-controlled headers such as
HTTP_REFERER.Require re-authentication or password confirmation for sensitive operations such as password changes or financial transactions.
Use cookie attributes such as
SameSiteto restrict cross-site request behavior. Additional flags such asSecureandHttpOnlyshould also be used to strengthen overall session security.Prevent Cross-Site Scripting (XSS) vulnerabilities, as XSS can be used to bypass CSRF protections by extracting tokens or executing authenticated requests within the application context.
A defense-in-depth approach is essential. While anti-CSRF tokens provide strong protection, they may be undermined if other vulnerabilities, such as XSS, are present.
Secure Implementation Example
At the Impossible security level, the application implements a significantly stronger defense against CSRF by combining anti-CSRF protection with additional verification of user intent.
Unlike the previous levels, the password change functionality no longer relies solely on session state and request parameters. Instead, the application requires:
a valid session-bound anti-CSRF token (
user_token)the user’s current password
matching new password values
The anti-CSRF token is validated server-side:
checkToken( \(_REQUEST['user_token'], \)_SESSION['session_token'], 'index.php' );
This prevents arbitrary forged requests from being accepted unless they include a valid token associated with the victim’s session.
In addition, the application requires the user to provide their current password:
\(pass_curr = \)_GET['password_current'];
The submitted password is then checked against the database for the currently authenticated user:
SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;
This introduces an important second layer of protection. Even if an attacker were somehow able to obtain a valid CSRF token, the password change would still fail unless the attacker also knew the victim’s current password.
The application also verifies that the new password and confirmation match before updating the account.
Overall, this implementation is more secure because it does not rely on a single defense mechanism. Instead, it applies multiple server-side controls that validate both the authenticity of the request and the legitimacy of the action being performed.
This demonstrates a defense-in-depth approach: the anti-CSRF token protects against forged requests, while current-password verification protects sensitive account changes even if other client-side controls are bypassed.
Figure 7: The form for impossible security level.






