# OTP/SMS/email for step-up on multi-device/web

- **Pattern:** `ab-001468` (`finserv-session-security.step-up-auth.otp-sms-email-multidevice`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001468
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001468)

## Why it matters

Not all users have biometric hardware — older laptops, shared workstations, and most desktop web browsers lack TouchID or FaceID. If biometric is the only step-up path on multi-device or web contexts, users without capable hardware are either blocked from completing financial operations or silently bypassed by the application. CWE-308 (Use of Single-Factor Authentication) applies when a required step-up factor is unavailable to a meaningful portion of users. PCI-DSS Req 8.4 requires that multi-factor authentication be available for all applicable users. At least two fallback methods — OTP-SMS, OTP-email, or TOTP — ensures step-up is universally enforced rather than selectively applied based on hardware.

## Severity rationale

Low because users without biometric hardware on multi-device contexts lose step-up protection entirely, effectively removing an authentication control for a predictable subset of the user population.

## Remediation

Add OTP and TOTP fallback paths in `src/lib/stepUpAuth.ts` for multi-device and web contexts:

```js
export async function performMultiDeviceStepUp(
  email: string,
  phone: string
): Promise<boolean> {
  const method = await promptStepUpMethod(
    ['otp-sms', 'otp-email', 'totp-app']
  );
  if (method === 'otp-sms') {
    const otp = generateOTP();
    await sendSMS(phone, `Your verification code: ${otp}`);
    return verifyOTP(otp);
  }
  if (method === 'otp-email') {
    const otp = generateOTP();
    await sendEmail(email, `Your verification code: ${otp}`);
    return verifyOTP(otp);
  }
  if (method === 'totp-app') {
    return verifyTOTP(); // TOTP authenticator app
  }
  return false;
}
```

Expose at minimum two of the three methods so a user without a phone can use email OTP, and a user without email access can use a TOTP app.

## Detection

- **ID:** `otp-sms-email-multidevice`
- **Severity:** `low`
- **What to look for:** Count all step-up authentication methods available on multi-device/web contexts. Enumerate each method (OTP-SMS, OTP-email, TOTP app, password re-entry). Quote the actual method options found. Verify at least 2 fallback methods exist for users without biometric hardware.
- **Pass criteria:** On multi-device or web contexts, at least 2 step-up authentication methods are available (e.g., OTP-SMS + OTP-email, or TOTP + password re-entry). Report the count even on pass (e.g., "3 step-up methods on web: OTP-SMS, OTP-email, TOTP app").
- **Fail criteria:** Multi-device step-up relies only on biometric with fewer than 2 fallback methods, or 0 step-up methods available on web.
- **Skip (N/A) when:** The application does not support multi-device scenarios — cite the actual device support found.
- **Detail on fail:** `"1 of 2 required step-up methods on web — only WebAuthn, 0 OTP fallbacks for users without biometric hardware"`
- **Remediation:** Implement OTP step-up for multi-device contexts (in `src/lib/stepUpAuth.ts`):
  ```js
  // lib/stepUpAuth.ts
  export async function performMultiDeviceStepUp(email: string, phone: string) {
    const method = await promptStepUpMethod(['otp-sms', 'otp-email', 'totp-app']);
    if (method === 'otp-sms') {
      const otp = generateOTP();
      await sendSMS(phone, `Your step-up code: ${otp}`);
      return await verifyOTP(otp);
    } else if (method === 'otp-email') {
      const otp = generateOTP();
      await sendEmail(email, `Your step-up code: ${otp}`);
      return await verifyOTP(otp);
    } else if (method === 'totp-app') {
      return await verifyTOTP(); // Authenticator app
    }
  }
  ```

---

## External references

- cwe CWE-308
- owasp A07
- pci-dss Req 8.4

Taxons: access-control, cryptography-and-secrets

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