A 4-line regex took down our image pipeline for 6 hours. It was legal.
Our image validation service stalled for about 6 hours in April. Not slow — stalled , requests queueing, CPU pinned at 100% on every worker. The regex that caused it was 4 lines long and I still have it in a scratch file: const matcher = /^ (\w + \.){2,}\w + \$ / That looks harmless. It is also catastrophically backtracking, and here is why. The input that broke it Attachments come from users, so…
In April, a seemingly harmless 4-line regular expression brought an image validation service to a grinding halt for six hours in April. The regex, `const matcher = /^ (\w + \.){2,}\w + $ /`, was deemed safe after being reviewed by ESLint, Semgrep, and the human reviewer. However, it turned out to be catastrophically backtracking, causing the system to queue requests and peg CPU usage at 100% on every worker.
The problem stemmed from the input being derived from users, leading to filenames that could trigger the backtracking issue. The regex would try every possible division of the string among the `{2,}` repetitions of `(\w+.)`, followed by a lengthy backtracking process before concluding that there is no match. This exponential backtracking caused a sudden jump in time to reject inputs, growing far worse than expected, leading to the outage.
Despite the static checks passing, the regex remained vulnerable due to the nature of the input domain. Most ReDoS detection techniques rely on pattern-list based checks, which are ineffective against unconstrained input. To address this, a simple time budget check was introduced, which proved to be a much earlier warning system.
By feeding the regex a length ladder of increasing input sizes and measuring the time taken for each sample, the time growth could be monitored. Anything that grew more than tripled per rung was flagged as exponential, and the regex in question was found to be a culprit.
Ultimately, the solution was to replace the regex with a simple filename extension check, which is immune to backtracking. This change eliminated the risk of catastrophic backtracking and made the image validation service more robust. It's important to note that the regex vulnerability isn't universal across all engines and programming languages, highlighting the need for dialect-specific notes in the codebase.
While no static check can guarantee a pattern's safety, this lint tool aims to catch common catastrophic backtracking shapes and provide clear failure modes, rather than a guarantee of safety.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.