no-unsafe-regex-query
Detects user input in MongoDB $regex operators that could cause ReDoS (Regular Expression Denial of Service) or infor...
Detects user input in MongoDB $regex operators that could cause ReDoS (Regular Expression Denial of Service) or information disclosure.
⚠️ This rule errors by default in the recommended config.
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-400 (Resource Exhaustion) |
| OWASP | A03:2021 - Injection |
| Severity | High (CVSS: 7.5) |
| Category | Security |
Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
🔒 CWE-400 OWASP:A06 CVSS:7.5 | Uncontrolled Resource Consumption (ReDoS) detected | HIGH
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A06_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-400 OWASP:A06 CVSS:7.5 |
| Issue Description | Specific vulnerability | Uncontrolled Resource Consumption (ReDoS) detected |
| Severity & Compliance | Impact assessment | HIGH |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Rule Details
User input in $regex operators is dangerous because:
- ReDoS attacks: Crafted regex patterns can cause exponential backtracking
- Information disclosure: Regex can be used to probe for data patterns
- Injection: Special regex characters can alter query behavior
Attack Example
// Attacker sends: "(a+)+$"
// This causes exponential backtracking on strings like "aaaaaaaaaa!"
db.users.find({ email: { $regex: userInput } });❌ Incorrect
// User input directly in $regex
User.find({ name: { $regex: req.query.search } });
// User input as regex pattern
User.find({ email: { $regex: new RegExp(userInput) } });
// User input with $options
User.find({ name: { $regex: req.body.pattern, $options: 'i' } });
// A RegExp value is matched exactly like $regex (with or without `new`)
User.find({ name: new RegExp(req.query.search) });
User.find({ name: RegExp(req.query.search, 'i') });
// Inside a $or / $and / $nor branch
User.find({ $or: [{ name: { $regex: req.query.search } }, { active: true }] });✅ Correct
// Escape special regex characters
import escapeRegex from 'escape-string-regexp';
User.find({ name: { $regex: escapeRegex(req.query.search), $options: 'i' } });
// Use $text search instead (indexed, safer)
User.find({ $text: { $search: req.query.search } });
// Anchor and limit pattern
const safePattern = `^${escapeRegex(req.query.search).slice(0, 50)}`;
User.find({ name: { $regex: safePattern } });
// An escaped value interpolated inline — escapeRegex, escapeRegExp,
// _.escapeRegExp, or the default export of escape-string-regexp /
// lodash.escaperegexp under any name
User.find({ name: { $regex: `^${escapeRegex(req.query.search)}` } });
User.find({ name: { $regex: `^${_.escapeRegExp(req.query.search)}$` } });
// Use MongoDB text index
db.users.createIndex({ name: 'text' });
User.find({ $text: { $search: userInput } });Known False Negatives
Sanitized Input
// ❌ NOT DETECTED - but may still be vulnerable
const sanitized = userInput.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
User.find({ name: { $regex: sanitized } });Escapers Recognised by Name
// ✅ NOT REPORTED - a helper named escapeRegex is trusted to escape
const escapeRegex = (s) => s;
User.find({ name: { $regex: `^${escapeRegex(req.query.q)}` } });Mitigation: Import the escaper from escape-string-regexp or lodash rather than hand-rolling it.
When Not To Use It
- When using escape-string-regexp or similar libraries consistently
- When regex patterns are from trusted source (internal config)
References
⚙️ Options
| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip this rule in *.test.* / *.spec.* files |
Use this rule
npm install -D oxlint-plugin-mongodb-security{ "jsPlugins": ["oxlint-plugin-mongodb-security"], "rules": { "mongodb-security/no-unsafe-regex-query": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-mongodb-security'], rules: { 'mongodb-security/no-unsafe-regex-query': 'error', }, },});oxlint-plugin-mongodb-security re-exports eslint-plugin-mongodb-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.
Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.