# Step-up auth for transfers/wires/payments

- **Pattern:** `ab-001465` (`finserv-session-security.step-up-auth.step-up-sensitive-ops`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001465
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001465)

## Why it matters

A session token that grants access to wire transfers and payments is the highest-value credential in a financial application. If that token is stolen — via XSS, network interception, or session fixation — the attacker can execute high-value transactions without any additional authentication barrier. Step-up authentication requires a second proof-of-identity at the moment the sensitive operation is initiated, so a stolen token alone is insufficient. CWE-306 (Missing Authentication for Critical Function), OWASP A07, PCI-DSS Req 8.4, and NIST 800-63B IA-11 all address this gap. Without server-side step-up enforcement, client-side UI guards are trivially bypassed with a direct API call.

## Severity rationale

High because an absent server-side step-up on financial endpoints means any actor possessing a valid session token — regardless of how it was obtained — can initiate transfers, wires, and payments with no additional authentication challenge.

## Remediation

Enforce step-up via server-side middleware, not client state, in `src/middleware/requireStepUp.ts`:

```js
export async function requireStepUp(req: Request): Promise<Response | null> {
  const session = await getSession(req);
  const verified = await checkStepUpStatus(session.id);
  if (!verified) {
    return Response.json(
      { error: 'Step-up authentication required' },
      { status: 403 }
    );
  }
  return null; // proceed
}

// src/app/api/transfer/route.ts
export async function POST(req: Request) {
  const block = await requireStepUp(req);
  if (block) return block;
  // safe to process transfer
}
```

Apply `requireStepUp` to every sensitive route: transfers, wires, payments, account changes, and password resets. Do not rely on a client-side flag or cookie indicating that step-up was completed — verify the server-side step-up record on every request.

## Detection

- **ID:** `step-up-sensitive-ops`
- **Severity:** `high`
- **What to look for:** Enumerate all sensitive financial operation endpoints (transfers, wires, payments, account changes, password reset) and count every endpoint that has server-side step-up middleware. Quote the actual step-up verification function found. An endpoint that only checks client-side step-up state does not count as pass — do not pass if step-up is client-only.
- **Pass criteria:** At least 90% of sensitive financial operation endpoints have server-side step-up authentication middleware. Count all sensitive endpoints — report the ratio even on pass (e.g., "5 of 5 sensitive endpoints require step-up: /api/transfer, /api/wire, /api/payment, /api/account/change, /api/password/reset").
- **Fail criteria:** Any sensitive operation can be executed with only the current session token and no additional authentication challenge, or step-up is client-side only.
- **Skip (N/A) when:** The application has no operations classified as sensitive — cite the actual routes found.
- **Detail on fail:** `"2 of 5 sensitive endpoints lack step-up — POST /api/transfer and POST /api/wire have session-only auth. 0 step-up middleware found on these routes."`
- **Cross-reference:** Check `finserv-session-security.step-up-auth.step-up-strength-equivalent` for strength requirements, and `finserv-session-security.session-integrity.suspicious-activity-step-up` for anomaly-triggered step-up.
- **Remediation:** Add step-up auth middleware for sensitive routes (in `src/middleware/requireStepUp.ts`):
  ```js
  // middleware/requireStepUp.ts
  export async function requireStepUp(req: Request) {
    const session = await getSession(req);
    const stepUpVerified = await checkStepUpStatus(session.id);
    if (!stepUpVerified) {
      return Response.json({ error: 'Step-up authentication required' }, { status: 403 });
    }
  }

  // app/api/transfer/route.ts
  export async function POST(req: Request) {
    await requireStepUp(req); // Enforces step-up before processing
    const { fromAccount, toAccount, amount } = await req.json();
    // Process transfer
  }
  ```

## External references

- cwe CWE-306
- owasp A07
- nist IA-11
- pci-dss Req 8.4

Taxons: access-control

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