insecure-deserialization
Skill2 starsChanged 4 months agoMITView on GitHub
SAST detection methodology for insecure deserialization (CWE-502) across Java (ObjectInputStream/ysoserial/Commons-Collections/Spring/JNDI), .NET (BinaryFormatter, LosFormatter/ViewState, Json.NET TypeNameHandling, ObjectStateFormatter), Python (pickle, unsafe PyYAML), PHP (unserialize + POP chains, phar://), Ruby (Marshal/YAML), and Node (node-serialize, funcster, unserialize). Covers magic-method gadget chains and how untrusted bytes reach a deserializer. Use when reviewing code that deserializes data. Writes confirmed findings to findings/10-insecure-deserialization.md.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- conjure-3301/skillstheir own version, first seen Aug 17, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- conjure-3301/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository49 other files it gives its agents.
- authentication-flawsSkill
- broken-access-control-idorSkill
- business-logic-flawsSkill
- cicd-and-pipeline-injectionSkill
- code-injectionSkill
- command-injectionSkill
- cors-misconfigurationSkill
- crlf-and-header-injectionSkill
- cross-site-scriptingSkill
- csrfSkill
- dependency-and-supply-chainSkill
- dom-clobbering-and-postmessageSkill
- graphql-injection-and-abuseSkill
- hardcoded-secretsSkill
- http-request-smugglingSkill
- iac-misconfigurationSkill
- information-disclosureSkill
- insecure-randomnessSkill
- jwt-vulnerabilitiesSkill
- ldap-injectionSkill
- llm-and-ai-application-securitySkill
- mass-assignmentSkill
- memory-safetySkill
- mobile-android-securitySkill
- mobile-ios-securitySkill
- nosql-injectionSkill
- oauth-oidc-saml-flawsSkill
- open-redirectSkill
- path-traversal-and-file-inclusionSkill
- prototype-pollutionSkill
- race-conditions-and-toctouSkill
- redosSkill
- sast-final-reportSkill
- sast-finding-validationSkill
- sast-methodologySkill
- security-logging-and-monitoring-failuresSkill
- security-misconfiguration-and-headersSkill
- server-side-template-injectionSkill
- session-managementSkill
- smart-contract-securitySkill
- sql-injectionSkill
- ssrfSkill
- unrestricted-file-uploadSkill
- unsafe-parsers-and-yamlSkill
- weak-cryptographySkill
- web-cache-poisoning-and-deceptionSkill
- websocket-securitySkill
- xpath-and-xml-injectionSkill
- xxeSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 2 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 24
If any reachable class (a *gadget*) performs a dangerous action in those methods, chaining gadgets turns byte control into remote code …
- Distinctive: line 43
All HTTP inputs (body, cookies, hidden fields, headers), uploaded/imported files, queue/RPC payloads, and cache entries.
- Very specific: line 96
Safe: do not deserialize untrusted data with native/polymorphic serializers.
- Very specific: line 97
Use data-only formats (JSON/Protobuf/MessagePack) mapped to known DTOs with
- Very specific: line 201
Prefer data-only formats mapped to known types with no polymorphic typing.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Insecure Deserialization — SAST Methodology
Class: Insecure Deserialization · CWE-502 · OWASP: A08 Software and Data Integrity Failures
Findings file: findings/10-insecure-deserialization.md
1. Overview
Insecure deserialization occurs when attacker-controlled bytes are handed to a deserializer that reconstructs arbitrary object graphs and, during reconstruction, invokes type constructors, setters, or "magic" lifecycle methods. If any reachable class (a gadget) performs a dangerous action in those methods, chaining gadgets turns byte control into remote code execution. The core test: do untrusted bytes reach a native-object deserializer (not a data-only parser) that permits arbitrary or polymorphic types? If yes, assume RCE is possible unless a strict type allowlist gates it.
2. Where it lives
- Session/state stores: serialized objects in cookies, hidden form fields, cache, message queues, or a database blob column.
- RPC/messaging: Java RMI, JMX, JMS, AMQP/Kafka payloads, .NET remoting.
- API bodies that deserialize with type information (
TypeNameHandling, polymorphic Jackson,phar://stream wrappers). - File uploads/imports that are
unserialized,pickle.loaded, orMarshal.loaded. - Framework internals: ASP.NET
ViewState/__VIEWSTATE, Node objects passed tonode-serialize.
3. Sources (tainted input)
All HTTP inputs (body, cookies, hidden fields, headers), uploaded/imported files,
queue/RPC payloads, and cache entries. Second-order: a serialized blob stored
earlier (session in DB/Redis, a queued job) and later deserialized — trace it to
the original write. PHP phar:// is a niche source: a filesystem operation on an
attacker-influenced path can trigger deserialization of embedded metadata.
4. Sinks (dangerous operations)
// Java — dangerous
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object o = ois.readObject(); // arbitrary gadget graph → RCE
XMLDecoder dec = new XMLDecoder(inputStream); dec.readObject();
// ysoserial payloads target: Commons-Collections, Spring, Groovy, JDK gadgets;
// many pivot to JNDI: InitialContext.lookup(attackerUrl) → remote class load.// .NET — dangerous
new BinaryFormatter().Deserialize(stream); // banned by MS, still found
new LosFormatter().Deserialize(viewState); // ViewState w/o MAC → RCE
new ObjectStateFormatter().Deserialize(data);
JsonConvert.DeserializeObject(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }); // gadget via $type# Python — dangerous
import pickle; pickle.loads(data) # __reduce__ → arbitrary call
import yaml; yaml.load(data) # no SafeLoader → object construction
jsonpickle.decode(data) # reconstructs arbitrary types// PHP — dangerous
$obj = unserialize($_COOKIE['data']); // POP chain via __wakeup/__destruct
file_exists("phar://" . $userPath); // phar:// → metadata deserialization# Ruby — dangerous
Marshal.load(data) # gadget chain → RCE
YAML.load(data) # pre-3.1 default = unsafe (Psych)// Node — dangerous
require('node-serialize').unserialize(userInput); // IIFE payload → RCE
require('funcster').deepDeserialize(userInput);
require('serialize-to-js') / 'cryo' with untrusted inputAny of these on untrusted bytes is dangerous. The distinguishing feature is type reconstruction: the deserializer instantiates classes named or implied in the data, versus a data-only parser that only produces strings/numbers/maps.
5. Sanitizers / safe patterns
Safe: do not deserialize untrusted data with native/polymorphic serializers.
Use data-only formats (JSON/Protobuf/MessagePack) mapped to known DTOs with
no polymorphic typing. Where native deserialization is unavoidable, enforce a
strict class allowlist: Java ObjectInputFilter/setObjectInputFilter
(JEP 290) or a look-ahead resolveClass allowlist; .NET avoid BinaryFormatter
entirely and set TypeNameHandling.None; Python use yaml.safe_load and never
pickle untrusted data; PHP unserialize($data, ['allowed_classes' => false]);
Ruby YAML.safe_load, avoid Marshal.load on untrusted input. Add integrity:
sign/MAC serialized state (e.g. ViewState MAC, HMAC cookies) so tampering is
rejected before deserialization.
Fails / not a real sanitizer:
- Blocklisting known gadget classes — the gadget space is open-ended; new chains appear constantly. Only allowlisting works.
- Encryption/encoding (base64, gzip) mistaken for a security control — it hides nothing from an attacker who controls the plaintext.
- MAC present but the key is default/leaked/hard-coded (classic ViewState RCE) — the signature is bypassable.
allowed_classesset to an over-broad list, ortrue(no restriction).- Type allowlist applied to one deserializer while another unguarded call exists.
- Assuming a "safe" JSON library is safe while
TypeNameHandling/enableDefaultTypingor a$type/!!python/objecttag re-enables polymorphism.
6. Detection methodology
- Find deserializer sinks.
rg -n 'readObject\(|ObjectInputStream|XMLDecoder|readUnshared' rg -n 'BinaryFormatter|LosFormatter|ObjectStateFormatter|NetDataContractSerializer|SoapFormatter' rg -n 'TypeNameHandling|enableDefaultTyping|@JsonTypeInfo' rg -n 'pickle\.loads?|yaml\.load\b|jsonpickle|Marshal\.load|YAML\.load\b' rg -n 'unserialize\(|phar://|node-serialize|funcster|serialize-to-js' - Confirm the input is untrusted: trace the byte source to HTTP/file/queue/ cache (directly or second-order). Constant/local test data is not a finding.
- Determine type freedom: does the call reconstruct arbitrary/polymorphic
types (native serializer,
TypeNameHandling.All,yaml.load,pickle)? or is it a data-only parse into a fixed DTO? - Check for a real gate: JEP 290 filter /
resolveClassallowlist /safe_load/allowed_classes=false/ MAC on the path? Verify it is not one of the §5 failures. - Assess gadget availability: are known gadget libraries on the classpath (Commons-Collections, Spring, Groovy, Jackson databind; .NET gadgets)? Presence raises confidence to RCE.
- Confirm reachability: exposed endpoint/consumer, reachable (pre-auth?).
7. Modern & niche variants
- Java
ObjectInputStream.readObject+ gadget chains: the archetypal case.ysoserialweaponizes gadget chains in Commons-Collections, Spring, Groovy, BeanShell, and pure-JDK classes; execution ridesreadObject/readResolve/InvocationHandlerhops. Many chains pivot through JNDI — a gadget callsInitialContext.lookup(attackerUrl), and the JNDI/LDAP reference loads a remote factory class = RCE (the Log4Shell mechanism). AlsoXMLDecoder.readObjectexecutes arbitraryjava.beansexpressions. - .NET:
BinaryFormatter/SoapFormatter/NetDataContractSerializeron untrusted input are RCE by design (ysoserial.net gadgets). ViewState:LosFormatter/ObjectStateFormatterwithout MAC — or with a known/default machine key — deserializes attacker__VIEWSTATEto RCE. Json.NETTypeNameHandling.All/Objects/Autolets$typename a gadget type (ObjectDataProvider,WindowsIdentity) for RCE. - Python:
pickle.loadsruns__reduce__/__reduce_ex__, letting a payload return(os.system, ('cmd',))— direct RCE. Unsafe PyYAMLyaml.loadhonors!!python/object/apply:os.systemtags to instantiate/call arbitrary callables.jsonpickle,dill, andshelveshare the pickle risk. - PHP:
unserializeon untrusted data drives POP (Property-Oriented Programming) chains — magic methods__wakeup,__destruct,__toString,__callon in-scope classes are chained into file writes or code execution.phar://deserialization triggers object instantiation from crafted PHAR metadata via any filesystem function on an attacker-influenced path (file_exists,fopen,getimagesize), no explicitunserializeneeded. - Ruby:
Marshal.loadreconstructs arbitrary objects (universal RDoc/Rails gadget chains → RCE).YAML.load(Psych) before safe-by-default honored!ruby/objecttags to instantiate arbitrary classes. - Node:
node-serialize/funcster/serialize-to-js/cryoreconstruct functions from serialized_$$ND_FUNC$$_payloads; an embedded IIFE executes on deserialization = RCE. - Magic-method gadget-chain intuition: the danger is never the top-level type
— it is the lifecycle callbacks invoked during reconstruction (
readObject,__wakeup/__destruct,__reduce__,readResolve, property setters). Spotting a finding = "untrusted bytes reach a reconstructor that calls user-defined lifecycle code on classes available in the app."
8. Common false positives
- Data-only parsers mapping to fixed DTOs with no polymorphic typing
(
JsonConvertwithTypeNameHandling.None,yaml.safe_load, Jackson without default typing). - Deserialization of trusted, integrity-protected data (validated MAC with a secret, non-default key) from a trusted source.
- Local/config/test fixtures deserialized from constants, not request data.
pickle/Marshalover an internal, non-attacker-reachable channel (still note as defense-in-depth, but lower severity/confidence).
9. Severity & exploitability
Base Critical — native/polymorphic deserialization of untrusted input is RCE
by default, especially with gadget libraries present. High if type freedom is
constrained but not fully allowlisted, or the sink is reachable only post-auth.
Lower only when a proven strict allowlist/safe_load gate is on the path (then
it is not a finding) or the channel is genuinely unreachable by attackers.
See references/severity-model.md.
10. Remediation
Prefer data-only formats mapped to known types with no polymorphic typing. Where
native deserialization is required, enforce a strict class allowlist (JEP 290
ObjectInputFilter, resolveClass), disable TypeNameHandling/enableDefaultTyping,
use yaml.safe_load/YAML.safe_load, unserialize(..., ['allowed_classes' => false]),
and never pickle/Marshal untrusted data. Sign/MAC any serialized state with a
strong non-default key. Remove unused gadget-prone libraries from the classpath.
11. Output
Append each confirmed finding to findings/10-insecure-deserialization.md
using references/finding-template.md. Set Class: Insecure Deserialization and
CWE: CWE-502. In Chain potential note that this class typically provides
the terminal RCE primitive (arbitrary code execution / arbitrary object
instantiation) and may provide a JNDI/SSRF pivot (remote class load) or
arbitrary file write; it commonly consumes an info-leak of a signing key /
machine key from another finding (turning a MAC-protected sink exploitable) or a
second-order write that plants the serialized blob.
Primitives (controlled): provides CODE_EXEC,OUTBOUND_REQUEST (JNDI/SSRF),FILE_WRITE; consumes GADGET,SECRET_LEAK (signing/machine key)
References
- CWE-502; OWASP A08:2021 Software and Data Integrity Failures; OWASP Deserialization Cheat Sheet; ysoserial / ysoserial.net gadget research.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

