FlawOpen

flawopen.com/Insecure Deserialization/.NET BinaryFormatter Security

Is .NET BinaryFormatter safe?

CWE-502: Deserialization of Untrusted DataReference page
Short answer — no safe configuration exists

Microsoft says BinaryFormatter is insecure and cannot be made secure. It recommends stopping its use even when an application believes the input is trusted. In .NET 9, the API types remain, but the in-box implementation always throws PlatformNotSupportedException; older runtimes and an unsupported compatibility package still carry the original risk.

UNSAFE — attacker-influenced input
// Legacy API: never use for attacker-influenced streams.
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class LegacyReader
{
    public static object Deserialize(Stream input) =>
        new BinaryFormatter().Deserialize(input);
}

// Also remove unrestricted polymorphic serializers:
SoapFormatter
NetDataContractSerializer
LosFormatter
ObjectStateFormatter  // ASP.NET ViewState internals

// A SerializationBinder does not make these safe.
MIGRATE — explicit data contract
// Application code declares the data shape.
// Nullable reference types make the DTO contract explicit.
#nullable enable
using System;
using System.IO;
using System.Text.Json;

public sealed record MyDto(int Id, string Name);

public static class DtoReader
{
    public static MyDto Parse(ReadOnlySpan<byte> json)
    {
        // Bound input size and validate application rules.
        if (json.Length > 65_536)
            throw new InvalidDataException();

        MyDto? value = JsonSerializer.Deserialize<MyDto>(json);
        if (value is null || value.Id <= 0 ||
            string.IsNullOrWhiteSpace(value.Name) ||
            value.Name.Length > 100)
            throw new InvalidDataException();

        return value;
    }
}

// For old NRBF data, inspect records with NrbfDecoder.
// Map only allowed values into a DTO; never instantiate
// arbitrary application types from serialized metadata.

Why BinaryFormatter is dangerous

BinaryFormatter.Deserialize reconstructs object graphs from an input stream and can let attacker-controlled data influence control flow. Microsoft warns of denial-of-service, information disclosure, and remote code execution risks. The central design problem is unrestricted polymorphic deserialization: serialized data can influence which types and object state are processed. No formatter switch converts this API into a safe parser for untrusted bytes.

The risk is not limited to public HTTP endpoints. Files, cache entries, queues, database records, desktop-client messages, and cloud-synced state can become attacker-influenced later. Trace how bytes enter and move through the system instead of treating “we wrote it” or “it is internal” as a permanent trust label.

Why SerializationBinder is not a fix

A custom SerializationBinder can restrict the types a formatter attempts to resolve, but Microsoft explicitly says a binder or another configuration switch cannot mitigate denial-of-service attacks and may be insufficient for other attack classes. Treat a binder as no substitute for migration; do not accept untrusted input with BinaryFormatter while waiting to remove it.

Find legacy use and related paths

Search source, project references, and runtime configuration for BinaryFormatter, IFormatter, SoapFormatter, NetDataContractSerializer, LosFormatter, and ObjectStateFormatter. Inspect framework session providers, cache adapters, queue consumers, file import/export code, and old ASP.NET Web Forms paths. ViewState is normally protected by a message authentication code; keep that protection enabled and protect the machine key. That MAC does not make general-purpose BinaryFormatter deserialization safe.

Plan migration by data format and framework version

For new data, choose an explicit contract such as System.Text.Json, DataContractSerializer, MessagePack, or protobuf-net according to compatibility and format needs; there is no drop-in replacement. If old NRBF data must be retained, .NET 9’s NrbfDecoder can decode records without instantiating encoded application types. Validate the decoded structure and map only expected values into application DTOs. Separately review WinForms/WPF resource, clipboard, and drag-and-drop migration guidance because these framework scenarios have their own migration behavior.

FAQ

We only deserialize data we wrote ourselves. Is that fine?

Microsoft recommends migrating even when data is believed to be trusted, because storage, caches, files, sync, and downstream systems can cross trust boundaries. Inventory who can write each source and stop using BinaryFormatter rather than relying on a trust assumption.

What happens when we move to .NET 9?

In .NET 9, the API types still exist, but the in-box implementation always throws PlatformNotSupportedException, regardless of the old compatibility switch. Audit usages and migrate before upgrading. An unsupported compatibility package restores the vulnerable implementation and is not a security fix.

Is Json.NET a safe replacement?

Json.NET defaults TypeNameHandling to None, which avoids using payload type metadata to select arbitrary CLR types. Do not enable non-None settings for untrusted input; if polymorphism is required, bind it to a strict application-controlled allowlist and follow the library guidance. See Is TypeNameHandling safe?

References

See also Insecure Deserialization: Risks and Remediation Java ObjectInputStream Security: Safer Deserialization Newtonsoft.Json TypeNameHandling: Safe Configuration? PHP unserialize() and Untrusted Input Python pickle.load() Security: Untrusted Data Risks Is Ruby YAML.load Safe? Psych Versions & Safe Loading