From 4d998c7326e8a3b9697c5cb117074deb04cf8b55 Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Mon, 25 May 2026 17:01:21 +0800 Subject: [PATCH] fix(parse): remove ambiguous numeric regex to prevent ReDoS Replace the backtracking-prone `\d*\.?\d+` numeric pattern with an unambiguous alternative and add regression coverage for long invalid input. Fixes #291. --- src/index.ts | 2 +- src/parse.test.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index d50e3c7..2e7baa7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -75,7 +75,7 @@ export function parse(str: string): number { ); } const match = - /^(?-?\d*\.?\d+) *(?milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)?$/i.exec( + /^(?-?(?:\d+\.?\d*|\.\d+)) *(?milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)?$/i.exec( str, ); diff --git a/src/parse.test.ts b/src/parse.test.ts index 9182411..3b6febf 100644 --- a/src/parse.test.ts +++ b/src/parse.test.ts @@ -54,6 +54,12 @@ describe('parse(string)', () => { expect(Number.isNaN(parse('foo'))).toBe(true); }); + it('should parse long invalid numeric strings without catastrophic backtracking', () => { + const start = performance.now(); + expect(Number.isNaN(parse(`${'9'.repeat(99)}z`))).toBe(true); + expect(performance.now() - start).toBeLessThan(20); + }); + it('should be case-insensitive', () => { expect(parse('53 YeArS')).toBe(1672552800000); expect(parse('53 WeEkS')).toBe(32054400000);