Invalid IBAN structure rejected before submission
Why it matters
An IBAN regex that validates structure but skips the mod-97 checksum accepts the majority of typoed IBANs — the check digit exists precisely to catch single-digit and transposition errors. Without it, GB82WEST12345698765432 and GB82WEST12345698765431 are indistinguishable to the validator, but only one is real. OWASP A03 treats insufficient input validation as an injection-class failure; an unvalidated IBAN that reaches payment processing triggers a failed SWIFT/SEPA transfer, chargeback risk, and customer trust damage.
Severity rationale
Medium because format-only IBAN validation lets typoed account numbers through to payment processing, causing failed transfers and chargeback exposure.
Remediation
Extend the IBAN validator in src/lib/validators.ts to include the mod-97 step after format checking. The algorithm rearranges the IBAN and reduces it modulo 97.
// src/lib/validators.ts
export function validateIBAN(iban: string): boolean {
iban = iban.replace(/\s/g, '').toUpperCase();
if (!/^[A-Z]{2}\d{2}[A-Z0-9]{1,30}$/.test(iban)) return false;
const rearranged = iban.slice(4) + iban.slice(0, 4);
const numeric = rearranged.replace(/[A-Z]/g, c =>
(c.charCodeAt(0) - 55).toString()
);
return BigInt(numeric) % 97n === 1n;
}
Wire this into the Zod schema used by src/app/api/transfers/route.ts via .refine(validateIBAN, 'Invalid IBAN').
Detection
- ID:
iban-structure-validation - Severity:
medium - What to look for: List all IBAN validation call sites. For each, classify whether the validation includes the mod-97 checksum algorithm or only checks format/length (regex-only). Quote the validation code found (e.g.,
% 97n === 1nor just/^[A-Z]{2}\d{2}/). Report: "X of Y IBAN validations include mod-97 checksum." - Pass criteria: At least 100% of IBAN validation sites include the mod-97 checksum verification. Invalid IBANs that match the format pattern but fail the checksum are rejected before submission. No more than 0 IBAN validations rely on regex alone.
- Fail criteria: Any IBAN validation checks only format or length without the mod-97 checksum.
- Must not pass when: An IBAN regex like
/^[A-Z]{2}\d{2}[A-Z0-9]+$/is the only validation — this accepts structurally invalid IBANs. - Skip (N/A) when: The project does not use IBAN (US-only or other non-IBAN region, 0 IBAN references found).
- Detail on fail:
"IBAN validation only checks format (2 letters + 2 digits + alphanumeric). No mod-97 checksum validation — invalid IBANs would be accepted." - Cross-reference: The account-format-validation check in this category handles the broader region-routing logic; this check focuses specifically on IBAN checksum depth.
- Remediation: Add mod-97 checksum to the IBAN validator in
src/lib/validators.ts. See the IBAN validation code in the account-format-validation check above.
External references
- cwe · CWE-20 — Improper Input Validation
- owasp:2021 · A03
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-form-validation·automated