highLogins, sessions and access
API Route Changes Data Without Checking Who Is Asking
This endpoint accepts writes from anyone, logged in or not.
Why it matters
Hiding a button behind a login does not protect the route behind it. Anyone can call the URL directly with curl and create, change or delete data. AI tools add the session check to the page and forget the route, because the page is what they were asked to build.
What it looks like
This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.
POST route writes without any auth check
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
export async function POST(req: Request) {
const { title } = await req.json();
const post = await prisma.post.create({ data: { title } });
return NextResponse.json(post);
}The smallest fix
minimal patch
import { auth } from '@/lib/auth'; // or getServerSession / supabase.auth.getUser
export async function POST(req: Request) {
const session = await auth();
if (!session?.user) return Response.json({ error: 'Unauthorized' }, { status: 401 });
// ... the existing handler, using session.user.id instead of trusting the body
}The better fix
If you have a few more minutes, this is the approach that holds up as the app grows.
safe alternative
// Put the check in one place for every protected route:
// middleware.ts with a matcher for /api/(.*), or a small requireUser()
// helper that every handler calls on its first line.Let your AI tool fix it
When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.
The route handler in [the file] exports a mutating method but never checks who is calling. Add a session or token check at the top of every POST, PUT, PATCH and DELETE export, return 401 when it fails, and use the verified user id rather than any id sent in the body. If this endpoint is intentionally public (a contact form, a webhook), add rate limiting or signature verification instead and tell me which it is.
How to check the fix worked
1. Call the route with curl and no cookies or token. Expect 401. 2. Call it with a valid session. Expect the normal response. 3. Call it with user A's session but user B's id in the body. Expect the change to apply to A only, or a 403.