Description
System.Linq.Dynamic.Core parses strings into LINQ expression trees. Passing a complete request string as the expression argument to Where, OrderBy, Select or DynamicExpressionParser.ParseLambda lets the caller control query structure, including conditions, ordering and projection.
Values supplied through @0 and @1 in a fixed expression, or through the library's WhereInterpolated, remain separate from expression structure. Concatenating input, using ordinary string interpolation to construct the expression, or accepting the complete expression is not parameterization.
The version-specific references here use System.Linq.Dynamic.Core 1.7.3. Versions 1.3.0 and 1.6.0 introduced security restrictions on callable methods and types, object methods and OrderBy expressions. These reduce earlier code-execution and reflection risks; they do not make it safe to let callers choose the application's filtering or projection policy.
Potential impact
- Callers may bypass intended filters or tenant boundaries and read unauthorized records.
- Unapproved projections or ordering may expose sensitive data.
- Complex or expensive expressions can consume database or application resources.
- Vulnerable versions before 1.3.0 can permit arbitrary code and command execution through CVE-2023-32571. Versions before 1.6.0 have reflection-type and static-member access risks associated with CVE-2024-51417.
Remediation
- Prefer strongly typed LINQ over string-based Dynamic LINQ.
- Map short client identifiers to server-owned
Expression<Func<T, bool>>values or fixed expression strings. Do not treat the entire input as an expression. - If only values must vary, keep the expression fixed and use
@0,@1orWhereInterpolated. Placeholders do not parameterize property names, operators or sort directions; select these through a separate fixed map. - Update
System.Linq.Dynamic.Coreto a maintained release. Keep restrictiveParsingConfigdefaults such asAllowNewToEvaluateAnyType = false,AllowEqualsAndToStringMethodsOnObject = falseandRestrictOrderByToPropertyOrField = true. Expose only necessary types through custom type providers. - Enforce data-access permissions separately and limit result counts, query time and complexity.
Examples
Before
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using System.Linq.Dynamic.Core;
public sealed class User
{
public bool IsActive { get; init; }
public int Age { get; init; }
}
public sealed class SearchController
{
public IQueryable<User> Search(
[FromQuery] string predicate,
IQueryable<User> users)
{
return users.Where(predicate);
}
}
After
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public sealed class User
{
public bool IsActive { get; init; }
public int Age { get; init; }
}
public sealed class SearchService
{
private static readonly IReadOnlyDictionary<string, Expression<Func<User, bool>>> Filters =
new Dictionary<string, Expression<Func<User, bool>>>(StringComparer.Ordinal)
{
["active"] = user => user.IsActive,
["adult"] = user => user.Age >= 18
};
public IQueryable<User> Search(string filter, IQueryable<User> users)
{
if (!Filters.TryGetValue(filter, out var predicate))
{
throw new ArgumentException("Unsupported filter.", nameof(filter));
}
return users.Where(predicate);
}
}
The first example parses predicate directly as Dynamic LINQ syntax. The second uses external input only as a fixed key; the server supplies the strongly typed condition.
If Dynamic LINQ is required and only a value comes from outside, use a fixed structure such as users.Where("Age >= @0", minimumAge). Even when minimumAge is a string, it is bound as the @0 value rather than parsed again as expression syntax.
References
- CWE-917: Expression Language Injection
- OWASP Top 10:2025 A05 Injection
- OWASP ASVS 5.0
- System.Linq.Dynamic.Core 1.7.3
- System.Linq.Dynamic.Core README and security changes
- System.Linq.Dynamic.Core changelog
- Dynamic LINQ configuration options
- Dynamic LINQ query operators
- GHSA-w65q-jcmv-28gj / CVE-2023-32571
- CVE-2024-51417
- KISA Software Security Weakness Assessment Guide 2021