Deserialization Attack in Aspnet (Csharp)
Deserialization Attack in Aspnet with Csharp — how this specific combination creates or exposes the vulnerability
Deserialization attacks in ASP.NET with C# occur when an application reconstructs objects from untrusted data, such as HTTP request payloads, cookies, or query strings. If the deserialization logic does not strictly validate input, an attacker can craft payloads that instantiate malicious objects, execute code, or bypass authorization checks. In ASP.NET, common vectors include view state, form data bound to complex models, and JSON or XML payloads processed by built-in formatters.
Because C# is statically typed and tightly integrated with the .NET runtime, deserialization often relies on concrete types and public constructors. When an attacker can influence which type is deserialized—by manipulating type hints in JSON, XML external entity (XXE) inputs, or serialized object streams—they can force the runtime to instantiate dangerous classes such as System.Runtime.Serialization.ObjectManager, System.Web.UI.ObjectStateFormatter, or types from popular libraries like Newtonsoft.Json. These can lead to remote code execution (RCE), privilege escalation, or sensitive data disclosure, some of which are reflected in findings such as BFLA/Privilege Escalation and Unsafe Consumption within middleBrick scans.
ASP.NET applications that accept unauthenticated requests and deserialize data without strict type whitelisting or schema validation expand the unauthenticated attack surface. middleBrick tests this surface by submitting payloads that attempt to trigger gadget chains via common .NET serialization formats. For example, an endpoint that accepts a JSON body like { "__type": "System.Web.Script.Serialization.TestType, System.Web.Extensions", "value": "..." } may be coerced into invoking methods that load assemblies or execute commands. The framework-agnostic checks in middleBrick’s LLM/AI Security and Input Validation categories help surface these risks even when the API does not explicitly advertise its types.
Real-world exploit patterns align with known CVEs affecting .NET components, such as insecure deserialization in libraries that handle object streams. The presence of Gadget Chains using types like System.Drawing.Image or System.Data.DataSet can indicate potential RCE paths. Because deserialization issues frequently intersect with BOLA/IDOR when object identifiers are user-supplied, middleBrick correlates findings across checks to highlight how an insecure deserialization flaw can amplify other vulnerabilities.
middleBrick’s OpenAPI/Swagger analysis (2.0, 3.0, 3.1) with full $ref resolution cross-references spec definitions with runtime behavior. If your spec describes a parameter as type object without constraining possible concrete types, middleBrick flags this as a potential input validation weakness. This approach helps teams understand how an attacker might leverage type confusion or gadget chains to reach unsafe states, even before running active probes.
In summary, the combination of ASP.NET’s model binding and C#’s type-driven deserialization mechanics can expose endpoints that reconstruct objects from attacker-controlled data. By running unauthenticated scans that include active LLM security probes and input validation checks, middleBrick surfaces these risks alongside remediation guidance mapped to OWASP API Top 10 and related compliance frameworks.
Csharp-Specific Remediation in Aspnet — concrete code fixes
To mitigate deserialization risks in ASP.NET with C#, prefer strongly typed models, avoid accepting raw object or System.Type parameters, and enforce strict schema validation. Where deserialization is necessary, use whitelists of allowed types and disable dangerous formatters.
For JSON payloads, configure System.Text.Json or Newtonsoft.Json to reject unknown types and to avoid resolving types from input. Example using System.Text.Json:
using System.Text.Json;
using System.Text.Json.Serialization;
var options = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { context =>
{
if (context.Type == typeof(object))
{
context.PossibleTypes = null; // Reject open type resolution
}
// Explicitly allow only safe, known types
if (context.Type == typeof(MySafeDto))
{
context.ShouldDeserialize = true;
}
}}
},
PropertyNameCaseInsensitive = true
};
var payload = "{\"name\":\"test\"}";
var dto = JsonSerializer.Deserialize<MySafeDto>(payload, options);
With Newtonsoft.Json, disable TypeNameHandling and use JsonObjectContract restrictions:
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
MetadataPropertyHandling = MetadataPropertyHandling.Ignore
};
var payload = "{\"name\":\"test\"}";
var dto = JsonConvert.DeserializeObject<MySafeDto>(payload, settings);
For XML deserialization, use XmlReader with XmlDictionaryReader and disable DTD processing to prevent XXE:
using System.Xml;
var readerSettings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using var reader = XmlReader.Create(new StringReader("<data>test</data>"), readerSettings);
// Safe deserialization logic here
In ASP.NET Core, avoid using [FromForm] or [FromBody] bound to object or dynamic models. Instead, bind to concrete, validated DTOs and apply explicit validation attributes:
[ApiController]
[Route("api/[controller]")]
public class ExampleController : ControllerBase
{
[HttpPost]
public IActionResult Update([FromBody] UpdateRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Safe processing
return Ok();
}
}
public class UpdateRequest
{
[Required]
[StringLength(100, MinimumLength = 1)]
public string Name { get; set; }
[Range(1, 100)]
public int Version { get; set; }
}
Apply runtime type checks when polymorphic deserialization is unavoidable. Use a custom JsonConverter or a factory that strictly validates the incoming type name against an allowlist:
public class SafeTypeConverter : JsonConverter<BaseType>
{
private static readonly HashSet<string> AllowedTypes = new() { "MyApp.DerivedA", "MyApp.DerivedB" };
public override BaseType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var doc = JsonDocument.ParseValue(ref reader);
if (doc.RootElement.TryGetProperty("type", out var typeProp) && AllowedTypes.Contains(typeProp.GetString()))
{
return typeProp.GetString() switch
{
"MyApp.DerivedA" => JsonSerializer.Deserialize<DerivedA>(doc.RootElement.GetRawText(), options),
"MyApp.DerivedB" => JsonSerializer.Deserialize<DerivedB>(doc.RootElement.GetRawText(), options),
_ => throw new JsonException("Type not allowed")
};
}
throw new JsonException("Type not specified or not allowed");
}
public override void Write(Utf8JsonWriter writer, BaseType value, JsonSerializerOptions options) =>
throw new NotImplementedException();
}
These C#-specific practices reduce the risk of deserialization-based RCE and BOLA/IDOR. middleBrick’s scans validate that endpoints reject unexpected types and that no unauthenticated payloads trigger unsafe object construction. By combining code-level controls with continuous monitoring—such as the Pro plan’s GitHub Action integration—you can fail builds automatically if risk scores drop below your defined threshold.