Critical CWE-306 OWASP A07:2021

Missing Authentication in Vibe Coded Apps

How to find and fix unprotected API routes that let anyone access your data

Quick Answer

Missing authentication means your API endpoints have no login check. Anyone can call them directly and access or modify data. Ranked #7 on OWASP Top 10. AI tools generate functional routes without auth by default.

#7
OWASP Ranking
CWE-306
Seconds
To exploit
Critical
Severity

Source: OWASP Top 10 (2021)

What is missing authentication?

Missing authentication is when API endpoints or pages can be accessed without verifying user identity. When your route handler processes requests without checking if the user is logged in, anyone who discovers the endpoint can use it.

Think of it like a house with no locks. The front door exists, but anyone can walk in. Even if your UI requires login, attackers bypass the frontend entirely and call your API directly.

According to OWASP Top 10 (2021), identification and authentication failures rank #7 in web application security risks. The OWASP Authentication Cheat Sheet provides comprehensive guidelines for implementing proper authentication. For vibe coders, this is especially common because AI generates the functionality you ask for without assuming you need authentication.

How do AI tools create unprotected routes?

AI tools create unprotected routes because they respond literally to your prompts. "Create an API to get user data" produces a working endpoint, but authentication is not implied in that request.

Common AI-generated vulnerable patterns

When you ask AI tools for API endpoints, they often generate code like this:

// AI-generated Next.js API route - no auth check
// src/app/api/users/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.user.findUnique({
    where: { id: params.id }
  })
  return Response.json(user)
}

// Anyone can call: GET /api/users/123
// Returns full user data including email, created_at, etc.

This code works perfectly, which is why AI generates it. But there is no check for who is making the request. Any user, logged in or not, can fetch any user's data.

Why this happens: AI tools are trained to fulfill your request efficiently. When vibe coding and you ask for "an API endpoint," it builds exactly that, with no extras. Authentication is considered a separate concern that you need to explicitly request.

All major AI coding tools (Cursor, Claude Code, Bolt, v0, Windsurf, and GitHub Copilot) exhibit this pattern. The solution is always the same: add explicit auth checks to every route that accesses protected data.

What could happen if I have missing authentication?

Missing authentication can result in complete data exposure, unauthorized actions, account takeover, and compliance violations.

  • Complete data exposure: Attackers enumerate your API to download all user data, orders, messages, or any stored information
  • Unauthorized actions: Create, modify, or delete records without permission (post as other users, change settings, delete content)
  • Account takeover: Access password reset endpoints, email change functions, or session management without auth
  • Privilege escalation: Access admin endpoints that were "hidden" but never protected
  • Compliance violations: GDPR, HIPAA, and PCI-DSS all require access controls; missing auth means automatic non-compliance

How do I detect missing authentication?

Detect missing authentication by reviewing every API route and checking if it verifies user identity before processing. Routes without session checks, JWT validation, or auth middleware are vulnerable.

Red flags to look for
// Next.js App Router - no auth check
export async function GET(request: Request) {
  // Immediately accesses data without verifying user
  const data = await db.query(...)
  return Response.json(data)
}

// Express - no middleware protection
app.get('/api/users/:id', async (req, res) => {
  // No req.user check, no session validation
  const user = await User.findById(req.params.id)
  res.json(user)
})

// SvelteKit - no hooks protection
export async function GET({ params }) {
  // No locals.user check
  return json(await getUser(params.id))
}

// Questions to ask for each route:
// 1. Does it check session/token before doing anything?
// 2. Is there middleware protecting this route?
// 3. Would this work if called from Postman with no cookies?

Scan your routes automatically

Scan your code free

How do I fix missing authentication?

Fix missing authentication by adding auth checks to every protected route. Verify user identity server-side before processing any request that accesses or modifies data.

AI Fix Prompt

Copy this prompt into Cursor, Claude Code, or Bolt to automatically add authentication to your routes:

