-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Major - P3
-
Affects Version/s: 2.14.0
-
Component/s: None
-
None
-
0.1
-
Dotnet Drivers
-
Not Needed
-
None
-
None
-
None
-
None
-
None
-
None
Summary
An application user whose input becomes a key or field name in a LINQ query can silently redirect that query or update to different database fields.
Impact
Queries and updates silently target different fields, documents, or array elements than the C# expression describes — enabling boolean-oracle probing of unintended fields (including other users' documents in shared collections), broadening of update scope to all array elements, and application-level filter-logic bypass, with no error signaled anywhere.
Severity: high
Exploitability: likely_exploitable — Given any application that feeds user strings into these LINQ positions (user-named attribute/metadata lookups are a common pattern), exploitation is deterministic — the attacker fully controls the injected path segment and no check anywhere in the translation or rendering pipeline inspects it.
Customer data: customer_content, customer_metadata (api_response)
Location
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFilterField.cs:49 in AstFilterField.SubField
- src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs:106 in TranslateDictionaryGetItemWithKey
- src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs:75 in TranslateBsonValueGetItemWithString
- src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/FieldMethodToFilterFieldTranslator.cs:41 in FieldMethodToFilterFieldTranslator.Translate
- src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/AllMatchingElementsMethodToFilterFieldTranslator.cs:49 in AllMatchingElementsMethodToFilterFieldTranslator.Translate
- src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsKeyMethodToFilterTranslator.cs:47 in ContainsKeyMethodToFilterTranslator.Translate
- src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFieldOperationFilter.cs:61 in AstFieldOperationFilter.Render
Reproduction / trigger path
Analyzed trigger path from static analysis — not an executed PoC. Confirm with a concrete repro before handing off.
Attacker controls: Full content of one field-path segment in the rendered filter: '.' splits it into nested traversal ('a.b' queries subdocument b of a instead of a literal key), '$'-prefixed segments enter operator-lookalike positions, ']'/'.' inside an AllMatchingElements identifier restructures the '$[...]' array-filter segment, null identifier silently becomes '$[]' (all array elements), and a null Mql.Field name throws ArgumentNullException instead of a translation error.
- (source) src/MongoDB.Driver/Linq/Linq3Implementation/Misc/PartialEvaluator.cs:41 in PartialEvaluator.EvaluatePartially — Attacker-influenced runtime strings captured in the application's LINQ expression (dictionary keys, Mql.Field names, AllMatchingElements identifiers) are folded into ConstantExpressions before translation.
- (hop) src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/MethodCallExpressionToFilterFieldTranslator.cs:33 in MethodCallExpressionToFilterFieldTranslator.Translate — Dispatcher routes get_Item / Field / AllMatchingElements calls to the producer translators (lines 28, 30, 33).
- (hop) src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs:106 in TranslateDictionaryGetItemWithKey — Serialized dictionary key passes only an 'is not BsonString' type check (line 101); content with '.', '$', or brackets flows through to SubField.
- (hop) src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/TranslatedFilterField.cs:37 in TranslatedFilterField.SubField — Forwards the sub-field name unchanged to the AST layer; no validation layer exists between translators and concatenation.
- (sink) src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFilterField.cs:49 in AstFilterField.SubField — Raw concatenation _path + "." + subFieldName; Render() (line 53) emits the string, and AstFieldOperationFilter.Render (AstFieldOperationFilter.cs:61) makes it the element name of the wire filter document that the MongoDB server interprets structurally.
Root cause
- AstFilterField.SubField (src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFilterField.cs:49) builds field paths by raw concatenation (_path + "." + subFieldName); the only guard is a null check at line 41, and Render() at line 53 emits the raw string.
- All five producers pass strings through unchecked: dictionary keys (GetItemMethodToFilterFieldTranslator.cs:106, guarded only by an 'is not BsonString' type check at :101), BsonValue keys (:75), Mql.Field names (FieldMethodToFilterFieldTranslator.cs:38-41), ContainsKey arguments (ContainsKeyMethodToFilterTranslator.cs:47), and AllMatchingElements identifiers (AllMatchingElementsMethodToFilterFieldTranslator.cs:38-49, which rejects only "" so null yields '$[]').
- PartialEvaluator (src/MongoDB.Driver/Linq/Linq3Implementation/Misc/PartialEvaluator.cs:41) folds captured runtime variables into constants, so runtime user input reaches GetConstantValue and then SubField.
- AstFieldOperationFilter.Render (src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Filters/AstFieldOperationFilter.cs:61) makes the concatenated path the element name of the wire filter document, which the server interprets structurally; by contrast the aggregation side guards exactly this case (AstGetFieldExpression.cs:69 checks for leading '$' and embedded '.' and falls back to a safe $getField form), a guard the filter side lacks.
Ownership
Assigned teams: @mongodb/dbx-csharp-dotnet
Filed from Aegis finding 2fa978de4893 (scan scan-320b0a32a42c) · primitive: Attacker string containing dots, dollars, brackets, or null is concatenated verbatim into the MQL filter field path, redirecting query matching and update targeting. · categories: NoSQL Injection, Data Corruption