# Admin Routes Protected with Role Check

- **Pattern:** `ab-002270` (`saas-authorization.admin-privilege.admin-routes-protected`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002270
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002270)

## Why it matters

An admin route that checks `if (!session)` but not `if (session.user.role !== 'admin')` is accessible to every authenticated user in the application. This exposes user management, system configuration, and privileged operations to any account holder. CWE-285 (Improper Authorization) and CWE-284 (Improper Access Control) define this failure precisely. OWASP A01 (Broken Access Control) lists this as a primary failure mode. NIST 800-53 AC-3 and AC-6 require that admin operations enforce both authentication and the specific privilege level required — the authentication check alone is necessary but not sufficient.

## Severity rationale

Critical because any authenticated user gains access to administrative functionality — user management, billing, system configuration — without needing any elevated credentials.

## Remediation

Use `middleware.ts` to enforce admin role checks across the entire `/admin` path group before requests reach individual handlers. Keep role checks in handlers as well for defense in depth.

```typescript
// middleware.ts
export async function middleware(req: NextRequest) {
  const token = await getToken({ req });

  if (req.nextUrl.pathname.startsWith('/admin')) {
    if (!token) return NextResponse.redirect(new URL('/login', req.url));
    if (token.role !== 'admin') return NextResponse.redirect(new URL('/403', req.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/admin/:path*', '/api/admin/:path*'],
};
```

Middleware can be bypassed in some configurations — individual admin API handlers should also check `session.user.role === 'admin'` as a second line of defense.

## Detection

- **ID:** `admin-routes-protected`
- **Severity:** `critical`
- **What to look for:** Count all relevant instances and enumerate each. Find admin-only routes — URL patterns like `/admin/*`, `/api/admin/*`, `/dashboard/admin/*`, or routes named with "admin" that handle user management, system configuration, or privileged operations. For each, check whether the handler verifies the admin role specifically, not just whether the user is authenticated. An admin route that only checks `if (!session)` but not `if (session.user.role !== 'admin')` is a fail.
- **Pass criteria:** All admin routes and admin API endpoints explicitly check for the admin role (or equivalent high-privilege permission) in addition to checking for authentication. At least 1 implementation must be verified. Both checks must be present.
- **Fail criteria:** Any admin-purpose route or endpoint only validates authentication without also verifying the admin role, making all admin functionality accessible to any authenticated user.
- **Skip (N/A) when:** No admin section or admin-specific routes detected in the codebase.
- **Detail on fail:** `"Admin route(s) check authentication but not admin role. Any authenticated user can access admin functionality."` (List the specific routes that are unprotected.)
- **Remediation:** For Next.js, use `middleware.ts` to enforce admin role checks across the entire `/admin` path group before the request reaches route handlers.

  ```typescript
  // middleware.ts
  export async function middleware(req: NextRequest) {
    const token = await getToken({ req });

    if (req.nextUrl.pathname.startsWith('/admin')) {
      if (!token) return NextResponse.redirect(new URL('/login', req.url));
      if (token.role !== 'admin') return NextResponse.redirect(new URL('/403', req.url));
    }

    return NextResponse.next();
  }

  export const config = {
    matcher: ['/admin/:path*', '/api/admin/:path*'],
  };
  ```

  Even with middleware protection, keep role checks in individual admin API handlers as defense in depth — middleware can be bypassed in some configurations.

## External references

- cwe CWE-285
- cwe CWE-284
- owasp A01
- nist AC-3
- nist AC-6

Taxons: access-control

HTML version: https://auditbuffet.com/patterns/ab-002270