Copy-paste this prompt
Add authentication checks to all unprotected API routes in my codebase. ## What to look for Search for API routes that access or modify data without verifying user identity: 1. Next.js App Router (app/api/**/route.ts): - Routes that don't call getServerSession() or verify JWT - Routes that immediately query database without auth check 2. Next.js Pages Router (pages/api/*.ts): - Handlers without session validation - No getSession() or token verification 3. Express routes: - Routes without auth middleware - No req.user or req.session checks 4. SvelteKit endpoints: - +server.ts files without locals.user checks - No hooks.server.ts protection ## How to fix Add authentication check at the start of every protected route: ### For Next.js App Router (with NextAuth): ```typescript import { getServerSession } from 'next-auth' import { authOptions } from '@/lib/auth' export async function GET(request: Request) { const session = await getServerSession(authOptions) if (!session) { return Response.json({ error: 'Unauthorized' }, { status: 401 }) } // Now safe to proceed with authenticated user const userId = session.user.id // ... rest of handler } ``` ### For Next.js with Supabase: ```typescript import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { cookies } from 'next/headers' export async function GET(request: Request) { const supabase = createRouteHandlerClient({ cookies }) const { data: { session } } = await supabase.auth.getSession() if (!session) { return Response.json({ error: 'Unauthorized' }, { status: 401 }) } // Proceed with session.user } ``` ### For Express: ```typescript // Create auth middleware const requireAuth = (req, res, next) => { if (!req.session?.userId) { return res.status(401).json({ error: 'Unauthorized' }) } next() } // Apply to routes app.get('/api/users/:id', requireAuth, async (req, res) => { // req.session.userId is guaranteed to exist }) ``` ### For SvelteKit: ```typescript // src/routes/api/users/[id]/+server.ts import { error, json } from '@sveltejs/kit' export async function GET({ params, locals }) { if (!locals.user) { throw error(401, 'Unauthorized') } // Proceed with locals.user } ``` ## Routes that need auth - Any route that reads user-specific data - Any route that creates, updates, or deletes records - Any route that returns sensitive information - Admin routes (also need role checks) ## Routes that might NOT need auth - Public content (blog posts, product listings) - Health check endpoints - Webhook receivers (use signature verification instead) - Auth endpoints themselves (login, register, password reset) ## After fixing 1. Test each route without auth cookies - should return 401 2. Test with valid auth - should work normally 3. List all routes you modified with the auth method used 4. Flag any routes you're unsure about for manual review Please proceed systematically through my codebase.

Manual Fix

The fix is always the same: verify user identity before processing the request. Return 401 Unauthorized if no valid session exists.

VULNERABLE
// No authentication - anyone can access
export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const user = await db.user.findUnique({
    where: { id: params.id }
  })
  return Response.json(user)
}

// Attacker opens DevTools, finds endpoint
// Calls: curl /api/users/admin-user-id
// Gets: Full admin user object
SECURE
// With authentication check
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const session = await getServerSession(authOptions)

  if (!session) {
    return Response.json(
      { error: 'Unauthorized' },
      { status: 401 }
    )
  }

  // Only return user's own data (also prevents IDOR)
  if (session.user.id !== params.id) {
    return Response.json(
      { error: 'Forbidden' },
      { status: 403 }
    )
  }

  const user = await db.user.findUnique({
    where: { id: params.id }
  })
  return Response.json(user)
}

What changed: The route now checks for a valid session before doing anything. It also verifies the user can only access their own data (preventing IDOR). Unauthenticated requests get 401, unauthorized requests get 403.

Frequently asked questions

Why does AI-generated code often lack authentication?

AI coding tools optimize for working code that fulfills your immediate request. When you ask for "an API to get user data," AI generates the endpoint logic but not the authentication wrapper because you did not explicitly ask for it. AI tools treat auth as a separate concern unless you specify it in your prompt.

Is middleware authentication enough?

Middleware authentication is a good start but not always sufficient. You need both authentication (who is this user?) and authorization (can this user access this resource?). Middleware typically handles authentication, but you still need per-route authorization checks to prevent IDOR vulnerabilities.

How do I protect Next.js API routes?

In Next.js App Router, use middleware.ts to protect routes globally, then add session checks in individual route handlers. For Pages Router, create a withAuth higher-order function. Always verify the session server-side, never trust client-side auth state alone.

Should internal APIs have authentication?

Yes, always. Internal APIs that are "only called by your frontend" are still accessible to anyone who can find the endpoint. Attackers use browser DevTools to discover API routes, then call them directly. Every API route that returns or modifies data needs authentication.

What is the difference between authentication and authorization?

Authentication verifies identity (who are you?). Authorization verifies permissions (what can you access?). Missing authentication means anyone can access the endpoint. Missing authorization means authenticated users can access resources belonging to other users. Both are critical; having one without the other is still a vulnerability.

Related content

Scan your code for missing authentication

Check your API routes for authentication issues and other common security vulnerabilities.

Try Vibeship Scanner