Authorization disclaimer. This walkthrough is limited to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or are explicitly authorized to assess.

Overview

The exercise isolates a CSRF enforcement gap: pOST /my-account/change-email includes csrf; converting it to GET first reports a missing email, then GET /my-account/change-email?email=hacked@hacker.com returns 302 and changes the email. The important evidence is the browser’s cookie and navigation behavior, not merely that a cross-site form can be submitted.

Lab objective/setup

Exercise CSRF where token validation depends on request method through the endpoint and input recorded in the lab note. POST /my-account/change-email includes csrf; converting it to GET first reports a missing email, then GET /my-account/[email protected] returns 302 and changes the email.

What I observed

POST /my-account/change-email includes csrf; converting it to GET first reports a missing email, then GET /my-account/[email protected] returns 302 and changes the email.

Lab description states that CSRF defenses are applied only to certain request types.
Lab description states that CSRF defenses are applied only to certain request types.
My Account shows the email-change form for user wiener.
My Account shows the email-change form for user wiener.
The HTTP history shows the protected POST /my-account/change-email request with the csrf body parameter.
The HTTP history shows the protected POST /my-account/change-email request with the csrf body parameter.
Changing the request to GET without an email parameter returns 400 Bad Request with “Missing parameter ‘email’”.
Changing the request to GET without an email parameter returns 400 Bad Request with “Missing parameter ‘email’”.

Why it is vulnerable

POST /my-account/change-email includes csrf; converting it to GET first reports a missing email, then GET /my-account/[email protected] returns 302 and changes the email. The application passes that value into the security-sensitive operation without the context-specific validation or encoding needed to prevent this result.

Walkthrough in the authorized PortSwigger lab

Recreate the account-change flow, establish the normal request’s token and cookie requirements, then alter only the method, token presence, cookie age, redirect path, or sibling-origin step named in the evidence. The goal is to show exactly where the browser still supplies authority to the forged request.

GET /my-account/change-email?email=... succeeds without csrf validation and returns 302 Found.
GET /my-account/change-email?email=... succeeds without csrf validation and returns 302 Found.
My Account displays abc@example.com, confirming the tokenless GET changed the email.
My Account displays [email protected], confirming the tokenless GET changed the email.
The exploit-server editor contains an auto-submitting method=GET form targeting /my-account/change-email with only the email field.
The exploit-server editor contains an auto-submitting method=GET form targeting /my-account/change-email with only the email field.
The Academy banner for “CSRF where token validation depends on request method” shows Solved.
The Academy banner for “CSRF where token validation depends on request method” shows Solved.

Verification

The lab is confirmed when POST /my-account/change-email includes csrf; converting it to GET first reports a missing email, then GET /my-account/[email protected] returns 302 and changes the email. The captured result and the Academy solved state provide the verification; an ordinary status code alone does not.

Impact and defensive lesson

A production attacker could change victim account data while relying on ambient cookies. Validate CSRF tokens on every state-changing route and method, bind them to the authenticated session, set deliberate SameSite attributes, and remove redirect or sibling-origin gadgets that turn same-site navigation into cross-site request authority.

References