CSRF in Express.js Applications
Express.js provides no built-in CSRF protection. Applications using cookie-based sessions (express-session, passport) are vulnerable to CSRF attacks unless they implement token validation, SameSite cookies, or Origin header checking.
Scan Your Express AppHow CSRF Manifests in Express
Express apps using cookie-based authentication are CSRF-vulnerable by default. Common patterns include: Session cookies from express-session or passport.js are automatically sent with cross-origin requests. Any state-changing endpoint (POST, PUT, DELETE) that relies on these cookies can be forged. APIs that serve both a web frontend and external clients often skip CSRF protection for the API, assuming tokens will be used. But if cookies are also accepted, CSRF is possible.
Real-World Impact
An Express admin panel used passport.js for authentication with session cookies. An attacker sent the admin a link to a page containing hidden forms that changed user roles, deleted accounts, and exported data. All requests succeeded because the admin's session cookie was sent automatically.
Step-by-Step Fix
Implement CSRF tokens with csrf-csrf
Use the csrf-csrf package (replacement for deprecated csurf).
import { doubleCsrf } from 'csrf-csrf';
import express from 'express';
import cookieParser from 'cookie-parser';
const app = express();
app.use(cookieParser('your-secret'));
app.use(express.urlencoded({ extended: true }));
const { doubleCsrfProtection, generateToken } = doubleCsrf({
getSecret: () => 'your-csrf-secret',
cookieName: '__csrf',
cookieOptions: { sameSite: 'lax', secure: true },
});
// Apply to all state-changing routes
app.use(doubleCsrfProtection);
// Provide token to forms
app.get('/form', (req, res) => {
const token = generateToken(req, res);
res.render('form', { csrfToken: token });
});Set SameSite cookies
Configure session cookies with SameSite to prevent cross-origin submission.
import session from 'express-session';
app.use(session({
secret: process.env.SESSION_SECRET!,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 24 * 60 * 60 * 1000,
},
}));Validate Origin header
Check Origin/Referer on mutation requests as an additional defense layer.
function csrfOriginCheck(req, res, next) {
if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
return next();
}
const origin = req.headers.origin || req.headers.referer;
const allowed = process.env.ALLOWED_ORIGIN || 'https://yourdomain.com';
if (!origin || !origin.startsWith(allowed)) {
return res.status(403).json({ error: 'CSRF validation failed' });
}
next();
}
app.use(csrfOriginCheck);Prevention Best Practices
1. Use the csrf-csrf or csrf-sync package for CSRF token validation. 2. Set SameSite=Lax on all session cookies. 3. Validate Origin and Referer headers on state-changing requests. 4. Use separate authentication for API (Bearer tokens) vs web (cookies + CSRF). 5. Add CSRF tokens to all forms and AJAX requests.
How to Test
1. Create a cross-origin HTML form that POSTs to your Express endpoints. 2. Open the form while logged in to your app and check if the request succeeds. 3. Verify session cookies have SameSite=Lax or Strict. 4. Check if CSRF tokens are required for all POST/PUT/DELETE endpoints. 5. Use Vibe App Scanner to detect missing CSRF protections in your Express application.
Frequently Asked Questions
Is the csurf package still recommended for Express?
No. The csurf package has been deprecated due to security issues. Use csrf-csrf (double submit cookie pattern) or csrf-sync (synchronizer token pattern) instead. Both are actively maintained and provide robust CSRF protection.
Do I need CSRF protection for an Express REST API?
If your API uses cookie-based authentication (session cookies), yes. If it uses only Bearer tokens (JWT in Authorization header), CSRF is not a concern because cross-origin requests cannot set custom headers. Many APIs use both, in which case CSRF protection is needed.
Does CORS prevent CSRF in Express?
No. CORS controls which origins can read responses, not which can send requests. A cross-origin form submission bypasses CORS entirely because form submissions do not trigger preflight checks. CORS and CSRF protection serve different purposes.
Related Security Resources
Is Your Express App Vulnerable to CSRF?
VAS automatically scans for csrf vulnerabilities in Express applications and provides step-by-step remediation guidance with code examples.
Scans from $5, results in minutes. Get actionable fixes tailored to your Express stack.