CSRF — the notifications toggle

Cross-Site Request Forgery
account settings — notifications
Email notifications: ENABLED Disable
GET /csrf/lab22/?enabled=false HTTP/1.1

Cookie: (your session rides along — nothing else is checked)

Read the request like a repeater send: the action is enabled, and there is no token anywhere — not in the query, not a user nonce, nothing the attacker couldn't predict. Nothing user-specific means nothing binds this request to "the user asked for this".

what a defended request looks like (next labs' prey)
GET    /csrf/lab22/?enabled=false&token=a91f2c…<unique-for-user>
POST   /csrf/lab22/          body: enabled=false&auth_token=7be0d1…   (the same idea inside the body)
API    header: X-CSRF-Token: 4d1f8a…   (hardest to bypass — the token is not in the URL)

Tokens make attackers rely on a leak or a flaw for every single request they want to force. GET-token, POST-body-token, and API-header token are three escalating grades — each has its own bypass tricks (own labs later in the category).

is this worth reporting? — severity follows the ACTION
toggle notificationslow – medium
change email addresscritical (prerequisite for account takeover)
reset / change passwordcritical (account takeover)
mint a new API keycritical (data + infra abuse)
move moneycritical (direct loss, at scale)

Hunters cherry-pick: notification toggles are rarely worth the report; email/password/API-key/transfer actions are. Decide "is this worth a CSRF attack at all" before you write the POC.

Method — check, build, validate cross-account
  1. Find an action first ("anything that takes a form or changes state"), then send the request to repeater (Ctrl/Cmd-R) and read it: query token? body token? header token? Nothing at all = candidate.
  2. Confirm the request is replayable: it must work with only the same-origin cookies — no nonces, no user-specific values anywhere in it.
  3. Build a proof of concept and host it outside the target. Modern browsers complicate local testing: the image-tag POC must go HTTPS→HTTPS (Chrome filters it out of local/file:// pages), while a plain hyperlink POC works from anywhere — even pasted in an address bar or chat link.
  4. Image-tag POC fires on visit (no click); the form POC fires on submit; the hyperlink needs user navigation — different trigger guarantees go into different reports.
  5. The two-account ritual: perform the action on account A, build the POC from A's request, then open it in a second browser logged into account B. Works? Token reused, removed, or never needed — report it exactly like you demonstrated it.
  6. Frame the report by impact: "forced action X via CSRF" + what X enables. A toggle nobody's harmed by is a demo, not a finding.
Spoiler — the three POC variants (exactly as demonstrated)
<img src="https://stuxnet.pro/csrf/lab22/?enabled=false">   (fires on visit — needs HTTPS host)
<a href="https://stuxnet.pro/csrf/lab22/?enabled=false">test POC</a>   (works anywhere, needs a click)
<form method="GET" action="https://stuxnet.pro/csrf/lab22/">
  <input type="hidden" name="enabled" value="false">
  <button type="submit">Send</button>
</form>

The form is the instructor's preferred POC. Note the quirk it dodges: a GET form replaces the action URL's query string with its own inputs — so the action carries a PATH ONLY and the parameters live in hidden inputs. Flip the boolean to whatever harms the account (the toggled value here was restored behind the scenes — the state chip above always shows the current truth).

Spoiler — why this works with no cookies at all (sandbox note)

On the course site the settings are a shared sandbox: the toggle changes globally, so no victim session is simulated. The accountable mechanics are identical everywhere: the request carries NO unguessable input — CSRF-proofing means tenant-binding (token, nonce, SameSite cookies) — and that absence is exactly what you document. On a real target the POC fires from another site while the victim's own cookies authenticate it, and the state change lands on the victim's account.