From grimoire
Prevents insecure deserialization vulnerabilities when processing data from untrusted sources (pickle, Java serialization, YAML, PHP unserialize). Recommends data-only formats and signed serialization.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:prevent-insecure-deserializationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Never deserialize untrusted data using native serialization formats — use data-only formats (JSON, Protobuf) with schema validation, or enforce strict type allowlists when native serialization is unavoidable.
Never deserialize untrusted data using native serialization formats — use data-only formats (JSON, Protobuf) with schema validation, or enforce strict type allowlists when native serialization is unavoidable.
Adopted by: OWASP Top 10 2021 A08 (Software and Data Integrity Failures) covers insecure deserialization. Oracle, Apache, Red Hat, and Cisco have all patched critical RCE vulnerabilities caused by Java deserialization (CVE-2015-4852, CVE-2016-0792, etc). Node.js node-serialize, Python pickle, PHP unserialize, and Ruby Marshal.load are all documented RCE vectors when given untrusted input.
Impact: Apache Commons Collections deserialization RCE (2015) affected WebLogic, JBoss, Jenkins, and dozens of Java application servers — enabling remote code execution with zero authentication. Python pickle.loads(user_input) is equivalent to eval(user_input) — it executes arbitrary code. GitHub's 2017 Enterprise Server RCE was caused by Ruby Marshal deserialization. Insecure deserialization is rated CVSS 9.8 (Critical) in most CVEs.
Why best: Denylisting dangerous classes (Java serialization filters, etc.) is the alternative — it requires knowing every gadget chain in advance and fails when new chains are discovered. Using data-only formats (JSON) eliminates the vulnerability class: JSON can represent data structures but cannot encode executable code.
Sources: OWASP Deserialization Cheat Sheet; Apache Commons Collections CVE-2015-4852; CWE-502; Java Serialization "AppSecCali 2015 — Marshalling Pickles" (Frohoff & Lawrence)
Prefer data-only serialization formats — JSON, XML (with XXE disabled), MessagePack, Protobuf, or Avro. These encode data, not executable objects.
# BAD — pickle executes arbitrary code on load
import pickle
obj = pickle.loads(user_input)
# GOOD — JSON only represents data
import json
data = json.loads(user_input) # safe; validate schema after
If native serialization is required, validate/authenticate the data before deserializing:
Sign the serialized blob with an HMAC and verify the signature before deserializing:
import hmac, hashlib, pickle
SECRET = b'server-secret-key-min-32-bytes-here'
def serialize_signed(obj):
payload = pickle.dumps(obj)
sig = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
return sig + ':' + payload.hex()
def deserialize_verified(signed_data):
sig, hex_payload = signed_data.split(':', 1)
payload = bytes.fromhex(hex_payload)
expected = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
raise ValueError("Signature mismatch — data tampered")
return pickle.loads(payload)
Java — implement serialization filters (JEP 290):
// Java 9+ serialization filter — allowlist only expected classes
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"com.example.SafeClass;!*" // allow only SafeClass, reject all others
);
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);
Object obj = ois.readObject();
Alternatively, use safer alternatives: Jackson (with @JsonTypeInfo restrictions), Kryo with registered-classes-only mode, or FST with class registration.
PHP — avoid unserialize() with untrusted input:
// BAD
$obj = unserialize($_COOKIE['data']);
// GOOD — use JSON
$data = json_decode($_COOKIE['data'], true);
// If unserialize is unavoidable, use allowed_classes:
$obj = unserialize($data, ['allowed_classes' => ['SafeClass']]);
Ruby — avoid Marshal.load with untrusted data:
# BAD
obj = Marshal.load(user_supplied_string)
# GOOD — JSON
require 'json'
data = JSON.parse(user_supplied_string)
Validate schema after deserialization — even with safe formats, verify the structure matches expectations before using the data:
import json
from jsonschema import validate
schema = {"type": "object", "properties": {"user_id": {"type": "integer"}}, "required": ["user_id"]}
data = json.loads(user_input)
validate(instance=data, schema=schema)
Log and alert on deserialization failures — unexpected deserialization errors often indicate exploit attempts:
try:
obj = deserialize(input_data)
except (ValueError, TypeError, pickle.UnpicklingError) as e:
logger.warning("Deserialization failure from %s: %s", request.remote_addr, e)
raise BadRequest("Invalid data format")
pickle.loads, yaml.load (without Loader=yaml.SafeLoader), Marshal.load, and Java's ObjectInputStream are unsafe on untrusted input — no exceptions.yaml.load() without SafeLoader allows arbitrary Python object construction — always use yaml.safe_load().yaml.load(input) instead of yaml.safe_load(input) — YAML's default loader supports Python object tags and executes arbitrary constructors.ObjectInputStream without filters — the default behavior accepts all classes, enabling gadget-chain RCE.npx claudepluginhub jeffreytse/grimoire --plugin grimoireAnalyzes insecure deserialization risks in Java, Python, PHP, Ruby, and .NET — focusing on RCE via ObjectInputStream, pickle, unserialize, Marshal.load, and YAML.load.
Attack checklist for insecure deserialization in Java, PHP, .NET, Python. Covers sinks, ysoserial gadgets, magic methods, evasion. Use only for authorized security testing.
Identifies and exploits insecure deserialization vulnerabilities in Java, PHP, Python, .NET apps for RCE during authorized pentests. Detects serialized payloads in HTTP traffic using ysoserial, PHPGGC, Burp Suite.