From 7f630bea17f9356be9630c3b010fd2b4c9fdac76 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 14:36:37 +0000 Subject: [PATCH] fix(security): raise Kotlin Gradle plugin, httpclient and commons-lang3 floors - kotlin-gradle-plugin 2.2.10 -> 2.4.20 on the root buildscript classpath (AGP 9.4.1 still ships 2.2.10; GHSA-r937-wjx7-w2jp, Kotlin build cache unsafe deserialization) - httpclient 4.5.6 -> 4.5.14 and commons-lang3 3.16.0 -> 3.21.0 on the Android lint tool configuration (GHSA-7r82-7xv7-xcpj, GHSA-j288-q9x7-2f5v), as per-module floors because org.apache.commons also holds commons-compress and commons-codec All build-toolchain only; nothing reaches the published AAR. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_018LexopwXbMBrV7EjBEdWu8 --- android/build.gradle.kts | 17 ++++++++++++++--- build.gradle.kts | 5 ++++- gradle/libs.versions.toml | 7 +++++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 9c45e49..12ea3b5 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -40,8 +40,8 @@ jacoco { // Raise known-vulnerable transitive dependencies of the build toolchain to patched // versions. None of these is a dependency of the SDK itself - they are pulled in by the // Android Gradle Plugin's Unified Test Platform (netty, protobuf), by Dokka's engine -// (jackson, jsoup, freemarker) and by the Kotlin plugin's signing helpers (Bouncy Castle), -// so the published AAR and its POM are unaffected. +// (jackson, jsoup, freemarker), by the Kotlin plugin's signing helpers (Bouncy Castle) and by the +// Android lint tool (httpclient, commons-lang3), so the published AAR and its POM are unaffected. // // These are floors, not overrides: `useVersion` on its own would also drag a *newer* // version back down, so anything at or above the floor is left alone and only older @@ -64,6 +64,15 @@ run { "org.bouncycastle" to libs.versions.bouncycastle.get(), ) + // Floors for single artifacts whose group also holds artifacts that must not be moved. + val moduleFloors = mapOf( + // The Android lint tool pulls httpclient 4.5.6 (via httpmime) and commons-lang3 3.16.0 + // (via commons-compress). commons-compress and commons-codec share the + // org.apache.commons group, hence the per-module floor. + "org.apache.httpcomponents:httpclient" to libs.versions.httpclient.get(), + "org.apache.commons:commons-lang3" to libs.versions.commonsLang3.get(), + ) + fun isBelowFloor(current: String?, floor: String): Boolean { if (current.isNullOrBlank()) return true fun numericParts(v: String) = v.split('.', '-', '_').mapNotNull(String::toIntOrNull) @@ -83,7 +92,9 @@ run { // pinned jackson-bom already pulls it to the matching line, so leave it alone. if (requested.name == "jackson-annotations") return@eachDependency - val floor = securityFloors[requested.group] ?: return@eachDependency + val floor = moduleFloors["${requested.group}:${requested.name}"] + ?: securityFloors[requested.group] + ?: return@eachDependency if (isBelowFloor(requested.version, floor)) { useVersion(floor) because("security floor - see gradle/libs.versions.toml") diff --git a/build.gradle.kts b/build.gradle.kts index 6b69936..a7e405e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ // The Android Gradle Plugin drags its own tooling onto this build script's classpath: gRPC and // Netty (io.grpc:grpc-netty), Bouncy Castle (com.android.tools:sdk-common), commons-compress -// (:repository), jose4j (bundletool) and JDOM (jetifier). The resolutionStrategy in +// (:repository), jose4j (bundletool), JDOM (jetifier) and the Kotlin Gradle plugin. The resolutionStrategy in // android/build.gradle.kts cannot reach any of it - that block configures the :android project's // own configurations, which are resolved separately, so Netty was still landing at 4.1.93.Final // there while the floor read 4.1.138.Final. @@ -23,6 +23,9 @@ buildscript { // Not from AGP directly: commons-compress 1.26+ depends on it, so the floor above // brings it onto this classpath. add("classpath", "org.apache.commons:commons-lang3:${libs.versions.commonsLang3.get()}") + // AGP 9.4.1 still resolves 2.2.10, which has an unsafe-deserialization flaw in the + // Kotlin build cache (fixed in 2.4.20-Beta1). It is already 2.4.20 in :android. + add("classpath", "org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}") } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f802a13..e5d1d31 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,10 +33,12 @@ dokka = "2.2.0" # resolved independently: # # - build.gradle.kts (root buildscript) - AGP's own plugin classpath. gRPC/Netty, Bouncy -# Castle, commons-compress (and its commons-lang3), jose4j and JDOM live here. +# Castle, commons-compress (and its commons-lang3), jose4j, JDOM and the Kotlin Gradle +# plugin (AGP 9 still ships 2.2.10; `kotlin` above is the floor) live here. # - android/build.gradle.kts (resolutionStrategy) - the :android project's configurations, # including AGP's Unified Test Platform, Dokka's engine (jackson, jsoup, freemarker) and -# the Kotlin plugin's signing helpers (Bouncy Castle again). +# the Kotlin plugin's signing helpers (Bouncy Castle again) and the Android lint tool +# (httpclient via httpmime, commons-lang3 via commons-compress). # # Dependabot reports both, attributing every alert to settings.gradle.kts - check which # classpath a version is on before adding a floor. @@ -54,6 +56,7 @@ jose4j = "0.9.6" jdom2 = "2.0.6.1" commonsCompress = "1.27.1" commonsLang3 = "3.21.0" +httpclient = "4.5.14" freemarker = "2.3.35" [libraries]