← All posts
CSRF protectionNext.jsvibe codingAI-coded appssecurity

How to Fix Missing CSRF Protection in AI-Coded Next.js Apps

O

OverMCP Team

Quick answer

CSRF protection is often missing in AI-coded Next.js apps because AI tools generate minimal server actions and API routes without anti-forgery tokens. To fix it, add a CSRF token using middleware or a library like csrf-csrf, and validate it on every state-changing request. This prevents attackers from tricking authenticated users into executing unwanted actions.

What to check first

Before adding CSRF protection, verify your app's current state:

  • [ ] Are you using Next.js server actions or API routes for form submissions?
  • [ ] Do your server actions or API routes check for a CSRF token?
  • [ ] Are your forms including a hidden CSRF token field?
  • [ ] Is your app using cookie-based authentication (like NextAuth.js)?
  • [ ] Have you tested with a tool like OverMCP's free AI app security scanner to detect missing CSRF protection?
  • If you answered "no" to any of these, your app is vulnerable.

    Step-by-step fix

    1. Install a CSRF library

    For Next.js App Router, a lightweight option is csrf-csrf:

    npm install csrf-csrf

    2. Create a CSRF middleware

    In src/middleware.ts, generate and validate tokens:

    import { NextRequest, NextResponse } from 'next/server';
    import { createCsrfMiddleware } from 'csrf-csrf';
    
    const { csrfMiddleware, csrfToken } = createCsrfMiddleware({
      cookie: { name: 'csrf-token', sameSite: 'strict' },
      header: 'x-csrf-token',
    });
    
    export function middleware(request: NextRequest) {
      // Protect all API routes and server actions
      if (request.nextUrl.pathname.startsWith('/api') || request.method !== 'GET') {
        return csrfMiddleware(request, NextResponse.next());
      }
      return NextResponse.next();
    }
    
    export const config = {
      matcher: ['/api/:path*', '/action/:path*'],
    };

    3. Add CSRF token to your forms

    In a server component or client component, fetch the token from a dedicated endpoint or pass it via props. Example using a simple API route:

    // app/api/csrf/route.ts
    import { csrfToken } from '@/middleware';
    import { NextRequest } from 'next/server';
    
    export async function GET(request: NextRequest) {
      const token = await csrfToken(request);
      return Response.json({ token });
    }

    Then in your form:

    // app/components/MyForm.tsx
    'use client';
    import { useEffect, useState } from 'react';
    
    export default function MyForm() {
      const [csrfToken, setCsrfToken] = useState('');
    
      useEffect(() => {
        fetch('/api/csrf')
          .then(res => res.json())
          .then(data => setCsrfToken(data.token));
      }, []);
    
      const handleSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        const formData = new FormData(e.target as HTMLFormElement);
        const res = await fetch('/api/submit', {
          method: 'POST',
          headers: { 'x-csrf-token': csrfToken },
          body: formData,
        });
      };
    
      return (
        <form onSubmit={handleSubmit}>
          <input type="hidden" name="csrf_token" value={csrfToken} />
          {/* your fields */}
          <button type="submit">Submit</button>
        </form>
      );
    }

    4. Validate on the server

    // app/api/submit/route.ts
    import { NextRequest, NextResponse } from 'next/server';
    import { csrfToken } from '@/middleware';
    
    export async function POST(request: NextRequest) {
      try {
        await csrfToken(request); // throws if invalid
        // process form...
        return NextResponse.json({ success: true });
      } catch {
        return NextResponse.json({ error: 'Invalid CSRF token' }, { status: 403 });
      }
    }

    Common mistakes

  • Skipping CSRF entirely – AI tools rarely generate CSRF tokens because they focus on functionality, not security. Always add them manually.
  • Using GET requests for state changes – Some AI-generated forms use GET requests to submit data, which is both a CSRF and REST violation.
  • Relying on SameSite cookies alone – SameSite helps but isn't a complete solution. Attackers from subdomains or via browser plugins can still forge requests.
  • Forgetting to exclude safe methods – GET, HEAD, OPTIONS don't need CSRF protection. Blocking them breaks caching and navigation.
  • Not testing after implementation – Use a tool like OverMCP's continuous security monitoring to ensure protection stays intact after updates.
  • FAQ

    What is CSRF and why is it dangerous?

    CSRF (Cross-Site Request Forgery) tricks an authenticated user into unknowingly executing actions on your app. For example, an attacker could create a malicious link that changes the user's email or password. In vibe-coded apps, missing CSRF protection is common because AI tools don't add it by default.

    Does Next.js have built-in CSRF protection?

    Next.js does not provide built-in CSRF protection for API routes or server actions. You must implement it yourself using middleware or a library. The App Router's server actions are particularly vulnerable because they can be called from any origin without a token.

    Can I use SameSite cookies instead of CSRF tokens?

    SameSite cookies (especially Strict or Lax) reduce CSRF risk but are not a complete replacement. They don't protect against attacks from subdomains or browser extensions. A CSRF token provides a second layer of defense that validates the request's authenticity.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free