Insecure deserialization: code execution through corrupted objects
Serialisation is the process that converts an object into a byte sequence or text representation (JSON, XML, binary) for storage or transmission. Deserialisation reconstructs the object from this representation. The vulnerability appears when the application deserialises data from an untrusted source (a cookie, HTTP parameter, queue message) without validating it.
Java deserialization and gadget chains
Java is particularly affected by this vulnerability class because its native deserialization invokes methods on objects during reconstruction. Methods readObject(), readResolve(), and finalisers are called automatically. If the classpath contains libraries with "gadgets" (classes whose chained methods produce dangerous effects), an attacker can craft a serialised payload that executes arbitrary code.
Commonly involved libraries: Apache Commons Collections, Spring Framework, Hibernate, Jackson (with certain modules). Ysoserial is the reference tool that generates payloads exploiting these known gadget chains.
PHP deserialization and object manipulation
PHP example: manipulation through deserialization
class User {
public $role = 'user';
public $redirectTo = '/dashboard';
}
// Données venant d'un cookie non signé :
$user = unserialize($_COOKIE['user']);
// Attaquant modifie le cookie avec :
// O:4:"User":2:{s:4:"role";s:5:"admin";s:10:"redirectTo";s:1:"/";}
// Résultat : $user->role === 'admin'
Python pickle
Python's pickle module is known to be dangerous with untrusted data. The official documentation states this explicitly: "Never unpickle data received from an untrusted source." A malicious pickle object can execute arbitrary code during deserialization via the __reduce__ method.
Prevention
The main rule: never deserialise data from an untrusted source using native serialization mechanisms. Alternatives: use simple data formats (JSON, protobuf) that cannot instantiate arbitrary code, cryptographically sign serialised data before storing it and verify the signature before deserialization, use class whitelists during deserialization.
Sign serialised data before storage
const crypto = require('crypto');
function sign(data) {
const payload = JSON.stringify(data);
const sig = crypto.createHmac('sha256', process.env.SECRET_KEY)
.update(payload).digest('hex');
return payload + '.' + sig;
}
function verify(signed) {
const [payload, sig] = signed.split('.');
const expected = crypto.createHmac('sha256', process.env.SECRET_KEY)
.update(payload).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
throw new Error('Signature invalide');
}
return JSON.parse(payload);
}
Further reading
A question after reading?
Does your application deserialise data received from clients? Send a message.
Or book a 30-minute scoping call directly
Book a call →