The Ravens’ control panel lets the leader change his recovery email. The page accepts the request on the session cookie alone, with no extra token. The leader is always logged in, and the falcon wants to set his own email in place of the leader’s to take over the account.
The Ravens control panel is an app on panel.ravens.lab where the leader changes his recovery email. The page accepts the request on the session cookie alone, with no extra token. You pick how the forged request is delivered from the attacker page: an auto-submitting form (POST), an image that loads a URL (GET), or a link the leader opens himself (GET). The app shows whether the browser attached the session cookie, and why.
Build an attacker page that sends a forged request changing the leader’s recovery email to yours, and deliver it to him.
The forged request changed the leader’s recovery email to the attacker’s.
Why the solution worked
This is CSRF: a forged cross-site request. The page trusted the session cookie alone, and the browser attaches that cookie automatically to any request to the panel, so any site can send a request as the leader. The fix: a per-session CSRF token sent with every state-changing request and verified on the server (the attacker cannot read it from another site), plus SameSite=Lax or Strict on the session cookie.
The root cause
The server trusts the session cookie alone as proof of user intent, and the cookie is attached automatically on cross-site requests, so nothing proves the request started from the site own page.
How the code is fixed
Cookies are attached automatically, which is what makes CSRF possible. A secret token breaks that: it is not a cookie, is not sent automatically, and another site cannot read it.
Vulnerable code
app.post('/settings', (req, res) => {
// Trusts the session cookie alone: any site can trigger this.
if (!req.session.user) return res.status(401).end();
db.setRecoveryEmail(req.session.user, req.body.email);
res.end('updated');
});
Safe code
app.post('/settings', (req, res) => {
if (!req.session.user) return res.status(401).end();
// A per-session token the attacker on another site cannot read.
if (req.body.csrf !== req.session.csrfToken) return res.status(403).end();
db.setRecoveryEmail(req.session.user, req.body.email);
res.end('updated');
});
// Cookie: Set-Cookie: session=...; SameSite=Lax; HttpOnly; Secure
Impact in the real world
CSRF performs actions as the victim — changing an email, moving money, changing settings — the moment the victim opens the attacker page, and has led to full account takeover.
How defenders detect it
Defenders check the Origin and Referer headers on state-changing requests and alert on change requests without a valid CSRF token.