Nightly dependency-CVE scan (Kraken) flagged org.apache.commons:commons-lang3 with
GHSA-j288-q9x7-2f5v (severity: medium; affected range >= 3.0, < 3.18.0). No explicit
version was pinned, leaving the version solely in transitive conflict-resolution hands.
commons-lang3 was not listed in gradle/libs.versions.toml and no resolutionStrategy
floor was applied. Gradle’s conflict-resolution happened to select 3.18.0 (via
commons-compress:1.28.0 → dataframe-arrow / POI / kandy), but nothing prevented a
future transitive update from introducing a vulnerable sub-3.18.0 version undetected.
commons-lang3 = "3.18.0" to [versions] in gradle/libs.versions.toml with
a comment citing GHSA-j288-q9x7-2f5v.allprojects { configurations.configureEach { resolutionStrategy.eachDependency } }
block in build.gradle.kts that floors org.apache.commons:commons-lang3 at 3.18.0
across all configurations, mirroring the existing gson / guava / log4j2 pattern.commons-lang3 in Gradle 9 version
catalog is libs.versions.commons.lang3.get() (nested), NOT libs.versions.commonsLang3.get()
(flat camelCase). Single-segment keys are flat; multi-segment keys form nested accessor classes.When a transitive CVE is cleared by Gradle’s existing conflict-resolution (i.e., the
resolved version already satisfies the floor), still add an explicit resolutionStrategy
floor so any future transitive regression is caught at build time, not discovered by the
next CVE scan.
Note on Gradle accessor naming: multi-segment version catalog keys (e.g., commons-lang3)
generate NESTED type-safe accessors (libs.versions.commons.lang3), while single-segment
keys (e.g., log4j2, gson) generate flat accessors (libs.versions.log4j2). Attempting
libs.versions.commonsLang3 (flat camelCase) for a two-segment key is an unresolved reference.