On May 2024, security researchers uncovered a Denial-of-Service vulnerability (ReDoS) in the popular JavaScript pattern matching library, micromatch. Tracked as CVE-2024-4067, this vulnerability arises from the way micromatch handles certain regular expression patterns — especially when using the braces() function. This post gives you an exclusive breakdown of the issue, explains how an attacker can exploit it, and shares safe practices to help you avoid falling prey to ReDoS attacks like this.
What's the Problem?
micromatch is used in many projects for advanced globbing and pattern matching. The vulnerable code lies in the braces() helper, which is responsible for parsing and expanding brace patterns like {a,b,c}.
The bug stems from how the regular expression is built and how the .* pattern is used. In regular expressions, .* means "match any number of any character." Since it is greedy, it will try to consume as much of the input as possible. If the regular expression is searching for a specific closing character (like a } bracket), and if an attacker supplies input designed to miss that closing character, the pattern can backtrack over the same data again and again. As a result, pattern matching may take an excessive amount of CPU, causing the process to hang or even bring down web servers.
Here’s a code snippet showing the root of the problem (abstracted from real micromatch code)
// Part of micromatch/index.js
function braces(input) {
// Simplified vulnerable code
const regex = /(.*)\}/;
const match = regex.exec(input);
if (match) {
// do something with match
}
}
Suppose the code processes an input like
braces('{'.repeat(10000));
Because .* is greedy, it will keep trying all possible ways of matching the string looking for the closing }. The longer the input, the more backtracking occurs, and the slower your application becomes.
How an Attack Works
A malicious user can trigger this vulnerability with a string that lacks the closing curly brace but has a long sequence of opening braces. For example:
const payload = '{'.repeat(100000); // 100,000 opening braces
micromatch.braces(payload); // This call may hang
This simple exploit can be fed into servers using micromatch for user input file path filtering or globbing. If your API endpoint ingests untrusted strings for pattern matching, attackers can freeze your Node.js process with very little effort.
Here’s a basic proof of concept (PoC)
const micromatch = require("micromatch");
const payload = "{".repeat(20000); // Large input, no closing brace
// This line may freeze or hang criminally slow:
micromatch.braces(payload);
console.log("Done"); // May never reach here
As you increase the number of opening braces, the function takes exponentially more time, eventually bringing your server to a crawl.
The Fix: What Went Wrong?
A patch was proposed and merged in early June 2024 that tried to limit the impact:
// Hypothetical fix (not actual code)
const safeRegex = /([^\}]*)\}/; // Non-greedy matching
However, recent security reviews found that the patch wasn't enough. Some crafty payloads were still able to bypass the fix due to alternative regex patterns within the codebase that still relied on greedy expressions. The central issue remains: as long as there is a greedy .* before the closing } in a regex, ReDoS is possible.
How To Protect Your App
Since the current stable release of micromatch is still vulnerable, you can protect your projects now with the following steps:
1. Sanitize Input
Never allow user-supplied input directly into glob or brace patterns. Validate and sanity-check any incoming data.
2. Limit Input Length
Impose strict maximum lengths for any field that will be used in pattern matching. ReDoS attacks are only practical with large strings.
if (pattern.length > 256) {
throw new Error("Pattern too long!");
}
3. Use Safe Regexes
Replace greedy .* or similar patterns with non-greedy versions or with explicit character exclusions. For example, [^\}]* instead of .*.
4. Upgrade When Safe
Track the micromatch GitHub repo or subscribe to NPM advisories for patch releases. As of June 2024, no complete fix is available; watch for updates to this security advisory.
References
- Original Micromatch Repo
- PR Attempting Fix
- CVE-2024-4067 at NVD *(pending publication)*
- OWASP: Regular expression Denial of Service - ReDoS
Conclusion
Greedy regular expressions are a classic source of vulnerabilities in JavaScript projects that process untrusted input. CVE-2024-4067 in micromatch reminds us that even mature, trusted open source packages can still have lurking bugs. Until a complete fix is released, be cautious, avoid using uncontrolled input in micromatch patterns, and watch for security updates!
Timeline
Published on: 05/14/2024 15:42:47 UTC
Last modified on: 05/22/2024 12:15:10 UTC