JSON and Jacksonsenior8+ years

A payments service needs to deserialize a polymorphic `PaymentMethod` — `CardPayment`, `BankTransferPayment`, `WalletPayment` — from a JSON field that names the subtype. A junior engineer suggests enabling `ObjectMapper.enableDefaultTyping()` so any request body can just work without per-type annotations. Why is that a serious security decision disguised as a convenience one, and what should be done instead?

enableDefaultTyping() doesn't just make polymorphic deserialization more convenient — it hands the incoming JSON the power to name any class on the classpath and have Jackson instantiate it, resolved with something equivalent to Class.forName. That's structurally the same shape of vulnerability as Java's own object serialization, which the lesson explicitly warns off for anything crossing a trust boundary: deserializing untrusted input can construct arbitrary classes and, through "gadget chains" in commonly used libraries already sitting on the classpath, that construction can be turned into remote code execution. This exact setting produced a long, well-documented series of real CVEs for exactly this reason. The safe alternative is @JsonTypeInfo paired with @JsonSubTypes — a discriminator field the JSON supplies, but resolved only against an explicit, closed list of classes the application itself wrote down and reviewed. Jackson never constructs anything the input alone named; it only ever constructs one of the types on that list.

The lesson behind it →
More on JSON and Jackson