[Security][Go-live] Unescaped user input used as Mongo regex → ReDoS / regex-injection (incl. anonymous lesson search) #436

Closed
opened 2026-07-06 06:34:07 +00:00 by spikerj · 1 comment
Owner

Problem

Two search paths pass raw user input straight into a Mongo BsonRegularExpression, so the user-supplied string is evaluated as a regex, server-side:

  • SpikerSoft.Business/Domain/Lessons/Queries/GetAllLessons/GetAllLessonsQueryHandler.cs:47-48request.SearchTerm on Title/Description. GetAllLessons is anonymous-by-omission (see #415), so this is an unauthenticated DoS lever.
  • SpikerSoft.EventHandlers.CodeExecution/Services/UserSubmittedCodeService.cs:336-338searchTerm on Code/Tags/UserNotes.

A crafted catastrophic-backtracking pattern (e.g. (a+)+$) submitted as the search term is executed by the Mongo server and can pin the shared cluster's CPU — an #411-class availability bomb — and it's a regex-injection (unexpected match semantics) besides.

The safe pattern already exists in the repo: OpsSecurityAlertQueryBuilder / OpsIncidentQueryBuilder wrap the value in Regex.Escape(...).

Fix

Introduced SpikerSoft.Data.Search.MongoRegexSearch.LiteralContains(term)Regex.Escapes the term so it matches literally (which is the behaviour a search box should have anyway) — and routed both call sites (all 5 usages) through it. Escaping neutralizes the metacharacters that enable ReDoS.

Note: this changes search from "regex" to "literal substring" — the correct/expected behaviour for these boxes; no one is relying on regex search in a kids' lessons/code finder.

Verification

MongoRegexSearchTests (6): escapes catastrophic/metacharacter inputs to their literal form, options stay case-insensitive, null-safe. Build clean.

Resolved by spikersoft-backend PR (linked below). Filing so the fix is traceable.

## Problem Two search paths pass **raw user input** straight into a Mongo `BsonRegularExpression`, so the user-supplied string is evaluated **as a regex, server-side**: - `SpikerSoft.Business/Domain/Lessons/Queries/GetAllLessons/GetAllLessonsQueryHandler.cs:47-48` — `request.SearchTerm` on Title/Description. **`GetAllLessons` is anonymous-by-omission** (see #415), so this is an **unauthenticated** DoS lever. - `SpikerSoft.EventHandlers.CodeExecution/Services/UserSubmittedCodeService.cs:336-338` — `searchTerm` on Code/Tags/UserNotes. A crafted catastrophic-backtracking pattern (e.g. `(a+)+$`) submitted as the search term is executed by the Mongo server and can **pin the shared cluster's CPU** — an #411-class availability bomb — and it's a regex-injection (unexpected match semantics) besides. The **safe pattern already exists** in the repo: `OpsSecurityAlertQueryBuilder` / `OpsIncidentQueryBuilder` wrap the value in `Regex.Escape(...)`. ## Fix Introduced `SpikerSoft.Data.Search.MongoRegexSearch.LiteralContains(term)` — `Regex.Escape`s the term so it matches **literally** (which is the behaviour a search box should have anyway) — and routed both call sites (all 5 usages) through it. Escaping neutralizes the metacharacters that enable ReDoS. Note: this changes search from "regex" to "literal substring" — the correct/expected behaviour for these boxes; no one is relying on regex search in a kids' lessons/code finder. ## Verification `MongoRegexSearchTests` (6): escapes catastrophic/metacharacter inputs to their literal form, options stay case-insensitive, null-safe. Build clean. Resolved by spikersoft-backend PR (linked below). Filing so the fix is traceable.
Author
Owner

Resolved in spikersoft-backend PR #126 (merged to master as b5bb73d). MongoRegexSearch.LiteralContains now Regex.Escapes user search input at all 5 sites (GetAllLessons + UserSubmittedCode); ReDoS/regex-injection closed, incl. the anonymous lesson-search path. 6/6 tests. Closing.

Resolved in spikersoft-backend PR #126 (merged to `master` as `b5bb73d`). `MongoRegexSearch.LiteralContains` now `Regex.Escape`s user search input at all 5 sites (GetAllLessons + UserSubmittedCode); ReDoS/regex-injection closed, incl. the anonymous lesson-search path. 6/6 tests. Closing.
Sign in to join this conversation.