Skip to content

Security: Enforce auth inside Server Actions ("use server") and add input validation #802

@coderabbitai

Description

@coderabbitai

Security Concern: Server Actions Authentication and Input Validation

Description

Server Actions (functions marked with "use server") in Next.js are exposed as public API endpoints. Without proper authentication checks and input validation within each action, they can be exploited by unauthorized users or malicious actors.

Key Security Risks:

  • Server Actions can be invoked directly via HTTP requests, bypassing client-side route protection
  • Middleware authentication alone is insufficient as it may not cover all action endpoints
  • Unvalidated inputs can lead to injection attacks, data corruption, or unauthorized data access
  • Missing authorization checks can expose sensitive operations to any user

Vulnerable Code Pattern

// ❌ VULNERABLE: No auth check inside the server action
"use server";

export async function deleteUserData(userId: string) {
  // Direct database operation without verifying if the caller is authorized
  await db.user.delete({ where: { id: userId } });
  return { success: true };
}
// ❌ VULNERABLE: No input validation
"use server";

export async function updateProfile(formData: FormData) {
  const email = formData.get('email'); // Unvalidated input
  await db.user.update({
    where: { id: getCurrentUserId() },
    data: { email } // Potential SQL injection or invalid data
  });
}

Recommended Solution

// ✅ SECURE: Auth check + input validation
"use server";

import { auth } from '@/lib/auth';
import { z } from 'zod';

const deleteUserSchema = z.object({
  userId: z.string().uuid(),
});

export async function deleteUserData(userId: string) {
  // 1. Verify authentication
  const session = await auth();
  if (!session?.user) {
    throw new Error('Unauthorized: Must be logged in');
  }
  
  // 2. Validate input
  const validated = deleteUserSchema.parse({ userId });
  
  // 3. Verify authorization (user can only delete their own data or is admin)
  if (session.user.id !== validated.userId && session.user.role !== 'admin') {
    throw new Error('Forbidden: Cannot delete other users\' data');
  }
  
  // 4. Perform the operation
  await db.user.delete({ where: { id: validated.userId } });
  return { success: true };
}

Suggested Action Items

  1. Audit all server actions - Search for all files containing "use server" directives
  2. Add authentication checks - Verify user session at the start of each server action
  3. Implement authorization - Check if the authenticated user has permission for the operation
  4. Validate all inputs - Use schema validation libraries (Zod, Yup, etc.) to validate inputs
  5. Add rate limiting - Protect sensitive actions from abuse
  6. Implement logging - Track security-relevant operations for audit trails

Code Search Command

# Find all server actions in the codebase
rg -l '"use server"' --type ts --type tsx

References

Priority

🔴 High Priority - Security vulnerabilities should be addressed immediately to prevent potential data breaches or unauthorized access.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions