Jackson is powerful, but some of its older configuration options can open serious security vulnerabilities in your application. The most critical is polymorphic type handling: when configured carelessly, it allows an attacker to supply a JSON payload that causes Jackson to instantiate and invoke arbitrary Java classes on your server — a Remote Code Execution (RCE) vector known as “deserialization gadget attacks.” This guide explains the risk, shows you what to avoid, and demonstrates the safe patterns you should follow in all production code.
Runnable code: every example below is in the jackson3-by-example repository, compiled and executed against Jackson 3.2.1 on JDK 21 — H01 the safe pattern, H02 which APIs survived into Jackson 3, H03 a provable allowlist with a negative test, H04 resource limits and H05 Object.class, with captured output in docs/part7-security.md.
The Risk: enableDefaultTyping and Gadget Attacks
Jackson historically provided a method called enableDefaultTyping() that automatically embedded and honoured Java class names in serialised JSON. This means an attacker who can send JSON to your application could supply a class name of their choosing as the type discriminator, causing Jackson to instantiate that class during deserialisation.
The attack exploits classes already on the JVM classpath that have side effects in their constructors or setters — so-called “gadget classes.” Common culprits include JDBC drivers, logging libraries, and many Apache Commons classes.
Never use this in production:
// DANGEROUS — do not use in any application that receives untrusted JSON
mapper.enableDefaultTyping(); // Deprecated and removed in Jackson 2.16
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // Also dangerous
Both were deprecated in Jackson 2.10 and are completely absent in Jackson 3.x. If you encounter them in a codebase being migrated to Jackson 3, treat it as a blocker — the code will not compile and the security risk must be remediated before upgrading.
One correction worth making here, since it changes when the pain lands: enableDefaultTyping() was not removed in 2.16. It is still present, deprecated, on ObjectMapper in Jackson 2.22.1 — a reflective check confirms it. So a Jackson 2 codebase can keep compiling against it through every 2.x upgrade, and Jackson 3 is where it finally fails. That is arguably the removal working as intended: the compiler forces the audit exactly once, at the major version boundary.