Password-only admin access means one phished or brute-forced credential hands an attacker complete administrative control. PCI DSS 4.0 Requirements 8.4 and 8.5 mandate multi-factor authentication for all access to the Cardholder Data Environment; NIST 800-53 rev5 IA-2(1) and IA-2(2) require MFA for privileged accounts. CWE-308 (Use of Single-Factor Authentication) and OWASP A07 both list missing MFA as a primary cause of privileged account compromise. A stolen admin password without a second factor exposes every user record, payment record, and configuration secret in the system.
High because admin account compromise via password alone escalates immediately to full data breach; MFA is the primary control preventing lateral movement from a single credential leak.
Gate every admin route on a verified second factor — check factor enrollment before rendering the page, not just on login.
// src/app/admin/layout.tsx
import { redirect } from 'next/navigation'
import { createClient } from '@/utils/supabase/server'
export default async function AdminLayout({ children }: { children: React.ReactNode }) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/login')
const { data } = await supabase.auth.mfa.getAuthenticatorAssuranceLevel()
if (data?.currentLevel !== 'aal2') {
redirect('/mfa-challenge')
}
return <>{children}</>
}
For Auth0 or Clerk, enable MFA enforcement in the provider dashboard and add a middleware check that validates the amr claim. Do not make MFA opt-in for admin roles — enforce enrollment before granting access.
ID: ecommerce-pci.access-control.mfa-enforced
Severity: high
What to look for: Enumerate all admin and CDE access paths (admin routes, dashboard pages, API endpoints with elevated permissions). For each access path, check whether MFA verification is enforced before granting access. Count the number of MFA-related dependencies (otplib, speakeasy, twilio, @supabase/auth mfa methods) and the number of code locations that call MFA verification functions. Before evaluating, quote the actual MFA enforcement code (e.g., the middleware check or redirect logic).
Pass criteria: At least 1 MFA verification check exists in code that gates admin or CDE access. Admin users and anyone accessing the CDE are required to authenticate with at least 2 factors (password + TOTP, password + SMS, password + hardware key). MFA is enforced (redirect or block on missing MFA), not optional. At least 1 MFA-related dependency is present in package.json.
Fail criteria: Admin access or CDE access requires only password, or MFA is optional/unenforced. Must not pass when MFA dependencies exist but no enforcement code is found.
Skip (N/A) when: No admin panel and no CDE access exists (no admin routes in src/app/admin/, no elevated-permission API endpoints, fully third-party payment processing with no local admin).
Detail on fail: Specify where MFA is missing. Example: "Admin dashboard at src/app/admin/page.tsx has no MFA check. 0 MFA enforcement points found across 3 admin routes." or "otplib dependency present but MFA verification never called in middleware"
Remediation: Enforce MFA for sensitive access. Using Supabase:
// src/app/admin/page.tsx
import { redirect } from 'next/navigation';
import { createClient } from '@/utils/supabase/server';
export default async function AdminPage() {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) redirect('/login');
// Require MFA
const { data: { factors } } = await supabase.auth.mfa.listFactors();
const hasMFA = factors?.totp && factors.totp.length > 0;
if (!hasMFA) {
redirect('/setup-mfa');
}
return <div>Admin Dashboard</div>;
}
For Auth0 or Clerk, configure MFA in their dashboards and add middleware checks. For custom auth, integrate a TOTP library:
import { authenticator } from 'otplib';
// Verify TOTP code
const isValid = authenticator.check(userTotpSecret, userProvidedCode);