CSRF
Cross-Site Request Forgery — the browser sends the cookie automatically. An img tag on a forum triggers a password change on a bank the victim left open in another tab.
Cross-Site Request Forgery — the browser sends the cookie automatically. An img tag on a forum triggers a password change on a bank the victim left open in another tab.
Cross-Site Request Forgery (CSRF) exploits the browser's automatic cookie inclusion. When a user is authenticated to a website, that site's cookies are sent with every request to its origin — even if the request originates from an attacker's page. A single <img> tag can trigger a state-changing action on a site the victim left open in another tab.
When a user visits a page on an attacker-controlled site, the attacker can embed HTML elements that trigger requests to other origins. The most common vector is a simple image tag: <img src="https://bank.com/transfer?amount=1000&to=attacker" />. The browser makes a GET request to the bank's server — and since the user has an active session cookie for the bank, the cookie is included automatically. If the bank's transfer endpoint accepts GET requests, the transfer executes.
POST-based CSRF uses a hidden form that auto-submits: <form action="https://bank.com/transfer" method="POST">. The attacker pre-fills the form fields and submits it via JavaScriptform.submit(). The browser sends the POST request with the user's cookies, and the server cannot distinguish this from a legitimate form submission.
The sandbox below shows two browser tabs side by side: a victim logged into a banking app and an attacker-controlled page. Toggle the SameSite cookie protection to see how the bank website can be protected against CSRF attacks.
<img
src="bank.com/transfer?
amount=1000&
to=attacker-account-999"
width="0"
height="0"
/>In 2008, a critical CSRF vulnerability was discovered in uTorrent's web UI. The BitTorrent client exposed a web-based management interface on localhost:8080 that accepted commands via GET requests. An attacker could craft a page with image tags pointing to URLs like http://localhost:8080/gui/?action=download&url=magnet:.... Since the browser treats localhost as a valid origin and uTorrent used cookie-based auth, any website could force the victim's uTorrent client to download arbitrary files.
The attack was compounded by the fact that uTorrent had a "settings" endpoint that could modify the application's startup script path, effectively allowing remote code execution. The uTorrent case demonstrates that CSRF is not limited to web applications — any service with an HTTP interface and cookie-based auth is vulnerable.
Modern browsers ship three CSRF defences. Use all of them.
// VULNERABLE — GET request transfers money
app.get('/transfer', async (req, res) => {
await db.transfer(req.query.amount, req.query.to);
res.send('OK');
});
// SAFE — only accept POST with SameSite cookie + CSRF token
app.post('/transfer', parseForm, csrfProtection, async (req, res) => {
await db.transfer(req.body.amount, req.body.to);
res.send('OK');
});
// SAFE cookie config
Set-Cookie: session=abc123; SameSite=Lax; HttpOnly; Secure
// SAFE custom header check (reject if missing X-Requested-With)
app.use((req, res, next) => {
if (req.method !== 'GET' && !req.headers['x-requested-with']) {
return res.status(403).send('CSRF protection');
}
next();
});Additional layers: never use GET for state-changing operations; require a custom header like X-Requested-With (which cross-origin requests from simple HTML elements cannot set); and use the Double Submit Cookie pattern where a cryptographically random CSRF token is set as a non-HttpOnly cookie and must also be sent in a custom header.
<img>, <script>, or hidden form can trigger a GET or POST request that the server treats as legitimate user action.1.What makes CSRF possible?
2.Which SameSite cookie setting blocks all cross-site cookie sends, including GET requests?
3.Why does a custom header like X-Requested-With provide CSRF protection?