security: add same-origin CSRF check to state-changing user API routes

Adds checkSameOrigin() helper in auth.ts that validates the Origin header
against the Host header. If Origin is present and mismatched, returns 403.
Applied to all 5 custom POST routes flagged in CPM-003 (NEXT-CSRF-001):
  - change-password, link-oauth-start, unlink-oauth, update-avatar, logout

SameSite=Lax (NextAuth default) already blocks standard cross-site CSRF;
this adds defense-in-depth against subdomain and misconfiguration scenarios.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-03-05 01:04:18 +01:00
parent e44e932e45
commit bdd3019214
6 changed files with 42 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/src/lib/auth";
import { auth, checkSameOrigin } from "@/src/lib/auth";
import { getUserById } from "@/src/lib/models/user";
import { createAuditEvent } from "@/src/lib/models/audit";
import db from "@/src/lib/db";
@@ -8,6 +8,9 @@ import { eq } from "drizzle-orm";
import { nowIso } from "@/src/lib/db";
export async function POST(request: NextRequest) {
const originCheck = checkSameOrigin(request);
if (originCheck) return originCheck;
try {
const session = await auth();
if (!session?.user?.id) {