
// TL;DR
On a private program (I’ll call the target redacted.com), I went looking for an email-change CSRF. The email-change action was protected against CSRF on POST — but the same action answered to GET with no protection. The surprise: supplying a new email value didn’t change the email to it; the GET request simply voided the existing email, leaving the account with none. Since email is the login identifier, that effectively deletes the account — the victim can’t log back in once they sign out. So a single crafted link, opened by a logged-in victim, wipes their email and locks them out of their own account for good. Reported and rewarded a $450 bounty.
What is CSRF?
Cross-Site Request Forgery (CSRF) tricks a logged-in user’s browser into making a state-changing request they didn’t intend. Because the browser automatically attaches the victim’s session cookies, the target site sees a perfectly authenticated request and acts on it. The standard defence is a per-request anti-CSRF token that an attacker’s page can’t know or guess.
The target had that protection — but it wasn’t applied everywhere it needed to be.
The bypass: POST protected, GET wasn’t
I was testing the email-change feature for CSRF. The action was protected against CSRF when submitted as a POST request — but the same action was also reachable over GET, and the GET path wasn’t enforcing the protection.
That’s the whole bug. Instead of fighting the CSRF token on the POST request, I expressed the same email change as a GET request in the URL:
https://redacted.com/account/profile/edit/?field_name=email&new_value=hacker@yopmail.com
field_name picks the field and new_value is supposed to be the new value. Here’s the twist: even though I supplied a new_value, the email didn’t update to it — the request simply voided the existing email, leaving the field empty. So the bypass didn’t let me set an attacker-controlled email; it let me erase the victim’s email. Delivered as a plain URL, it’s trivially weaponisable — a logged-in victim only has to open the link (embedded in an image, an iframe, a redirect, a shortened link) and their browser fires the authenticated GET with no token required.

From “edit” to “wipe the account”
Here’s the important nuance: I went in looking for a standard email-change CSRF (set the victim’s email to mine → take over the account). It didn’t work that way. The supplied new_value was ignored — instead the GET request voided the email field, leaving the account with no email address associated with it at all. The account info was effectively deleted, not changed to an attacker’s address.
That’s the sharp edge: on Slader, the email is what you log in with. Once it’s wiped:
- The victim’s profile data is cleared without their consent.
- With no email left on the account, as soon as the victim logs out they can’t log back in — the identifier they used to authenticate no longer exists on the account.
- The account is effectively deleted/blocked from the owner’s point of view, and they lose access entirely.
So a “profile edit” CSRF escalated into wiping the user’s account info and locking the owner out for good — delivered by a single link.
Replication
- Create and log in to an account on the target.
- In the same browser, visit:
https://redacted.com/account/profile/edit/?field_name=email&new_value=hacker@yopmail.com - Open your settings — the account now has no email associated with it.
- Log out. You can no longer log back in with the previous credentials.
In a real attack, step 2 is simply a link the attacker gets the victim to open while logged in.
The fix
The root issue is that a state-changing action was reachable over a method the CSRF protection didn’t cover:
- Enforce anti-CSRF tokens on every method that changes state — don’t protect
POSTwhile leavingGETopen to the same handler. - Never allow state changes over
GET. GET requests should be safe/idempotent; account mutations belong behind POST (or PUT/PATCH) with token validation. A profile edit should never happen just by loading a URL. - Validate the token server-side on the action, not on the surface form, so an alternate method or content type can’t skip it.
Takeaways
- CSRF protection is only as good as its weakest method. If
POSTis guarded but the same action answers toGET, the protection is bypassed — always test the other HTTP methods against a protected endpoint. - “Can’t set a useful value” isn’t “no impact.” Even if the bypass can only wipe fields rather than set attacker-chosen ones, wiping the login identifier (email) deletes the account’s info and locks the owner out permanently — frame that impact clearly in the report.
- A GET-based state change is a CSRF gift. Anything that mutates an account from a bare URL can be delivered in an
<img>, iframe, or link with zero victim interaction beyond a page visit.
Thanks for reading — hope it was useful. Happy hacking!
Leave a Reply