Regex Missing Timeout
Learn how to prevent Regex Missing Timeout vulnerabilities with real code examples and best practices. Protect your application from denial of service attacks caused by regex patterns.
Tools recognizing this:
Fortify Checkmarx SonarQube Snyk Semgrep CodeQL
What is Regex Missing Timeout and How Does it Work?
Regex Missing Timeout is a security vulnerability that occurs when regular expressions are executed without a timeout limit. This can lead to denial of service attacks through catastrophic backtracking, where a malicious input causes the regex engine to spend excessive time processing.
The vulnerability can be exploited when:
Complex regex patterns are used without timeout controls
User input can influence the string being matched
The regex pattern is susceptible to catastrophic backtracking
No execution time limits are set for the regex operation
This guide covers Regex Missing Timeout vulnerabilities, examples, prevention methods, and how to implement proper timeout controls using real-world techniques.
One Simple Regex Missing Timeout Attack Example
Consider this vulnerable regex implementation:
Regex regex = new Regex("^(a+)+b$");
bool isMatch = regex.IsMatch(userInput);An attacker could provide this input:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaX
This input would cause catastrophic backtracking, potentially freezing the application as the regex engine attempts to process all possible combinations.
Regex Missing Timeout Prevention Methods: How to Fix Your Code
The most efficient way to fix a Regex Missing Timeout issue is by implementing proper timeout controls when executing regular expressions.
Adding timeouts ensures that regex operations cannot run indefinitely, protecting against denial of service attacks. Different programming languages offer various mechanisms to implement these controls.
Code Samples
Vulnerable Code
string pattern = @"^(a+)+b$";
string input = userInput;
Regex regex = new Regex(pattern);
bool isMatch = regex.IsMatch(input);Fixed Code
string pattern = @"^(a+)+b$";
string input = userInput;
Regex regex = new Regex(pattern, RegexOptions.None, TimeSpan.FromMilliseconds(30000));
bool isMatch = regex.IsMatch(input);Fix Explanation
The vulnerable code creates a Regex without timeout controls.The fix adds a timeout parameter of 30 seconds using TimeSpan.FromMilliseconds.If the regex operation exceeds the timeout, it throws a RegexMatchTimeoutException.This prevents infinite processing of malicious inputs.
Vulnerable Code
String pattern = "^(a+)+b$";
Pattern regex = Pattern.compile(pattern);
boolean isMatch = regex.matcher(userInput).matches();Fixed Code
String pattern = "^(a+)+b$";
Pattern regex = Pattern.compile(pattern);
RegexTimeout timeout = new RegexTimeout(30, TimeUnit.SECONDS);
boolean isMatch = timeout.matches(regex, userInput);
class RegexTimeout {
private final long timeout;
private final TimeUnit unit;
public RegexTimeout(long timeout, TimeUnit unit) {
this.timeout = timeout;
this.unit = unit;
}
public boolean matches(Pattern pattern, String input) {
FutureTask<Boolean> task = new FutureTask<>(() ->
pattern.matcher(input).matches());
Thread thread = new Thread(task);
thread.start();
try {
return task.get(timeout, unit);
} catch (TimeoutException e) {
thread.interrupt();
throw new RuntimeException("Regex timeout exceeded");
}
}
}Fix Explanation
The vulnerable code has no timeout mechanism for regex operations.The fix implements a custom timeout wrapper using FutureTask and Thread.The regex operation runs in a separate thread with a specified timeout.If the timeout is exceeded, the thread is interrupted and an exception is thrown.
Vulnerable Code
import re
pattern = r'^(a+)+b$'
regex = re.compile(pattern)
is_match = bool(regex.match(user_input))Fixed Code
import re
import signal
from contextlib import contextmanager
@contextmanager
def timeout(seconds):
def timeout_handler(signum, frame):
raise TimeoutError("Regex timeout exceeded")
original_handler = signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, original_handler)
pattern = r'^(a+)+b$'
regex = re.compile(pattern)
try:
with timeout(30):
is_match = bool(regex.match(user_input))
except TimeoutError:
is_match = FalseFix Explanation
The vulnerable code has no timeout mechanism.The fix implements a context manager using signal.SIGALRM.Sets a 30-second timeout for the regex operation.If the timeout is exceeded, raises a TimeoutError.Note: This solution works only on Unix-like systems.
Vulnerable Code
const pattern = /^(a+)+b$/;
const isMatch = pattern.test(userInput);Fixed Code
function regexWithTimeout(pattern, input, timeout = 30000) {
return new Promise((resolve, reject) => {
const worker = new Worker(
URL.createObjectURL(new Blob([`
self.onmessage = function(e) {
const pattern = new RegExp(e.data.pattern);
const isMatch = pattern.test(e.data.input);
self.postMessage(isMatch);
}
`], { type: 'text/javascript' }))
);
const timeoutId = setTimeout(() => {
worker.terminate();
reject(new Error('Regex timeout exceeded'));
}, timeout);
worker.onmessage = (e) => {
clearTimeout(timeoutId);
worker.terminate();
resolve(e.data);
};
worker.postMessage({ pattern: pattern.source, input });
});
}
// Usage
const pattern = /^(a+)+b$/;
try {
const isMatch = await regexWithTimeout(pattern, userInput);
} catch (error) {
console.error('Regex timeout:', error);
}Fix Explanation
The vulnerable code has no timeout controls.The fix uses a Web Worker to run regex in a separate thread.Implements a timeout using Promise and setTimeout.If the timeout is exceeded, the worker is terminated.This prevents the main thread from being blocked by long-running regex operations.
Vulnerable Code
$pattern = '/^(a+)+b$/';
$isMatch = preg_match($pattern, $userInput);Fixed Code
function regexWithTimeout($pattern, $input, $timeout = 30) {
$previousLimit = ini_get('max_execution_time');
set_time_limit($timeout);
try {
$startTime = microtime(true);
$isMatch = preg_match($pattern, $input);
if (microtime(true) - $startTime >= $timeout) {
throw new Exception('Regex timeout exceeded');
}
return $isMatch;
} finally {
set_time_limit($previousLimit);
}
}
try {
$pattern = '/^(a+)+b$/';
$isMatch = regexWithTimeout($pattern, $userInput);
} catch (Exception $e) {
// Handle timeout exception
}Fix Explanation
The vulnerable code has no timeout mechanism.The fix implements a wrapper function with timeout control.Uses set_time_limit() to enforce a maximum execution time.Monitors actual execution time using microtime().Restores original time limit after execution.
Need more help in preventing Regex Missing Timeout?
Mobb supports fixing many forms of Regex Missing Timeout vulnerabilities, and can mitigate your issues in batch.
Start now for free at app.mobb.ai
We'd love your feedback!
We're excited to hear your thoughts and ideas about fixing vulnerabilities.
Book a meeting or Contact us if you have any corrections, questions or suggestions. Start now for free at https://app.mobb.ai
Last updated
Was this helpful?