CWE-352HighMITRE entry

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF)

What it is

CWE-352 occurs when a web application accepts state-changing requests from a user without verifying that the user actually intended to make the request. An attacker hosts a page that issues a request to the target site; if the victim is authenticated and the target site does not check origin, referrer, or a CSRF token, the request executes with the victim's credentials.

Why it matters

CSRF is one of the longest-standing entries in the OWASP Top 10 (most recently consolidated under A01:2021 Broken Access Control). Successful exploitation lets an attacker transfer funds, change passwords, add admin users, post content, or trigger any other state change the victim is authorized to perform. Modern browsers ship SameSite=Lax cookies by default, which mitigates many cross-origin POST attacks, but GET-based state changes and same-site iframes remain exploitable when CSRF tokens are missing.

Common patterns

  • State-changing endpoints (POST, PUT, DELETE, PATCH) without CSRF token validation.
  • Cookies issued without the SameSite attribute, or with SameSite=None and no Secure flag.
  • Endpoints that perform state changes on GET (a CWE-650 overlap).
  • Custom session middleware that forgets to verify a per-session CSRF token.
  • API endpoints that authenticate via cookies but accept cross-origin requests via permissive CORS.

Languages affected

JavaScriptTypeScriptPythonRubyJavaGoPHP

What Deva detects

Deva flags Express, Koa, Flask, Django, and Rails route handlers that perform writes without a CSRF middleware (csurf, lusca, django-csrf, Rails protect_from_forgery). The scanner also detects cookie-set calls that omit SameSite, and CORS configurations that allow credentials with a wildcard origin. For SPAs that use Authorization headers instead of cookies, Deva treats the route as exempt because tokens are not auto-attached by browsers.

Example

Vulnerable

import express from 'express'
import session from 'express-session'

const app = express()
app.use(session({ secret: 'k', resave: false, saveUninitialized: false }))

app.post('/account/email', (req, res) => {
  req.session.user.email = req.body.email
  res.json({ ok: true })
})

Fixed

import express from 'express'
import session from 'express-session'
import csurf from 'csurf'

const app = express()
app.use(session({
  secret: 'k',
  resave: false,
  saveUninitialized: false,
  cookie: { sameSite: 'lax', secure: true, httpOnly: true },
}))
app.use(csurf())

app.get('/csrf-token', (req, res) => {
  res.json({ token: req.csrfToken() })
})

app.post('/account/email', (req, res) => {
  // csurf middleware already validated req.body._csrf
  req.session.user.email = req.body.email
  res.json({ ok: true })
})

Explanation

The vulnerable version accepts a POST to change the account email without any anti-forgery defense. An attacker's page issues a cross-origin POST with the victim's cookies attached and changes the email. The fix sets SameSite=Lax (defense in depth), requires CSRF tokens on writes, and exposes a /csrf-token endpoint so the SPA can attach the token to subsequent POSTs.

Where this fits in OWASP Top 10

Compliance framework mapping

FrameworkControls
OWASP Top 10 (2021)
A01:2021 Broken Access Control
NIST 800-53 Rev 5
AC-4 Information Flow EnforcementSI-10 Information Input Validation
PCI-DSS v4.0
6.2.4 Software engineering techniques
CMMC 2.0 L2
AC.L2-3.1.3 CUI flow control

Related CWEs

Deva detects CWE-352 alongside 970+ other CWE patterns at write time, with AI-assisted fix generation that maintains compliance.