4.9 KiB
Apache Flink — CWE-407 Disclosure Brief
2026-03-27 · Patch available — awaiting upstream merge
Finding
Four O(n²) defects in Apache Flink's job graph construction, Table API SQL planning, and sink schema processing. All patched. Patches ready for upstream review.
The Defects
flink-0001 (PATCHED — HIGH): runtime/src/main/java/.../JobGraph.java
// On job graph construction — userJars dedup:
List<Path> userJars = new ArrayList<>();
// ...
if (!userJars.contains(jar)) { // O(n) List.contains() per jar
userJars.add(jar);
}
// O(n²) dedup over n user JARs
userJars is a List. .contains() performs O(n) scan per JAR addition during job graph construction. O(n²) total. Fix: LinkedHashSet. PATCHED.
flink-0002 (PATCHED — HIGH): table/api/.../RowTypeUtils.java:43,49
// Inside field dedup — nested for + do-while:
List<String> checklist = new ArrayList<>();
List<String> result = new ArrayList<>();
// ...
if (!checklist.contains(field) && !result.contains(field)) {
// O(N×M²) total — both lists scanned per field
}
checklist.contains() and result.contains() both O(N) per field in nested for+do-while. O(N × M²) field dedup. Measured ratio: 37×.
flink-0003 (PATCHED — HIGH): flink-table/.../AggregateReduceGroupingRule.java:88
// Inside aggregate pushdown query planning:
if (newGroupingList.contains(field)) { ... } // O(G) List.contains() per field
// O(G²) per planning step
newGroupingList.contains() O(G) per field in aggregate grouping reduction. O(G²) query planning. Measured ratio: 50×.
flink-0004 (PATCHED — HIGH): flink-table/.../DynamicSinkUtils.java
// In schema-columns processing:
List<String> updatedColumnNames = new ArrayList<>();
// ...
if (!updatedColumnNames.contains(col)) { ... } // O(C) per column
int idx = updatedColumnNames.indexOf(col); // O(U) per column
// O(C×U) total — columns × updated columns
Both .contains() and .indexOf() on List<String> inside the schema-columns loop. O(C × U) total. Fix: HashSet + Map. Measured ratio: 48×.
Complexity Proof
flink-0001: For n user JARs added to the job graph:
- Per JAR: O(n)
List.contains()scan - Total: O(n²) — fixed:
LinkedHashSet.
flink-0002: For N fields, M checklist entries:
- O(N×M²) — 37× measured ratio.
flink-0003: For G=50 grouping fields:
- O(G²) = 2,500 comparisons per planning step
- Fixed:
Set<Integer>→ O(G) - 50× measured ratio.
flink-0004: For C columns and U updated column names:
- Per column: O(C)
contains()+ O(U)indexOf()scan - Total: O(C × U)
- 48× measured ratio. Fixed:
HashSet<String>+HashMap<String, Integer>.
Impact
All Apache Flink deployments. flink-0001 fires on every job graph construction with multiple user JARs. flink-0002 and flink-0003 affect all SQL or Table API deployments — the primary programming model for Flink. RowTypeUtils is used in schema inference and field resolution; AggregateReduceGroupingRule fires during aggregate pushdown optimization for GROUP BY queries. flink-0004 fires during dynamic sink schema processing. Complex queries with many fields and grouping keys hit all four defects during query planning and job submission.
The Fix
flink-0002: Replace checklist/result lists with LinkedHashSet:
// Before
if (!checklist.contains(field) && !result.contains(field)) { ... } // O(M²)
// After
// CWE-407 fix: LinkedHashSet for O(1) contains() instead of O(M) list scan.
Set<String> checkSet = new LinkedHashSet<>();
Set<String> resultSet = new LinkedHashSet<>();
if (!checkSet.contains(field) && !resultSet.contains(field)) { ... }
flink-0003: Replace newGroupingList ArrayList with LinkedHashSet.
flink-0004: Replace updatedColumnNames list with HashSet<String> for membership and HashMap<String, Integer> for index lookup:
// Before
if (!updatedColumnNames.contains(col)) { ... }
int idx = updatedColumnNames.indexOf(col);
// After
// CWE-407 fix: HashSet + HashMap for O(1) contains/index instead of O(C) + O(U) scans.
Set<String> updatedColumnSet = new HashSet<>(updatedColumnNames);
Map<String, Integer> updatedColumnIndex = IntStream.range(0, updatedColumnNames.size())
.boxed().collect(Collectors.toMap(updatedColumnNames::get, i -> i));
Patch
defects/flink/patch/flink-0001-jobgraph-linkedhashset.patch
defects/flink/patch/flink-0002-0003-rowtypeutils-grouping-set.patch
defects/flink/patch/flink-0004-dynamicsinkutils-hashset-map.patch
What We Ask
- Confirm receipt and assign a GitHub Security Advisory or JIRA reference.
- Validate the patch against your Table API SQL planning test suite.
- Assess CVE eligibility — both defects fire during SQL query planning.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
Contact: see cover email. This brief is confidential until coordinated disclosure.