Step-up authentication is only meaningful if the challenge it presents is at least as hard to satisfy as the initial login. Downgrading from a password+biometric login to a plain OTP step-up means the attacker who cannot replicate the biometric at login can instead wait for the step-up prompt and satisfy it with a weaker factor. CWE-287 (Improper Authentication) and NIST 800-63B AAL2 both require that step-up methods match or exceed the assurance level of the authenticating session. OWASP A07 identifies authentication downgrade as a category-defining failure. In practice, a strength mismatch turns step-up into a false signal — it appears to add security while actually lowering the bar.
Medium because strength downgrade does not eliminate the step-up challenge but renders it easier to satisfy than the original login, reducing the additional security margin that step-up is supposed to provide.
Define strength levels explicitly in src/lib/authStrength.ts and enforce that the step-up method meets or exceeds the login method's level:
const STRENGTH: Record<string, number> = {
'password': 1,
'otp': 1,
'password+otp': 2,
'biometric': 2,
'password+biometric': 3
};
export async function requireStepUpAuth(
session: Session,
minOverride?: number
): Promise<boolean> {
const loginStrength = STRENGTH[session.authMethod] ?? 1;
const requiredStrength = Math.max(loginStrength, minOverride ?? 0);
const stepUpMethod = await promptStepUp(requiredStrength);
return STRENGTH[stepUpMethod] >= requiredStrength;
}
Never hard-code step-up to a fixed method without first querying the session's login strength — users who authenticated at level 3 must be challenged at level 3.
finserv-session-security.step-up-auth.step-up-strength-equivalentmedium"Login requires strength level 3 (password+biometric). Step-up is level 1 (OTP only) — below minimum."src/lib/authStrength.ts):
// lib/authStrength.ts
const authStrengthLevels = {
'password': 1,
'otp': 1,
'password+otp': 2,
'biometric': 2,
'password+biometric': 3
};
export async function requireStepUpAuth(session: Session, minStrength: number) {
// Determine initial login strength
const loginStrength = authStrengthLevels[session.authMethod];
// Require step-up of equal or higher strength
const requiredStepUpStrength = loginStrength;
const stepUpMethod = await promptStepUp(requiredStepUpStrength);
return authStrengthLevels[stepUpMethod] >= requiredStepUpStrength;
}