Adversarial Input in Aspnet
How Adversarial Input Manifests in ASP.NET
Adversarial input in ASP.NET applications exploits the framework's powerful data handling features when they are improperly secured. ASP.NET's model binding, Entity Framework, and JSON/XML parsers provide convenience but can become attack vectors if validation and sanitization are overlooked. These attacks typically fall under OWASP API Top 10 A03:2021 – Injection and A04:2021 – Insecure Design.
SQL Injection via Entity Framework
While Entity Framework (EF) Core uses parameterized queries by default, developers sometimes introduce vulnerabilities by using raw SQL queries (FromSqlRaw) or concatenating user input into LINQ queries that EF cannot parameterize. For example, dynamic OrderBy clauses based on user input can lead to SQL injection if not strictly validated against a whitelist.
// VULNERABLE: Dynamic OrderBy with user input
public IActionResult GetProducts(string sortColumn)
{
// sortColumn comes from query string, e.g., ?sortColumn=Price DESC; DROP TABLE Users;
var query = _context.Products.AsQueryable();
query = query.OrderBy(sortColumn); // System.Linq.Dynamic.Core parses this string
return Ok(query.ToList());
}An attacker could supply ?sortColumn=Price;DROP%20TABLE%20Users-- to execute arbitrary SQL if the Dynamic LINQ library is used without restriction.
XML External Entity (XXE) in .NET XML Parsers
ASP.NET applications that accept XML payloads (e.g., SOAP services, file uploads) may use XmlDocument, XmlReader, or XDocument without disabling DTD processing. .NET's default settings for some parsers allow external entity resolution, leading to data exfiltration or SSRF. This is particularly relevant in older .NET Framework applications or when third-party libraries use unsafe defaults.
// VULNERABLE: XmlDocument with default settings
[HttpPost]
public IActionResult ProcessXml(IFormFile file)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load(file.OpenReadStream()); // DTD processing enabled by default in .NET Framework
// ... process xmlDoc
}An attacker could upload an XML file containing <!ENTITY xxe SYSTEM "file:///etc/passwd"> to read server files.
Insecure Deserialization in JSON APIs
ASP.NET Core uses System.Text.Json by default, which is generally safe. However, if an application uses Newtonsoft.Json (Json.NET) with TypeNameHandling.All or similar settings, it becomes vulnerable to remote code execution via gadget chains. This is common in legacy ASP.NET Web API projects or when libraries require polymorphic deserialization.
// VULNERABLE: Newtonsoft.Json with TypeNameHandling
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.TypeNameHandling = TypeNameHandling.All);
// Attacker sends: {"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework", ...}
// This can trigger a gadget chain leading to RCE on the server.Prototype Pollution in Model Binding
ASP.NET Core's model binder binds JSON properties to .NET object properties. If the application uses dictionaries or dynamic objects without protection, an attacker might inject properties like __proto__ or prototype chain modifiers that alter application behavior, especially in JavaScript-heavy apps that share model definitions with client-side code.
ASP.NET-Specific Detection
Detecting adversarial input vulnerabilities in ASP.NET requires testing the API's unauthenticated attack surface, as these flaws often exist in publicly accessible endpoints. middleBrick's Input Validation check (one of its 12 parallel security checks) actively probes for these patterns by sending crafted payloads and analyzing responses.
The scanner tests for:
- SQL Injection patterns in query parameters, headers, and JSON bodies, including time-based and error-based probes tailored to SQL Server (common in ASP.NET environments). It also checks for dynamic LINQ injection by submitting suspicious
OrderByexpressions. - XXE payloads in XML endpoints, attempting to resolve external entities and detect file disclosure or SSRF responses.
- Deserialization gadgets by sending known
Newtonsoft.Jsonpayloads (e.g.,TypeNameHandlingexploits) and monitoring for unusual response times or error messages that indicate gadget execution. - Prototype pollution by injecting
__proto__and other prototype-modifying properties in JSON requests, then checking if subsequent requests are affected by altered server-side objects.
Because middleBrick performs black-box scanning without credentials, it simulates an external attacker's perspective, testing exactly what an unauthenticated user can submit to your API. This is critical because many adversarial input flaws are exposed in public login, search, or data submission endpoints.
You can run this detection in several ways:
- Web Dashboard: Paste your ASP.NET API URL to get a full report with per-category scores (0–100) and prioritized findings.
- CLI Tool: Use
middlebrick scan https://your-api.comfrom your terminal to get JSON output, which can be integrated into scripts. - GitHub Action: Add
middlebrick/scanto your workflow to scan staging APIs before deployment and fail the build if the Input Validation score drops below a threshold.
For example, a typical CLI scan of an ASP.NET Core API might reveal:
$ middlebrick scan https://api.example.com
{
"score": 65,
"categories": {
"input_validation": {
"score": 40,
"findings": [
{
"severity": "high",
"title": "Potential SQL Injection in OrderBy parameter",
"endpoint": "GET /api/products?sortColumn={payload}",
"evidence": "Time delay observed with payload 'Price;WAITFOR DELAY '0:0:5'--'"
}
]
}
}
}This output directly points to the vulnerable code pattern in your ASP.NET controller, enabling precise remediation.
ASP.NET-Specific Remediation
Fixing adversarial input vulnerabilities in ASP.NET involves leveraging the framework's built-in security features and following secure coding practices. The goal is to validate, sanitize, and constrain all user-supplied data before it reaches sensitive operations like database queries, XML parsing, or deserialization.
1. Secure Dynamic Queries and LINQ
Never pass raw user input to OrderBy, Where, or FromSqlRaw. Use a whitelist of allowed properties and directions.
// SECURE: Whitelist validation for dynamic sorting
private static readonly Dictionary<string, Expression<Func<Product, object>>> _sortMap = new()
{
{ "price", p => p.Price },
{ "name", p => p.Name }
};
public IActionResult GetProducts(string sortColumn, bool ascending)
{
if (!_sortMap.TryGetValue(sortColumn.ToLower(), out var sortExpr))
sortColumn = "name"; // default
var query = _context.Products.AsQueryable();
query = ascending ? query.OrderBy(sortExpr) : query.OrderByDescending(sortExpr);
return Ok(query.ToList());
}For raw SQL, always use parameterized queries with FromSqlInterpolated or explicit SqlParameter objects.
2. Prevent XXE in XML Parsers
Configure XmlReaderSettings to disable DTD processing and resolve external entities. Apply this globally if your application processes XML.
// SECURE: Safe XmlReader configuration
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit, // .NET Core / .NET 5+
XmlResolver = null // prevents any external resolution
};
using var reader = XmlReader.Create(file.OpenReadStream(), settings);
var xmlDoc = new XmlDocument();
xmlDoc.Load(reader);For XDocument, use LoadOptions that omit DTD processing, or better yet, avoid XML entirely if possible in favor of JSON.
3. Secure JSON Deserialization
Stick with System.Text.Json (default in ASP.NET Core 3.0+) and avoid Newtonsoft.Json unless absolutely necessary. If you must use Json.NET, never enable TypeNameHandling for untrusted data. Instead, use a custom SerializationBinder to restrict types.
// SECURE: Restricted type binder for Newtonsoft.Json
public class SafeSerializationBinder : ISerializationBinder
{
private readonly HashSet<Type> _allowedTypes = new()
{
typeof(Product),
typeof(Order)
// only permit known safe types
};
public Type BindToType(string assemblyName, string typeName)
{
var type = Type.GetType($"{typeName}, {assemblyName}");
if (type != null && _allowedTypes.Contains(type))
return type;
throw new JsonSerializationException("Type not allowed for deserialization");
}
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null; typeName = serializedType.FullName;
}
}
// In Startup.cs:
services.AddControllers()
.AddNewtonsoftJson(opts =>
opts.SerializerSettings.SerializationBinder = new SafeSerializationBinder());4. Validate and Sanitize All Inputs
Use ASP.NET's data annotations and IValidatableObject for model-level validation. For complex scenarios, implement custom validation attributes.
// SECURE: Data annotations and custom validation
public class CreateProductRequest : IValidatableObject
{
[Required]
[StringLength(100, MinimumLength = 3)]
public string Name { get; set; }
[Range(0.01, 1000000.00)]
public decimal Price { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Name.Contains("