CMMC 2.0 AC.L1-3.1.1 (NIST 800-171r2 3.1.1) requires that only authorized users and processes access organizational systems. Without enforced authentication on every sensitive route and API endpoint, any unauthenticated actor — a misconfigured crawler, a SSRF exploit, or a direct URL request — can read or exfiltrate Federal Contract Information. A single unguarded API endpoint in a DoD contractor's system is enough to trigger a CMMC assessment failure and jeopardize contract eligibility. CWE-306 (Missing Authentication for Critical Function) and OWASP A01 name this as the highest-severity access control failure class.
Critical because unauthenticated route access exposes FCI to any network-reachable requester with zero credential requirements.
Lock every API route and server-rendered page that touches FCI behind an authentication check. In middleware.ts, define an explicit allowlist of public paths and redirect all unmatched requests without a valid session:
// middleware.ts
const PUBLIC_PATHS = ['/', '/login', '/signup', '/api/auth']
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const isPublic = PUBLIC_PATHS.some(p => pathname.startsWith(p))
if (!isPublic && !request.cookies.get('session')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}
Verify the matcher pattern does not create bypass gaps for /api/* paths — test with a tool like curl -s against each protected route without a cookie.
ID: gov-cmmc-level-1.access-control.authorized-access
Severity: critical
CMMC Practice: AC.L1-3.1.1
What to look for: Examine authentication middleware, route guards, and session management. Check that all routes or API endpoints that handle sensitive or contract-related data require authentication before processing. Look for middleware patterns that short-circuit unauthenticated requests (e.g., if (!session) return redirect('/login'), requireAuth(), or equivalent). Check for any API endpoints that accept POST/PUT/DELETE operations on sensitive resources without first verifying a session or token. Look for public route definitions and ensure none of the protected paths appear there by mistake.
Pass criteria: Count all routes and API endpoints that handle FCI or sensitive data. All require authentication with no gaps. Auth middleware covers all protected paths. No more than 0 unprotected API endpoints may expose data that should be access-controlled. Report even on pass: "X of Y sensitive routes have authentication middleware." Before evaluating, extract and quote the auth middleware configuration to verify coverage.
Fail criteria: Any protected route is accessible without authentication, or API endpoints lack authentication checks. Do NOT pass when middleware covers most routes but excludes specific API paths via a matcher pattern — verify the matcher does not create bypass gaps.
Cross-reference: For role-based authorization beyond authentication, see the transaction-control check in this audit.
Skip (N/A) when: Never — access control is fundamental to CMMC Level 1.
Detail on fail: Identify the specific unprotected route or endpoint. Example: "GET /api/contracts returns all records without auth check. Middleware in middleware.ts excludes /api/* paths, leaving all API routes unprotected." Keep under 500 characters.
Remediation: Every route that processes or returns sensitive data must require authentication. In Next.js, use middleware to protect all non-public routes:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const PUBLIC_PATHS = ['/', '/login', '/signup', '/api/auth']
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const isPublic = PUBLIC_PATHS.some(p => pathname.startsWith(p))
if (!isPublic && !request.cookies.get('session')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)']
}
For API routes, check the session at the top of every handler before processing the request:
// app/api/contracts/route.ts
import { getServerSession } from 'next-auth/next'
export async function GET(req: Request) {
const session = await getServerSession()
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
// ... proceed with handler
}