# Deserialization type instantiation gadget chains

Input picks a class or type name that gets instantiated, reaching constructors, getters, or loaders with side effects

_Area: Web injection and code execution. Seen in 5 disclosed reports; 2 confirmed bounties: $500 and $20,000; latest 2025-12-08. Updated 2026-10-23._

## How it works
A parser is asked to rebuild typed objects, not just data. It resolves a class or type name from the input, instantiates it, then calls constructors, setters, or getters. The broken assumption is that only data crosses the boundary; in fact the attacker chooses which already-loaded class gets built and with what field values. Any class on the classpath or runtime becomes reachable, and one whose constructor or getter does file IO, `require`/`load`, JDBC connect, or `Function()` turns type selection into code execution [E1](https://bugbountylibrary.com/r/h1%3A1125425.md)[E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md)[E4](https://bugbountylibrary.com/r/h1%3A73257.md). Ruby's `create_additions`/`json_create` is the same shape: input names a class whose factory method runs [E5](https://bugbountylibrary.com/r/h1%3A706934.md). A related shape is a decoder that fails to type-check references, letting attacker objects impersonate internal types and resolve to a constructor [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md).

## Where it shows up
- Renderer inline options reaching `const_get`/`constantize` then instantiated with attacker opts [E1](https://bugbountylibrary.com/r/h1%3A1125425.md)
- Default typing / polymorphic type fields in JSON or XML deserializers [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md)
- Decoders that resolve `$`-prefixed chunk references without type-checking them [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md)
- Parsers with undocumented tags that bridge to native deserialization (`!php/object`) [E4](https://bugbountylibrary.com/r/h1%3A73257.md)
- Ruby JSON `json_create` on the nil-options branch [E5](https://bugbountylibrary.com/r/h1%3A706934.md)

## How to review
Find every path where input selects a type or class name. The invariant: the set of instantiable types must be a fixed allowlist, and no constructor, setter, or getter on those types may perform IO, loading, or command execution on attacker-controlled fields. Concrete checks:
- Grep for default-typing flags (`enableDefaultTyping`, `activateDefaultTyping`, `TypeNameHandling.All`) and `NetDataContractSerializer`/`BinaryFormatter` call sites; confirm none sit behind an unauthenticated handler [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md).
- Confirm the allowlist is actually enforced at the resolution point, not just that a flag is set; trace the resolved name into the instantiation call [E1](https://bugbountylibrary.com/r/h1%3A1125425.md)[E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md).
- For RSC/Flight, confirm the decoder type-checks chunk references before resolving them [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md).
- For Ruby, check both the options-hash and nil-options branches of the JSON parser [E5](https://bugbountylibrary.com/r/h1%3A706934.md).
- For PHP YAML, confirm `!php/object` is disabled [E4](https://bugbountylibrary.com/r/h1%3A73257.md).

## Variants seen
- Renderer inline options reaching `const_get` then a driver that `require_relative`s a path [E1](https://bugbountylibrary.com/r/h1%3A1125425.md)
- Flight/RSC chunk-state forgery rehydrating a thenable and reaching `Function()` [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md)
- Jackson default typing reaching a JDBC-connecting getter [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md)
- PHP YAML `!php/object` delegating to `unserialize()` [E4](https://bugbountylibrary.com/r/h1%3A73257.md)
- Ruby JSON `json_create` on the unpatched nil-options branch [E5](https://bugbountylibrary.com/r/h1%3A706934.md)

## Why fixes fail
Shared decoders mean fixing one framework leaves sibling consumers exposed; the bug lives in the library, so port the check to Waku/Vite RSC and similar [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md). A fix that patches one code path leaves the sibling branch exploitable [E5](https://bugbountylibrary.com/r/h1%3A706934.md).

## Impact and severity
RCE in most cases, including miner and backdoor deployment [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md) and SSRF-to-RCE [E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md). Severity is highest when the endpoint is auto-enabled or pre-auth and the gadget class ships by default; some cases required an authenticated or lower-privilege foothold first [E1](https://bugbountylibrary.com/r/h1%3A1125425.md)[E3](https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md)[E5](https://bugbountylibrary.com/r/h1%3A706934.md).

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1125425.md
- E2: https://bugbountylibrary.com/r/blog%3Awiz-io-blog-nextjs-cve-2025-55182-react2shell-deep-dive.md
- E3: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2019-07-22-jackson-gadgets-html.md
- E4: https://bugbountylibrary.com/r/h1%3A73257.md
- E5: https://bugbountylibrary.com/r/h1%3A706934.md
