Symptom

Kraken’s nightly dependency-CVE scan opened #818: seven open Dependabot alerts on com.fasterxml.jackson.core:jackson-databind (medium/high), all reachable transitively through kandy-lets-plot → arrow on the server’s jvmRuntimeClasspath. The lead’s proposed fix was to bump the jackson version ref in gradle/libs.versions.toml from 2.21.1 to 2.21.4.

Root cause

gradle/libs.versions.toml pinned jackson = "2.21.1" via a forced jackson-bom platform in server/build.gradle.kts, which was already one patch behind. ./gradlew :server:dependencies --configuration jvmRuntimeClasspath confirmed jackson-databind:2.21.1 resolved on the shipped classpath — the “shippable runtime” classification was correct.

The proposed bump to 2.21.4 would have cleared six of the seven alerts (GHSA-5hh8-q8hv-fr38, GHSA-9fxm-vc8v-hj55, GHSA-hgj6-7826-r7m5, GHSA-rmj7-2vxq-3g9f, GHSA-j3rv-43j4-c7qm, GHSA-rcqc-6cw3-h962 — all first_patched_version: 2.21.4 per the GitHub Advisory API) but left one open: GHSA-5jmj-h7xm-6q6v (CVE-2026-54515, case-insensitive @JsonIgnoreProperties bypass). That advisory’s structured vulnerable_version_range for the 2.21.x line is >= 2.19.0, < 2.21.5 with first_patched_version: null — the machine-readable field is empty because the advisory prose, not the structured range, is where the fix version lives: “Will be fixed in 2.18.9, 2.21.5, 2.22.1 and 3.1.4.” A local model (or a naive automation) reading only the alert’s range/first-patched fields would miss that 2.21.4 doesn’t actually clear this one — it needs 2.21.5.

Fix

gradle/libs.versions.toml — bumped jackson from 2.21.1 to 2.21.5 (not the proposed 2.21.4), with an updated comment recording why 2.21.5 specifically. Verified via jackson-bom’s Maven Central metadata that 2.21.5 is published, then re-ran ./gradlew :server:dependencies --configuration jvmRuntimeClasspath to confirm jackson-databind/jackson-core both resolve to 2.21.5 project-wide (no stray transitive override survives the BOM force). :server:jvmTest and :server:shadowJar both stay green, and unzipping the resulting server-all.jar confirms jackson-databind-2.21.5’s pom.properties is the one actually bundled into the shipped artifact — not just resolved at configuration time.

Prevention

When triaging a Dependabot/GHSA-driven version bump, don’t trust an alert’s first_patched_version field at face value if it’s null — some advisories (especially ones covering multiple major lines at once, like this one spanning 2.18.x/2.21.x/2.22.x/3.x) only carry the fix version in the free-text description. Cross-check every alert in the cluster against the target version before shipping the bump, and prefer bumping to the highest version needed to clear every alert in the cluster in one PR rather than the version that clears only the majority.