Skip to main content
interlace
Plugin: mongodb-securityRules

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

AspectDetails
CWE ReferenceCWE-400 (Resource Exhaustion)
OWASPA03:2021 - Injection
SeverityHigh (CVSS: 7.5)
CategorySecurity

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

ComponentPurposeExample
Risk StandardsSecurity benchmarksCWE-400 OWASP:A06 CVSS:7.5
Issue DescriptionSpecific vulnerabilityUncontrolled Resource Consumption (ReDoS) detected
Severity & ComplianceImpact assessmentHIGH
Fix InstructionActionable remediationFollow the remediation steps below
Technical TruthOfficial referenceOWASP Top 10

Rule Details

User input in $regex operators is dangerous because:

  1. ReDoS attacks: Crafted regex patterns can cause exponential backtracking
  2. Information disclosure: Regex can be used to probe for data patterns
  3. 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

OptionTypeDefaultDescription
allowInTestsbooleantrueSkip this rule in *.test.* / *.spec.* files

Use this rule

npm install -D oxlint-plugin-mongodb-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-mongodb-security"],  "rules": {    "mongodb-security/no-unsafe-regex-query": "error"  }}
vite.config.ts
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.