CWE-502CriticalMITRE entry

Insecure Deserialization

Deserialization of Untrusted Data

What it is

CWE-502 exists when an application deserializes data from an untrusted source using a deserializer that can instantiate arbitrary objects or trigger code paths during reconstruction. Many serialization formats (Python pickle, Java Serializable, PHP unserialize, .NET BinaryFormatter, Ruby Marshal) allow gadget chains that execute attacker-controlled code during deserialization.

Why it matters

Insecure deserialization typically grants remote code execution with the privileges of the deserializing service. Gadget-chain research has produced reliable exploits for most major serialization libraries. The Apache Commons Collections gadget chain alone has been used in dozens of major breaches over the past decade.

Common patterns

  • Python pickle.load or pickle.loads on data from HTTP requests, message queues, or cache backends.
  • Java ObjectInputStream.readObject on data from network sources.
  • PHP unserialize on cookie or query-string values.
  • .NET BinaryFormatter (deprecated in .NET 5, removed by default in .NET 9).
  • Ruby Marshal.load on session data or cache entries.
  • YAML.load (Python) or YAML.load_file without safe_load on user-supplied YAML.

Languages affected

PythonJavaRubyPHPC#

What Deva detects

Deva flags every call to pickle.load, pickle.loads, yaml.load (without Loader=yaml.SafeLoader), Marshal.load, ObjectInputStream.readObject, BinaryFormatter.Deserialize, NetDataContractSerializer, and PHP unserialize where the data parameter traces back to untrusted input. The scanner also flags trusted-source deserialization at high severity when the trust boundary is weak (signed-but-not-verified cookies, encrypted-but-not-authenticated caches).

Example

Vulnerable

import pickle
import base64
from flask import request

@app.route('/restore', methods=['POST'])
def restore():
    data = base64.b64decode(request.form['state'])
    state = pickle.loads(data)
    return restore_session(state)

Fixed

import json
import hmac, hashlib
from flask import request

SECRET = os.environ['SESSION_SIGNING_KEY'].encode()

@app.route('/restore', methods=['POST'])
def restore():
    body = request.form['state']
    payload, sig = body.rsplit('.', 1)
    expected = hmac.new(SECRET, payload.encode(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        abort(403)
    state = json.loads(payload)  # JSON cannot instantiate arbitrary classes
    return restore_session(state)

Explanation

The vulnerable version pickle.loads data straight from a form parameter. Any attacker producing a pickle bytestream achieves remote code execution. The fix uses JSON (which deserializes only built-in types) and an HMAC signature to enforce integrity. The two changes together are the standard defense pattern.

Where this fits in OWASP Top 10

Compliance framework mapping

FrameworkControls
OWASP Top 10 (2021)
A08:2021 Software and Data Integrity Failures
NIST 800-53 Rev 5
SI-10 Information Input ValidationSC-8 Transmission Confidentiality and Integrity
PCI-DSS v4.0
6.2.4 Software engineering techniques

Related CWEs

Deva detects CWE-502 alongside 970+ other CWE patterns at write time, with AI-assisted fix generation that maintains compliance.