java-topology/whitepaper/outreach/gradle.md

3.2 KiB
Raw Blame History

Gradle — CWE-407 Disclosure Brief

Project: Gradle Disclosure date: 2026-03-27 Severity: HIGH Speedup: varies with M×Status: PATCHED


Finding

Gradle's CLI option reader rebuilds a list via CollectionUtils.toList().contains() for every method-option pair evaluation. The OptionReader in subprojects/cli/ converts option collections to lists on each membership check rather than pre-building the list once, producing O(M×O²) total work where M is the number of methods with options and O is the number of options per method.

The Defect(s)

ID Location Pattern Complexity
gradle-0001 subprojects/cli/ OptionReader CollectionUtils.toList().contains() rebuilt per method-option pair O(M×O²)

Complexity Proof

Let M = number of methods with declared options, O = number of options per method.

For each of the M methods, the OptionReader validates options by iterating over all O options and calling CollectionUtils.toList().contains(option) for each. toList() constructs a new List from the collection on every invocation, making each membership check O(O) — both due to the list rebuild and the subsequent linear scan:

For method_1:
  For option_1: toList() O(O) + contains() O(O) = O(O)
  For option_2: toList() O(O) + contains() O(O) = O(O)
  ...
  For option_O: O(O)
  Subtotal: O × O = O(O²)

For all M methods: M × O² total work

Pre-building the option list or set once per method reduces inner membership checks to O(1), making total work O(M×O). For M = 50 task methods with O = 20 options each, the defective path performs 50 × 400 = 20,000 operations; the fixed path performs 50 × 20 = 1,000.

Impact

Gradle users invoking tasks with many declared options — custom plugins with extensive option sets, build scripts using @Option-annotated task properties extensively — experience superlinear CLI parsing time. Large enterprise Gradle builds with many custom tasks and option declarations are most affected. The defect occurs during task option resolution, which runs on every Gradle invocation before the build graph is even constructed.

The Fix

Pre-build the option list or HashSet once per method before iterating options. Replace CollectionUtils.toList().contains(option) with a single pre-built Set.contains(option) that is constructed once and reused for all O membership checks.

Patch

- for (Method method : methods) {
-     for (String option : options) {
-         if (CollectionUtils.toList(method.getOptions()).contains(option)) {
-             // handle option
-         }
-     }
- }
+ for (Method method : methods) {
+     Set<String> methodOptions = new HashSet<>(CollectionUtils.toList(method.getOptions()));
+     for (String option : options) {
+         if (methodOptions.contains(option)) {
+             // handle option
+         }
+     }
+ }

What We Ask

Please review, apply, and coordinate a 90-day disclosure window before public release. Reply to security@undefect.com.


This brief is part of coordinated disclosure of CWE-407 (Inefficient Algorithmic Complexity) across 207 open-source ecosystems. Full report: https://undefect.com