Step-up auth for transfers/wires/payments
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:
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-equivalentfor strength requirements, andfinserv-session-security.session-integrity.suspicious-activity-step-upfor anomaly-triggered step-up. - Remediation: Add step-up auth middleware for sensitive routes (in
src/middleware/requireStepUp.ts):// 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 — Missing Authentication for Critical Function
- owasp:2021 · A07
- nist:rev5 · IA-11 — Re-Authentication
- pci-dss:4.0 · Req 8.4 — Multi-factor authentication for CDE access
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-session-security·automated