# jackson-databind has a PolymorphicTypeValidator bypass via generic type parameters that allows arbitrary class instantiation

Jackson-databind's PolymorphicTypeValidator validates only the raw container class in generic type IDs, letting attackers smuggle denied classes as type parameters and instantiate them.

- Payout: Research
- Severity: high
- Program: jackson-databind
- Found by: caveeroo, omkhar, 75ACOL
- Disclosed: 2026-06-23
- CVE: CVE-2026-54512
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-j3rv-43j4-c7qm
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-j3rv-43j4-c7qm
- Tags: area:oss domain:oss impact:integrity impact:rce kind:research platform:ghsa sev:high tech:java technique:incomplete-fix technique:source-review vuln:auth-bypass vuln:deserialization

**Target:** Java JSON deserialization library (PolymorphicTypeValidator / DatabindContext)
**Root cause:** _resolveAndValidateGeneric() validates only the raw container class name (substring before `<`) against the PTV, then parses the full canonical type via TypeFactory.constructFromCanonical() and returns parameterized type without validating nested type arguments.
**Steps:**
1. Configure BasicPolymorphicTypeValidator allowing only `java.util.ArrayList`.
2. Send payload `{"value":["java.util.ArrayList<com.evil.EvilGadget>",[{"cmd":"calc.exe"}]]}` to a field typed Object with `@JsonTypeInfo(use=Id.CLASS, include=As.WRAPPER_ARRAY)`.
3. Container `java.util.ArrayList` passes PTV check; `com.evil.EvilGadget` is loaded via `Class.forName(name, true, loader)`, instantiated, and its `cmd` property set.
4. Variants: `java.util.HashMap<Evil,String>`, `java.util.HashMap<String,Evil>`, `java.util.ArrayList<java.util.ArrayList<Evil>>`, `java.util.ArrayList<Evil[]>`.
**How found:** Code review of DatabindContext._resolveAndValidateGeneric() revealed the PTV check only inspects the substring before `<`, while the full canonical string is later parsed and its type arguments resolved without validation.
**Exploitation:** Attacker controlling the type ID places a denied gadget class as a generic parameter of an allow-listed container; the container passes validation, the nested class is instantiated with attacker-controlled properties, enabling side-effect gadgets (JNDI, JDBC, TemplatesImpl) for potential RCE.
**Escalation:** Chain smuggled gadget class with exploitable side effects (JNDI lookup, connection-pool gadgets, TemplatesImpl loaders) present on classpath to reach RCE.
**Insight:** When auditing type-allow-list validators, check whether generic/parameterized type strings are validated recursively — a check on the raw container name alone leaves nested type arguments unvalidated and instantiable.

## Proof of concept (copied exactly from the original report)

**Malicious JSON payload bypassing PTV allow-list**

```
{"value":["java.util.ArrayList<com.evil.EvilGadget>",[{"cmd":"calc.exe"}]]}
```

**PTV config restricting to ArrayList only**

```
BasicPolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder()
        .allowIfSubType("java.util.ArrayList")
        .build();

ObjectMapper mapper = JsonMapper.builder()
        .polymorphicTypeValidator(ptv)
        .build();
```

