Spring4shell in Aspnet with Hmac Signatures
Spring4shell in Aspnet with Hmac Signatures — how this specific combination creates or exposes the vulnerability
The Spring4shell (CVE-2022-22965) vector in an ASP.NET context becomes notable when HMAC-based signatures are used to bind request data to a server-side model without strict validation of the target type. In such setups, an attacker can supply crafted form data or JSON that leverages model binding to invoke arbitrary method execution, for example via a POST to an endpoint that expects a simple DTO but receives nested properties like __type or polymorphic deserialization hints. When HMAC signatures are applied to protect integrity, the signature may cover only selected headers or a subset of the payload, leaving the bound model open to manipulation if the server deserializes unexpected types.
ASP.NET’s default model binders can be coerced into mapping attacker-supplied values to constructors or methods if the application uses permissive binding sources (e.g., BindingSource.Any) and does not explicitly whitelist expected types. Even when an HMAC signature confirms the request came from a trusted client, the server may still process maliciously modified parameters because the signature does not guarantee semantic correctness of the bound object graph. This mismatch between integrity protection (HMAC) and type safety (model binding) can lead to unauthorized operations, reflected in middleBrick’s findings for BOLA/IDOR and Property Authorization when the scan detects over-permissive binding or missing type constraints.
Consider an endpoint that validates an HMAC header but does not restrict the deserialized type:
// Risk: model binding may instantiate unexpected types despite HMAC validation
[HttpPost("update")]
public IActionResult Update([FromBody] UpdateModel model)
{
if (!VerifyHmac(model)) return Forbid();
// Proceed with update using model properties
return Ok();
}
private bool VerifyHmac(UpdateModel model)
{
var computed = ComputeHmac(model.SensitiveData, _secretKey);
return TimingSafeEquals(computed, model.ClientHmac);
}
If UpdateModel is replaced during binding with a malicious subtype that overrides behavior, the HMAC may still pass (because the attacker can echo back the signature over the modified payload if the key is exposed or the scope is too broad), while the server performs unintended actions. MiddleBrick’s LLM/AI Security checks can surface prompt injection or data exfiltration patterns that parallel this risk when endpoints expose functionality that can be tricked via crafted inputs.
Moreover, if the HMAC is computed over only selected fields (e.g., headers or a subset of the JSON), an attacker can modify unchecked properties to trigger path traversal, SSRF, or insecure deserialization patterns that the scanner flags under Data Exposure and Input Validation. The combination of weak binding rules and partial integrity checks creates a scenario where the application believes the request is authentic but processes it unsafely.
Hmac Signatures-Specific Remediation in Aspnet — concrete code fixes
To reduce risk, ensure that HMAC validation covers all inputs that affect behavior and that model binding is constrained to known types. Prefer explicit DTOs with strict binding rules and validate the entire payload before acting.
1) Validate the full payload and use strict binding
Avoid [FromBody] with permissive sources. Use a concrete type and disable inference of complex types from query strings or form data.
[HttpPost("update")]
public IActionResult Update([Bind(Prefix = "payload")] UpdateRequest request)
{
if (request == null || !VerifyHmacFullPayload(request)) return Forbid();
// Safe processing
return Ok();
}
private bool VerifyHmacFullPayload(UpdateRequest request)
{
var json = JsonSerializer.Serialize(request, _jsonOptions);
var computed = HmacSha256(json, _secretKey);
return TimingSafeEquals(computed, request.ClientHmac);
}
public class UpdateRequest
{
public required string Action { get; set; }
public required int ItemId { get; set; }
public string? Metadata { get; set; }
public required string ClientHmac { get; set; }
}
2) Use a fixed binding source and disable formatters you don’t need
In Program.cs, restrict input formatters to JSON only and avoid allowing form-data to bind to sensitive commands.
builder.Services.Configure<MvcOptions>(options =>
{
options.InputFormatters.RemoveType<SystemTextJsonInputFormatter>();
options.InputFormatters.Add(new SystemTextJsonInputFormatter(
new JsonSerializerOptions(JsonSerializerDefaults.Web)));
});
3) Include all relevant data in the HMAC and enforce type constraints
Compute HMAC over the canonical JSON representation of the full DTO, and enforce a closed type model to prevent polymorphic deserialization.
private string ComputeHmacForDto(object dto, byte[] key)
{
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
var utf8 = JsonSerializer.SerializeToUtf8Bytes(dto, dto.GetType(), options);
using var hmac = new HMACSHA256(key);
return Convert.ToBase64String(hmac.ComputeHash(utf8));
}
On receipt, recompute over the raw JSON body (preserving order and casing) and compare before model binding proceeds to a specific known type. This approach aligns with the scanner’s checks for Encryption and Data Exposure by ensuring integrity covers the entire message.
4) Add anti-tampering checks for model metadata
Validate that no unexpected type hints (e.g., __type, $type) are present and reject requests that attempt to bind to base types or interfaces unless explicitly supported.
if (request.Metadata != null && request.Metadata.Contains("__type", StringComparison.OrdinalIgnoreCase))
{
ModelState.AddModelError("Metadata", "Type hints are not allowed");
}