Correct currency code usage to prevent conversion errors
Why it matters
Payment providers require amounts in the smallest currency unit — cents for USD, pence for GBP — but zero-decimal currencies (JPY, KRW, VND, and 13 others) are already expressed in their smallest unit and must not be multiplied by 100. A checkout that applies price * 100 to a JPY price of ¥1,000 submits a charge for ¥100,000 — a 100x overcharge. CWE-681 (Incorrect Conversion between Numeric Types) captures this integer arithmetic error. The ISO 4217 functional correctness requirement means using the wrong currency code (e.g., "JP" instead of "jpy") will also cause the payment to be rejected or processed in the wrong currency. This is a silent production defect: it passes all tests that mock the Stripe API but fails live with real amounts.
Severity rationale
Low because zero-decimal currency miscalculation causes 100x overcharges on live transactions for affected currencies, and invalid currency codes cause silent payment failures.
Remediation
Centralize currency-to-amount conversion in a single utility function that handles zero-decimal currencies correctly.
// lib/currency.ts
const ZERO_DECIMAL = new Set([
'bif', 'clp', 'gnf', 'jpy', 'kmf', 'krw', 'mga',
'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf'
])
export function toProviderAmount(amount: number, currency: string): number {
const code = currency.toLowerCase()
if (!code.match(/^[a-z]{3}$/)) throw new Error(`Invalid ISO 4217 currency code: ${currency}`)
return ZERO_DECIMAL.has(code) ? Math.round(amount) : Math.round(amount * 100)
}
// app/api/payment/route.ts
const paymentIntent = await stripe.paymentIntents.create({
amount: toProviderAmount(priceInLocalUnits, currency),
currency: currency.toLowerCase(), // Stripe requires lowercase ISO 4217
})
Write a unit test for JPY, KRW, and USD to lock in the conversion logic before any multi-currency work ships.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Payment Security Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-681 — Incorrect Conversion between Numeric Types
- iso-25010:2011 · functional-suitability.functional-correctness
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ecommerce-payment-security·automated