Repository navigation
utils - fix: reject malformed numbers in shorthandToMilliseconds - #1744
rudycelekli wants to merge 1 commit into
Conversation
The shorthand regex used [\d.]+ for the numeric part, so malformed values were not rejected: "1.2.3s" silently parsed as 1.2s (1200ms) and "..s" or ".s" returned NaN instead of throwing the documented unsupported-format error. Require a well-formed number (digits with at most one decimal point). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
jaredwray
left a comment
There was a problem hiding this comment.
Thank you for this fix. The new regex accepts and rejects the correct inputs. But it adds a performance problem.
Problem: polynomial backtracking (ReDoS) in the new regex
In \d+\.?\d*, the dot is optional. So \d+ and \d* can divide one run of digits in many ways. When the end of the string does not match, the engine tries each division. The time increases with the square of the input length. The old [\d.]+ did not have this problem.
| Input | main |
This PR | Suggested regex |
|---|---|---|---|
40,000 digits + "x" |
0.5 ms | 2,092 ms | 0.5 ms |
Cacheable.set, @cacheable/memory, and @cacheable/node-cache send string TTLs to this function without validation. A long TTL string from user input can block the event loop.
Requested change
Put the decimal part in one optional group at packages/utils/src/shorthand-time.ts:33:
const match = /^(\d+(?:\.\d*)?|\.\d+)\s*(ms|s|m|h|hr|d)$/i.exec(shorthand);This regex gives the same captures as the regex in this PR. A comparison on all 597,870 strings of length 6 or less over [0 1 . s m h r d space] found 0 differences.
Optional
- Use
test.eachfor the malformed inputs. Then a failure shows which input failed. - Add the four test-audit answers from
AGENTS.mdto the verification list in the PR body.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1744 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 29 29
Lines 3620 3620
Branches 810 811 +1
=========================================
Hits 3620 3620 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Please check if the PR fulfills these requirements
What kind of change does this PR introduce? Bug fix (
@cacheable/utils)shorthandToMillisecondsmatched the numeric part of a shorthand with[\d.]+, so malformed numbers slipped through instead of hitting the "Unsupported time format" error:"1.2.3s"1200(silently parsed as1.2s)"1..5s"1000"..s",".s"NaN".5s","5.s"500,5000A
NaNTTL is especially bad since it flows into expiry math in the stores. The regex now requires digits with at most one decimal point:^(\d+\.?\d*|\.\d+)\s*(ms|s|m|h|hr|d)$.Verification (run from
packages/utilswith a standalone vitest 3 and biome, sincepnpm installcould not self-switch versions on my machine):send in string with malformed number and valid unit throwsfails on the old regex (expected [Function] to throw an error) and passes with the fix.vitest run test/shorthand-time.test.ts test/ttl.test.ts: 38 passed.biome checkon the two touched files: clean.Written with Claude Code (AI-assisted); I reproduced the behavior and ran the tests above myself.
🤖 Generated with Claude Code