Don't use insecure deserializers
Matches methods using a deserializer that instantiates arbitrary types named in the payload: BinaryFormatter (obsolete SYSLIB0011, removed from .NET 9), SoapFormatter, NetDataContractSerializer, LosFormatter, ObjectStateFormatter, JavaScriptSerializer with a type resolver, or Newtonsoft.Json with TypeNameHandling set. Gadget chains available in the framework turn such deserialization of untrusted input into remote code execution: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide
This is CWE-502 Deserialization of Untrusted Data.
Flagged Code
This is CWE-502 Deserialization of Untrusted Data.
Flagged Code
static Order Load(byte[] payload) {
var formatter = new BinaryFormatter(); // flagged: BinaryFormatter
using var stream = new MemoryStream(payload);
return (Order)formatter.Deserialize(stream);
}
static JsonSerializerSettings Settings() =>
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; // flagged
Fixed Codestatic Order Load(byte[] payload) => JsonSerializer.Deserialize<Order>(payload); // System.Text.Json, fixed type static JsonSerializerSettings Settings() => new JsonSerializerSettings(); // TypeNameHandling stays None
How to fix
Use System.Text.Json, XmlSerializer or DataContractSerializer with a fixed, known set of types. With Newtonsoft.Json keep TypeNameHandling.None or provide a restrictive SerializationBinder. If a legacy format must be read, deserialize it only from trusted sources and suppress the issue with a justification.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Don't use insecure deserializers</Name>
// <Id>ND3110:DontUseInsecureDeserializers</Id>
warnif count > 0
// Third-party members are part of the code model only when the application uses them.
let insecureDeserializerTypes = ThirdParty.Types.WithFullNameIn(
"System.Runtime.Serialization.Formatters.Binary.BinaryFormatter",
"System.Runtime.Serialization.Formatters.Soap.SoapFormatter",
"System.Runtime.Serialization.NetDataContractSerializer",
"System.Web.UI.LosFormatter",
"System.Web.UI.ObjectStateFormatter",
"System.Messaging.BinaryMessageFormatter",
// JavaScriptSerializer becomes unsafe as soon as a type resolver is provided
"System.Web.Script.Serialization.SimpleTypeResolver",
"System.Web.Script.Serialization.JavaScriptTypeResolver").ToHashSetEx()
// Newtonsoft.Json: TypeNameHandling other than None lets the payload choose the types to instantiate.
// The enum value is not visible in IL, but explicitly setting the property is the smell to review.
let typeNameHandlingSetters = ThirdParty.Types.WithFullNameIn(
"Newtonsoft.Json.JsonSerializerSettings",
"Newtonsoft.Json.JsonSerializer")
.ChildMethods().Where(m => m.SimpleName == "set_TypeNameHandling").ToHashSetEx()
where insecureDeserializerTypes.Any() || typeNameHandlingSetters.Any()
from m in Application.Methods
let insecureTypesUsed = insecureDeserializerTypes.Where(t => m.IsUsing(t)).ToArray()
let typeNameHandlingSettersCalled = m.MethodsCalled.Intersect(typeNameHandlingSetters).ToArray()
where insecureTypesUsed.Length > 0 || typeNameHandlingSettersCalled.Length > 0
select new {
m,
insecureTypesUsed,
typeNameHandlingSettersCalled,
Debt = (insecureTypesUsed.Length > 0 ? 2.ToHours() : 30.ToMinutes()).ToDebt(),
Severity = insecureTypesUsed.Length > 0 ? Severity.Critical : Severity.High
}
//<Expl>
// The *{0}* uses {1}{2}: deserializing untrusted data with it can lead to
// *remote code execution*, since the payload decides which types get instantiated.
//</Expl>
//<Desc>
// Matches methods using a deserializer that instantiates arbitrary types
// named in the payload: *BinaryFormatter* (obsolete SYSLIB0011, removed
// from .NET 9), *SoapFormatter*, *NetDataContractSerializer*,
// *LosFormatter*, *ObjectStateFormatter*, *JavaScriptSerializer* with a
// type resolver, or Newtonsoft.Json with *TypeNameHandling* set.
// Gadget chains available in the framework turn such deserialization of
// untrusted input into remote code execution:
// https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide
//
// This is CWE-502 *Deserialization of Untrusted Data*.
//
// **Flagged Code**
// ```csharp
// static Order Load(byte[] payload) {
// var formatter = new BinaryFormatter(); // flagged: BinaryFormatter
// using var stream = new MemoryStream(payload);
// return (Order)formatter.Deserialize(stream);
// }
// static JsonSerializerSettings Settings() =>
// new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; // flagged
// ```
//
// **Fixed Code**
// ```csharp
// static Order Load(byte[] payload) =>
// JsonSerializer.Deserialize<Order>(payload); // System.Text.Json, fixed type
// static JsonSerializerSettings Settings() =>
// new JsonSerializerSettings(); // TypeNameHandling stays None
// ```
//</Desc>
//<HowToFix>
// Use *System.Text.Json*, *XmlSerializer* or *DataContractSerializer*
// with a fixed, known set of types. With Newtonsoft.Json keep
// *TypeNameHandling.None* or provide a restrictive *SerializationBinder*.
// If a legacy format must be read, deserialize it only from trusted
// sources and suppress the issue with a justification.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Security: all 39 items
- Software Composition Analysis (SCA) ND3120
- Transitive Software Composition Analysis (SCA) ND3121
- Don't hard-code secrets in constants ND3114
- Review credentials built from hard-coded values ND3115
- Don't use insecure deserializers ND3110
- Don't use weak hash algorithms (MD5, SHA1) ND3109
- Don't use DES/3DES/RC2 weak cipher algorithms ND3102
- Don't use weak password-based key derivation ND3123
- Don't use the ECB encryption mode ND3132
- Don't disable certificate validation ND3103
- Don't hard-code TLS/SSL protocol versions ND3122
- Review commands vulnerable to SQL injection ND3107
- Review data adapters vulnerable to SQL injection ND3108
- Review raw SQL built from composed strings ND3128
- Review LDAP filters composed from strings ND3137
- Don't enable external XML entity resolution (XXE) ND3111
- Review processes started with a composed arguments string ND3124
- Review web endpoints building file paths from their parameters ND3129
- Review custom archive extraction (Zip Slip) ND3135
- Review assemblies and types loaded from runtime-provided names ND3125
- Review web endpoints without [Authorize] nor [AllowAnonymous] ND3118
- Review state-changing endpoints opened to anonymous callers ND3130
- Review state-changing MVC actions without anti-forgery validation ND3119
- Review HTML-encoding bypasses ND3133
- Review explicitly disabled request validation ND3134
- Review redirects to a URL that is not validated as local ND3126
- Review request-influenced outbound HTTP calls (SSRF) ND3136
- Review insecure ASP.NET Core CORS policies and unguarded developer exception page ND3116
- Review cookies created without HttpOnly and Secure flags ND3117
- Review regular expressions without a match timeout (ReDoS) ND3112
- Review secrets compared with non-constant-time equality ND3113
- Review secrets passed to logging methods ND3127
- Review security operations that log nothing ND3131
- Don't use System.Random for security purposes ND3101
- Don't use CoSetProxyBlanket and CoInitializeSecurity ND3100
- Review publicly visible event handlers ND3104
- Pointers should not be publicly visible ND3105
- Seal methods that satisfy non-public interfaces ND3106
- Restrict sensitive APIs to reviewed components ND3138