ViewState deserialization and forged __VIEWSTATE

ViewState deserialization and forged __VIEWSTATE

Written by

in

ViewState deserialization is how classic ASP.NET Web Forms rebuilds page state on the server. The browser sends back a hidden field called __VIEWSTATE, and the server turns that string back into .NET objects. When the protection around that field is off or its key has leaked, an attacker can forge a __VIEWSTATE value that deserializes into a gadget, and the page that was meant to remember a text box ends up running attacker code.

What ViewState is and how it travels

ASP.NET Web Forms keeps the state of a page, the values of its controls, between requests. It serializes that state, base64 encodes it, and puts it in a hidden form field:

<input type="hidden" name="__VIEWSTATE"
       value="/wEPDwUKLTEyMzQ1Njc4OQ9kFgICAw9kFgI..." />

On the next postback the browser sends that field straight back. The server base64 decodes it and deserializes it into the object graph that describes the page. That deserialization step is the whole story. If an attacker can make the server deserialize bytes they chose, they are back to the object building problem at the heart of the insecure deserialization primer.

What normally keeps ViewState deserialization safe

ViewState is not meant to be attacker controllable, and ASP.NET ships two protections:

  • A message authentication code, the ViewState MAC. The server signs the ViewState with a secret key and checks that signature on the way back in. Edit one byte without the key and the check fails, so the server refuses to deserialize it. This is controlled by the EnableViewStateMac setting.
  • The machine key. The signing, and optional encryption, use keys configured as machineKey. Those keys are the secret that makes forgery hard.

When both are in place and the key is secret, a forged ViewState is rejected before any object is built. The danger appears when that is not true.

ViewState is only safe while its key is secret. The signature is the one thing standing between a hidden form field and your deserializer.

How forged ViewState deserialization turns into code execution

Two broken conditions open the door.

  • MAC disabled. If EnableViewStateMac is off, the server deserializes whatever arrives with no signature check. An attacker crafts a serialized object graph, base64 encodes it, and sends it as __VIEWSTATE. The server builds it with no questions asked.
  • Leaked or weak machine key. If the key is committed to source control, copied from a sample config, or reused across many servers, an attacker who learns it can sign their own forged ViewState so the MAC check passes.

Either way the attacker controls the bytes going into the deserializer. From there they point it at a class already present in the .NET runtime whose construction does something dangerous, the same class of gadget used in dotnet BinaryFormatter RCE and selected by TypeNameHandling. Chained, those classes form a deserialization gadget chain that ends in remote code execution. No forged value is shown here, on purpose.

How to spot the risk

  • Check EnableViewStateMac. Search config and page directives for EnableViewStateMac="false". Turning the MAC off was never safe, and modern frameworks do not let you, but legacy apps still carry it.
  • Audit the machine key. Look for a machineKey with hardcoded validationKey and decryptionKey values in web.config, especially the same values across environments or copied from a tutorial.
  • Look for leaked configs. A web.config in source control, in a backup, or reachable through a file read bug hands over the key.
  • Note the framework. Classic Web Forms is where this lives. Newer ASP.NET Core does not use ViewState at all.

How to fix ViewState deserialization

  • Keep the MAC and validation on. Never set EnableViewStateMac to false. Let the server sign and verify every ViewState.
  • Protect and rotate the machine key. Generate unique keys per application, keep them out of source control, store them as secrets, and rotate them if you suspect exposure.
  • Encrypt as well as sign. Set ViewState to be encrypted so its contents are not even readable, which removes another source of leaked information.
  • Minimize what ViewState holds. The less page state you round trip through the client, the smaller the target.
  • Move to a framework without ViewState. Modern .NET web apps use anti forgery tokens and server held state instead of serializing object graphs into a hidden field. If you are building new, you avoid the whole category.

Why ViewState deserialization rewards understanding the app

A scanner throwing generic payloads will miss this, because success depends on whether the MAC is on and whether the specific key is known. You find it by reasoning about the protection around the field, not by guessing. That is assumption testing. For the wider family of input that crosses a trust boundary, see the injection and input category.

This is the kind of flaw an autonomous researcher that reasons about whether untrusted input can reach a type resolving deserializer is built to find. You can read how we think about it on our about page.

Frequently asked questions

What is ViewState deserialization?

ASP.NET Web Forms saves page state by serializing it, base64 encoding it, and putting it in the hidden __VIEWSTATE field. On the next postback the server decodes and deserializes that field back into .NET objects. That deserialization step is where forged input becomes dangerous.

How can an attacker abuse __VIEWSTATE?

If the ViewState MAC is disabled or the machine key has leaked, an attacker can craft or sign a __VIEWSTATE value that the server deserializes. By pointing it at a class already loaded in the runtime, they can start a gadget chain that can end in remote code execution.

What protects ViewState normally?

Two things. The ViewState MAC signs the field with a secret key and verifies it on each postback, so edits without the key are rejected. The machine key is that secret, and optional encryption hides the contents. With both in place and the key kept secret, forged ViewState is refused before any object is built.

How do I fix ViewState deserialization risk?

Keep EnableViewStateMac on, never disable it, and protect the machine key by generating unique keys, keeping them out of source control, and rotating them if exposed. Encrypt ViewState, keep it small, and prefer a modern framework that does not serialize page state into a hidden field.


Put an autonomous researcher on your own systems

UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, and a say in what it looks for. If your team ships software worth pressure testing, apply to the design partner program.