From edffb559e2b9e3326baa61b5167b36ac5a6af56a Mon Sep 17 00:00:00 2001 From: Bornoz Date: Tue, 1 Sep 2026 01:29:37 +0300 Subject: [PATCH] Reject amount strings with trailing or invalid characters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit parseAmount stripped formatting characters and then called parseFloat, which parses a leading numeric prefix and ignores the rest. So "10abc" parsed as 10 and "1.25xyz" as 1.25 — a malformed string was silently accepted as a smaller-looking but different value. "1e5" parsed as 100000. For monetary values used in deposit and refund flows this is the wrong failure mode. Require the cleaned string to be a plain decimal in its entirety before parsing, so anything with trailing or non-numeric characters is rejected instead. Valid formatted inputs like $1,000.50 still parse to 1000.5. Closes #38 --- lib/utils/amount.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/utils/amount.ts b/lib/utils/amount.ts index 1571278..f698558 100644 --- a/lib/utils/amount.ts +++ b/lib/utils/amount.ts @@ -22,10 +22,16 @@ export const parseAmount = (amountStr: string): number => { .replace(/[$€£,\s]/g, "") .replace(/−/g, "-"); - // Parse the amount + // The cleaned string must be a plain decimal in its entirety. parseFloat + // accepts a valid numeric prefix and ignores the rest, so "10abc" would parse + // as 10 and "1e5" as 100000 — both silently altering a monetary value. + if (!/^\d+(\.\d+)?$/.test(cleanAmount)) { + throw new Error(`Invalid amount: ${amountStr}`); + } + const amount = parseFloat(cleanAmount); - if (Number.isNaN(amount) || amount <= 0) { + if (amount <= 0) { throw new Error(`Invalid amount: ${amountStr}`); }