-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Critical - P2
-
Affects Version/s: None
-
Component/s: None
-
None
-
0.2
-
Fully Compatible
-
Dotnet Drivers
-
Not Needed
-
None
-
None
-
None
-
None
-
None
-
None
Summary
Attackers who control a document compared for equality can smuggle query operators, making the database match and reveal records it never should.
Impact
Untrusted input intended as a literal equality comparand is executed as query operators, letting attackers read records they should not see, bypass equality-based lookup/authorization checks, and cause updates or deletes to hit the wrong documents.
Severity: critical
Exploitability: exploitable — Any application comparing a document-typed field to untrusted input via LINQ equality is exploitable with a single crafted payload such as
; the attacker fully controls the injected operator document.
Customer data: customer_content, credentials, pii (api_response)
Location
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs:163 in VisitFieldOperationFilter
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs:234 in VisitFieldOperationFilter (IsFieldEqValue guard)
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs:184 in VisitFieldOperationFilter ($elemMatch $eq collapse)
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstImpliedOperationFilterOperation.cs:41 in Render
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFieldOperationFilter.cs:61 in Render
- src/MongoDB.Driver/Linq/LinqProviderAdapter.cs:152 in TranslateExpressionToFilter
Reproduction / trigger path
Analyzed trigger path from static analysis — not an executed PoC. Confirm with a concrete repro before handing off.
Attacker controls: Full control of the operator document applied to the compared field: any query operator and arguments ($ne, $gt, $lt, $in, $regex, $exists, $where is not reachable since injection is field-level), enabling match-everything, match-nothing, and blind regex-based data extraction.
- (source) src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs:94 in Translate — Attacker-influenced constant comparand (e.g. user-supplied BsonDocument) is serialized without any operator-shape validation.
- (hop) src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFilter.cs:91 in Compare — Builds AstFieldOperationFilter with AstComparisonFilterOperation(Eq, value) — the safe explicit {field:{$eq:value}} form.
- (hop) src/MongoDB.Driver/Linq/LinqProviderAdapter.cs:152 in TranslateExpressionToFilter — Every LINQ-expression filter (Find, Builders.Filter.Where; pipelines via AstPipelineOptimizer.cs:23) is passed through AstSimplifier unconditionally.
- (hop) src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs:163 in VisitFieldOperationFilter — IsFieldEqValue (line 232-238, regex-only guard) matches; explicit $eq is replaced by AstImpliedOperationFilterOperation carrying the raw dollar-keyed document. Same collapse for $elemMatch $eq at line 184.
- (sink) src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFieldOperationFilter.cs:61 in Render — Renders
{field: rawValue}
(via AstImpliedOperationFilterOperation.Render:41) into the query document sent to the MongoDB server, which parses the dollar-keyed value as query operators — the injection sink.
Root cause
- The translator serializes a constant equality comparand of any shape and builds the safe explicit form {field:{$eq:value}} with no operator-shape check (src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs:94-95, AstFilter.cs:89-91).
- AstSimplifier.VisitFieldOperationFilter rewrites {field:{$eq:value}} (and {field:{$elemMatch:{$eq:value}}}) to implied equality
{field:value}
; its guards IsFieldEqValue and IsFieldElemMatchEqValue only exclude BsonType.RegularExpression, admitting BsonDocument values whose first element name starts with '$' (AstSimplifier.cs:161-164, 184, 232-238, 271-287).
- AstImpliedOperationFilterOperation.Render returns the raw value and AstFieldOperationFilter.Render emits
{fieldPath: value}
with no re-validation (AstImpliedOperationFilterOperation.cs:39-42, AstFieldOperationFilter.cs:61).
- The simplifier runs unconditionally on every LINQ filter surface: Find/Builders.Filter.Where (LinqProviderAdapter.cs:152), elemMatch filters (LinqProviderAdapter.cs:137), and aggregate/queryable pipelines (AstPipelineOptimizer.cs:23); the MongoDB server parses a dollar-keyed document in that position as query operators.
Ownership
Assigned teams: @mongodb/dbx-csharp-dotnet
Filed from Aegis finding b82befbd7791 (scan scan-320b0a32a42c) · primitive: Dollar-keyed document constants survive equality-filter simplification and render as raw query operators, converting literal equality comparisons into attacker-chosen predicates. · categories: NoSQL Injection, Data Corruption, Authentication Bypass
- is related to
-
CSHARP-6210 NoSQL injection via equality-filter simplification of dollar-keyed documents in the LINQ provider (port to main branch)
-
- Needs Triage
-