Injection Flaws in Aspnet with Mongodb
Injection Flaws in Aspnet with Mongodb — how this specific combination creates or exposes the vulnerability
Injection flaws in an ASP.NET application that uses MongoDB typically arise when untrusted input is concatenated into database queries or the LINQ pipeline without proper validation or parameterization. Unlike SQL, MongoDB does not support parameterized queries in the same way, so developers must rely on correct usage of the official driver and deliberate design patterns to avoid injection.
In ASP.NET, common injection surfaces include query filters built dynamically from request parameters, LINQ expressions constructed from user input, and aggregation pipelines assembled with raw BSON or JSON strings. Because ASP.NET often deserializes JSON payloads into C# objects and then passes those values into MongoDB operations, attackers can supply crafted payloads that change the structure or semantics of queries. For example, a filter built by merging user-supplied JSON directly into a Builders can inadvertently expose fields or bypass intended access controls.
The risk is amplified when applications implement custom query logic or use string interpolation to construct filter definitions, such as embedding field names or values directly into JSON-like structures. This can lead to unintended document retrieval, data exfiltration, or manipulation of more records than intended. Injection flaws may also interact with other checks in middleBrick’s scan, such as Input Validation and Property Authorization, revealing that field-level authorization was not enforced server-side.
Real-world attack patterns mirror issues cataloged in the OWASP API Top 10 and can be discovered when scan findings highlight unsafe consumption or missing input validation. For instance, an endpoint that accepts a JSON filter object and uses BsonDocument.Parse to build a query is vulnerable if the JSON is not strictly validated. Similarly, aggregation pipelines that include user-controlled stages or expressions can be coerced into leaking information or bypassing rate-limiting logic.
middleBrick detects these risks by analyzing OpenAPI/Swagger specifications (including $ref resolution) and comparing declared behavior with runtime findings across its 12 security checks. This includes checks for Input Validation, Property Authorization, and Unsafe Consumption, which help identify where untrusted data enters the MongoDB interaction layer. Because middleBrick performs unauthenticated, black-box scanning, it can surface insecure endpoint designs without requiring credentials.
Mongodb-Specific Remediation in Aspnet — concrete code fixes
To reduce injection risk in ASP.NET with MongoDB, use the official MongoDB .NET driver safely, validate and sanitize all inputs, and avoid dynamic query assembly. Prefer strongly typed filter definitions and the driver’s built-in expression trees instead of raw JSON or string concatenation.
1. Use FilterDefinitionBuilder and avoid raw BSON/JSON injection
Never parse untrusted JSON directly into a BsonDocument for queries. Instead, use FilterDefinitionBuilder<T> to construct queries safely.
// Unsafe: directly parsing user input
var userFilter = BsonDocument.Parse(userSuppliedJson);
var collection = database.GetCollection<MyEntity>("items");
var unsafeResults = await collection.Find(userFilter).ToListAsync();
// Safe: use strongly typed filter builder
var filter = Builders<MyEntity>.Filter.Eq(x => x.OwnerId, userId);
if (!string.IsNullOrEmpty(searchTerm))
{
filter &= Builders<MyEntity>.Filter.Regex(x => x.Name, new BsonRegularExpression(searchTerm, "i"));
}
var results = await collection.Find(filter).ToListAsync();
2. Validate and bind input models explicitly
Use ASP.NET model validation and bind to DTOs with strict rules. Reject unexpected fields and validate formats before using values in queries.
public class ItemFilterDto
{
[Required]
[Range(1, int.MaxValue)]
public int? MaxResults { get; set; }
[RegularExpression(@"^[a-zA-Z0-9_]+$")]
public string SortField { get; set; }
}
[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
private readonly IMongoCollection<MyEntity> _collection;
public ItemsController(IMongoDatabase database)
{
_collection = database.GetCollection<MyEntity>("items");
}
[HttpGet]
public async Task<ActionResult<IEnumerable<MyEntity>>> List([FromQuery] ItemFilterDto dto)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var filter = Builders<MyEntity>.Filter.Empty;
if (!string.IsNullOrEmpty(dto.SortField))
{
// Safe: field name validated via regex
var sortDefinition = new BsonDocument("_" + dto.SortField, 1);
// Use sortDefinition with caution; ensure field mapping is strict
var cursor = await _collection.Find(filter).Sort(sortDefinition).Limit(dto.MaxResults ?? 50).ToListAsync();
return Ok(cursor);
}
var results = await _collection.Find(filter).Limit(dto.MaxResults ?? 50).ToListAsync();
return Ok(results);
}
}
3. Secure aggregation pipelines and avoid concatenation
If you must use aggregation, construct pipeline stages programmatically and avoid inserting raw user input into stage definitions.
var pipeline = PipelineDefinition<MyEntity, BsonDocument>.Create(new[]
{
// Safe: stage defined by code, not user input
PipelineStageDefinitionBuilder.Match(Builders<MyEntity>.Filter.Gte(x => x.CreatedAt, DateTime.UtcNow.AddDays(-30))),
PipelineStageDefinitionBuilder.Group(
keySelector: "$_id",
accumulator: new BsonDocument("$sum", "$Value")),
});
var results = await collection.Aggregate(pipeline).ToListAsync();
4. Apply field-level selectors and avoid returning sensitive fields
Explicitly include or exclude fields to prevent over-fetching, especially when queries are influenced by user input.
var projection = Builders<MyEntity>.Projection
.Include(x => x.Id)
.Include(x => x.Name)
.Exclude(x => x.InternalMetadata);
var safeResults = await collection.Find(filter).Project(projection).ToListAsync();
5. Use role-based filters and avoid client-supplied selectors for authorization
Never allow clients to specify which fields to include or exclude if that impacts authorization. Instead, enforce server-side policies.
// Server-side enforced filter
var baseFilter = Builders<MyEntity>.Filter.Eq(x => x.IsPublic, true);
var combinedFilter = baseFilter & (userRole == "admin"
? Builders<MyEntity>.Filter.Empty
: Builders<MyEntity>.Filter.Ne(x => x.Sensitive, true));
var authorizedResults = await collection.Find(combinedFilter).ToListAsync();