Regex Dos in Feathersjs
How Regex Dos Manifests in Feathersjs
Regular expression denial of service (ReDoS) attacks exploit poorly constructed regex patterns that can cause exponential backtracking, leading to CPU exhaustion. In Feathersjs applications, this vulnerability often manifests in several critical areas.
The most common attack vector is through query filtering. Feathersjs allows clients to pass complex filter objects to database queries, which are then translated into MongoDB queries. Consider this vulnerable service:
const { NotFound } = require('@feathersjs/errors');
class VulnerableService {
async find(params) {
const { query } = params;
// Client-controlled regex patterns
if (query.email) {
const regex = new RegExp(query.email, 'i');
return this._find({ query: { email: regex } });
}
return this._find({ query });
}
}
An attacker can send a request like:
{
"email": "(a+)+b"
}
This pattern causes catastrophic backtracking because the regex engine tries every possible combination of the repeated group. With just 30 characters of input, this can take seconds to process, and with 50+ characters, it can hang the Node.js process entirely.
Another Feathersjs-specific scenario involves service hooks that process regex patterns. Consider a hook that validates email addresses:
const hooks = require('@feathersjs/hooks');
class UserService {
@hooks.before({
create: [
async context => {
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!emailRegex.test(context.data.email)) {
throw new Error('Invalid email');
}
}
]
})
async create(data, params) {
return this._create(data, params);
}
}
The problem here is that the regex pattern itself is vulnerable to ReDoS. An attacker could craft an email like "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!" that triggers exponential backtracking in the pattern's character classes.
Feathersjs's real-time features also introduce attack surfaces. When using socket.io or similar transports, clients can send filter objects that are processed on the server. A vulnerable pattern might look like:
app.service('messages').on('created', async (data, context) => {
const { text } = data;
// Vulnerable regex processing
const pattern = new RegExp(context.params.query.filter || '.*');
if (pattern.test(text)) {
// Process message
}
});
The combination of Feathersjs's flexible query syntax and Node.js's regex engine creates a perfect storm for ReDoS attacks, especially when user input flows through multiple layers of regex processing.
Feathersjs-Specific Detection
Detecting ReDoS vulnerabilities in Feathersjs applications requires a multi-layered approach. The first step is static analysis of your codebase to identify dangerous regex patterns and dynamic query handling.
Using middleBrick's API security scanner, you can automatically detect ReDoS vulnerabilities in your Feathersjs endpoints. The scanner tests for:
- Regex patterns with nested quantifiers like (a+)+, (a*)*
- Character class alternations with overlapping ranges [a-zA-Z0-9]
- Backtracking-heavy patterns like (a|aa)*
- Dynamic regex construction from user input
middleBrick's LLM/AI security module also checks for prompt injection vulnerabilities that might be exploited alongside ReDoS attacks in AI-powered Feathersjs applications.
For manual detection, use this Feathersjs-specific scanning approach:
const { execSync } = require('child_process');
// Scan for vulnerable regex patterns
function scanForReDoS(serviceCode) {
const vulnerablePatterns = [
/(/[^/]+/[gimy]*)\s*=/g, // Finds regex literals
/new\s+RegExp\s*\(/g, // Finds RegExp constructors
];
const matches = [];
for (const pattern of vulnerablePatterns) {
let match;
while ((match = pattern.exec(serviceCode)) !== null) {
matches.push(match[0]);
}
}
return matches;
}
// Test regex performance
function testRegexPerformance(pattern, input) {
const start = process.hrtime();
try {
const regex = new RegExp(pattern);
regex.test(input);
const diff = process.hrtime(start);
const ms = diff[0] * 1000 + diff[1] / 1e6;
return ms < 100; // Safe if under 100ms
} catch (error) {
return false;
}
}
// Example usage
const serviceFile = execSync('cat src/services/users.service.js').toString();
const patterns = scanForReDoS(serviceFile);
for (const pattern of patterns) {
if (!testRegexPerformance(pattern, 'a'.repeat(50))) {
console.log('VULNERABLE:', pattern);
}
}
middleBrick's continuous monitoring (Pro plan) can automatically scan your Feathersjs APIs on a schedule, alerting you when new ReDoS vulnerabilities are detected in production.
Feathersjs-Specific Remediation
Fixing ReDoS vulnerabilities in Feathersjs requires both immediate patches and architectural changes to prevent future issues. Here are Feathersjs-specific remediation strategies:
1. Input Validation and Sanitization
const { BadRequest } = require('@feathersjs/errors');
function safeEmailFilter(email) {
// Only allow simple email patterns
const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailPattern.test(email)) {
throw new BadRequest('Invalid email format');
}
// Use non-capturing groups and avoid nested quantifiers
return new RegExp(`^${email}$`, 'i');
}
class SafeUserService {
async find(params) {
const { query } = params;
if (query.email) {
const safeRegex = safeEmailFilter(query.email);
return this._find({ query: { email: safeRegex } });
}
return this._find({ query });
}
}
2. Rate Limiting and Timeouts
const { Timeout } = require('@feathersjs/errors');
class ProtectedService {
async find(params) {
const { query } = params;
// Set a timeout for regex operations
const timeoutPromise = new Promise((resolve, reject) => {
setTimeout(() =>
reject(new Timeout('Regex operation timed out')), 100);
});
// Use Promise.race to enforce timeout
return Promise.race([
this._find({ query }),
timeoutPromise
]);
}
}
3. Use Safe Regex Libraries
const safeRegex = require('safe-regex');
function validateRegex(pattern) {
if (!safeRegex(pattern)) {
throw new Error('Regex pattern is potentially unsafe');
}
return new RegExp(pattern);
}
// In your service
class SecureService {
async find(params) {
const { query } = params;
if (query.filter) {
const regex = validateRegex(query.filter);
return this._find({ query: { $regex: regex } });
}
return this._find({ query });
}
}
4. Database-Level Protection
// Use MongoDB's $regex with safe patterns
class MongoService {
async find(params) {
const { query } = params;
// Only allow simple patterns
const safePatterns = {
email: /^[a-z0-9._%+-]+$/i,
username: /^[a-z0-9_-]+$/i
};
const safeQuery = {};
for (const [key, value] of Object.entries(query)) {
if (safePatterns[key] && safePatterns[key].test(value)) {
safeQuery[key] = { $regex: value, $options: 'i' };
} else {
safeQuery[key] = value;
}
}
return this._find({ query: safeQuery });
}
}
5. Continuous Monitoring with middleBrick
The Pro plan includes continuous monitoring that automatically scans your Feathersjs APIs for ReDoS vulnerabilities. You can set up GitHub Actions to run middleBrick scans before deployment:
name: API Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install -g middlebrick
- run: middlebrick scan https://api.yourdomain.com
env:
MIDDLEBRICK_API_KEY: ${{ secrets.MIDDLEBRICK_API_KEY }}
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |