1026 lines
37 KiB
Markdown
1026 lines
37 KiB
Markdown
# Send Queue — CWE-407 Coordinated Disclosure
|
||
|
||
**Date:** 2026-03-26
|
||
**From:** security@undefect.com
|
||
**Window:** 90 days from first contact per target
|
||
|
||
---
|
||
|
||
## 1. FRRouting — frrouting-0002 — OSPF SPF 199.5x
|
||
|
||
**Priority:** 1
|
||
**Contact:** security@frrouting.org (primary); GitHub advisory fallback: https://github.com/FRRouting/frr/security/advisories/new
|
||
**Method:** Email
|
||
**Attachment:** `whitepaper/outreach/pdf/frrouting.pdf` (MD5: `95f4c539a13e3d0aa33807c81acc2348`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in FRRouting OSPF SPF — coordinated disclosure request
|
||
```
|
||
|
||
**Body:**
|
||
```
|
||
To: security@frrouting.org
|
||
From: security@undefect.com
|
||
Subject: Pre-disclosure: CWE-407 in FRRouting OSPF SPF — coordinated disclosure request
|
||
|
||
Hello FRRouting Security Team,
|
||
|
||
We have identified a confirmed CWE-407 (Inefficient Algorithmic Complexity) defect in
|
||
FRRouting's OSPF implementation. A patch is ready. We are requesting a 90-day coordinated
|
||
disclosure window before any public release.
|
||
|
||
--- The Defect ---
|
||
|
||
frrouting-0002: ospf_spf.c, line 275
|
||
|
||
listnode_lookup(vp->parent->children, v)
|
||
|
||
This call appears inside Dijkstra's main SPF loop. `vp->parent->children` is a linked
|
||
list. `listnode_lookup` performs a linear scan from the head on every invocation.
|
||
|
||
On a hub-and-spoke topology with H spoke routers:
|
||
|
||
- The hub's children list accumulates H entries as spokes are processed
|
||
- Each subsequent spoke scans that list to locate its predecessor
|
||
- Scan lengths: 1, 2, 3, ... H — sum = H(H+1)/2 = O(H²)
|
||
|
||
This cost is paid on every OSPF SPF computation. Every link flap, BFD timeout, metric
|
||
change, or router restart triggers a full SPF rerun. On busy ISP cores this fires
|
||
continuously.
|
||
|
||
--- Impact ---
|
||
|
||
Every FRRouting router running OSPF on a hub-and-spoke or partial-mesh topology:
|
||
|
||
- ISP hub sites aggregating spoke CPE or PE routers
|
||
- Enterprise MPLS cores with hub-site route reflectors
|
||
- Carrier peering fabrics with high-degree OSPF speakers
|
||
- Data center spine/leaf fabrics running OSPF underlay
|
||
|
||
Under load with frequent topology events, the O(H²) SPF cost delays convergence — the
|
||
opposite of what OSPF is supposed to provide.
|
||
|
||
--- The Fix ---
|
||
|
||
Add `struct hash *children_index` to `struct vertex` in ospf_spf.h. In
|
||
`ospf_vertex_add_parent()`, replace `listnode_lookup(vp->parent->children, v)` with
|
||
`hash_lookup(vp->parent->children_index, v)` — O(1). The linked list is retained for
|
||
ordered traversal; the hash is used solely for the duplicate membership check.
|
||
Allocation in `ospf_vertex_new()`, cleanup in `ospf_vertex_free()`.
|
||
|
||
FRRouting already uses `hash_*` APIs extensively elsewhere in the codebase — the pattern
|
||
is established. The TI-LFA fix (frrouting-0001) already demonstrates the team knows how
|
||
to address this class of defect. frrouting-0002 is the same pattern in a hotter code path.
|
||
|
||
--- Benchmark ---
|
||
|
||
Patch: defects/frrouting/patch/frrouting-0002-ospf-spf-vertex-parent-hashset.patch
|
||
|
||
Unit tests: 5/5 pass.
|
||
At V=400 spoke routers: defective=79,800 comparisons, fixed=400 comparisons — 199.5x speedup.
|
||
|
||
The full complexity proof, before/after code, and benchmark methodology are in the
|
||
attached brief (frrouting.pdf).
|
||
|
||
--- What We Ask ---
|
||
|
||
1. Confirm receipt within 5 business days and assign a tracker reference.
|
||
2. Validate the patch against your CI / regression suite.
|
||
3. Assess whether frrouting-0002 warrants a CVE (CWE-407 — algorithmic complexity,
|
||
degraded OSPF convergence under load).
|
||
4. Coordinate a disclosure date within the 90-day window (deadline: 90 days from today).
|
||
|
||
Credit is optional — the goal is the fix. If you have a preferred acknowledgment format,
|
||
let us know.
|
||
|
||
This message is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
|
||
--- Attachment integrity ---
|
||
|
||
frrouting.pdf MD5: 95f4c539a13e3d0aa33807c81acc2348
|
||
Verify with: md5sum frrouting.pdf
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Tor Project — tor-0001 — Router fingerprint lookup 200.5x
|
||
|
||
**Priority:** 2
|
||
**Contact:** security@torproject.org (primary); GitLab fallback: https://gitlab.torproject.org (open a confidential security issue)
|
||
**Method:** Email
|
||
**Attachment:** `whitepaper/outreach/pdf/tor.pdf` (MD5: `15de40cac68482513013c5849001a685`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in Tor routerlist fingerprint lookup — coordinated disclosure request
|
||
```
|
||
|
||
**Body:**
|
||
```
|
||
To: security@torproject.org
|
||
From: security@undefect.com
|
||
Subject: Pre-disclosure: CWE-407 in Tor routerlist fingerprint lookup — coordinated disclosure request
|
||
|
||
Hello Tor Security Team,
|
||
|
||
We have identified a confirmed CWE-407 (Inefficient Algorithmic Complexity) defect in
|
||
Tor's router descriptor download logic. A patch is ready. We are requesting a 90-day
|
||
coordinated disclosure window before any public release.
|
||
|
||
--- The Defect ---
|
||
|
||
tor-0001: src/feature/nodelist/routerlist.c, line 2179
|
||
|
||
smartlist_contains_string(requested_fingerprints, fp)
|
||
|
||
`requested_fingerprints` is a `smartlist_t` — Tor's dynamic array.
|
||
`smartlist_contains_string` scans from index 0 on every call. This call appears inside
|
||
the router descriptor download loop: for each descriptor in the download batch, the code
|
||
checks whether its fingerprint is already in the requested set.
|
||
|
||
Batch size R descriptors → R membership checks → each check scans up to R entries →
|
||
O(R²) string comparisons total.
|
||
|
||
For a directory authority processing a full consensus: R ≈ 8,000 relays.
|
||
O(R²) ≈ 32,000,000 string comparisons at startup and on each full directory refresh.
|
||
Each comparison is a strcmp on a 40-character hex fingerprint.
|
||
|
||
--- Impact ---
|
||
|
||
- Directory authorities: worst case. Full consensus download on start or after a
|
||
split-brain event. 32M string comparisons before the authority can serve clients.
|
||
- Relays: directory updates fire hourly. Under churn (guard turnover, relay churn
|
||
events) the batch size grows.
|
||
- Clients: partial consensus downloads — smaller R, but fires on every bootstrap
|
||
and every hourly update.
|
||
|
||
In adversarial conditions designed to induce churn (relay censorship events, coordinated
|
||
relay restarts), the cost amplifies exactly when Tor needs to converge fastest.
|
||
|
||
--- The Fix ---
|
||
|
||
The correct fix is already demonstrated in the same file. `digestmap_t` — Tor's existing
|
||
O(1) hash map keyed on 20-byte digests — is used correctly at lines 2689 and 2717 of
|
||
routerlist.c for adjacent operations.
|
||
|
||
// Before — O(R) per lookup, O(R²) total
|
||
smartlist_t *requested_fingerprints = smartlist_new();
|
||
smartlist_add(requested_fingerprints, tor_strdup(fp));
|
||
if (smartlist_contains_string(requested_fingerprints, fp)) // O(R)
|
||
|
||
// After — O(1) per lookup, O(R) total
|
||
digestmap_t *requested_fps = digestmap_new();
|
||
digestmap_set(requested_fps, fp, (void*)1);
|
||
if (digestmap_get(requested_fps, fp)) // O(1)
|
||
|
||
The `requested_fingerprints` smartlist is used only for membership testing in this code
|
||
path — there is no ordering requirement. The conversion is mechanical and self-contained.
|
||
|
||
--- Benchmark ---
|
||
|
||
Patch: defects/tor/patch/tor-0001-routerlist-digestset.patch
|
||
|
||
Unit tests: 5/5 pass.
|
||
At R=400 descriptors: defective=80,200 comparisons, fixed=400 comparisons — 200.5x speedup.
|
||
|
||
The full complexity proof, before/after code, and benchmark methodology are in the
|
||
attached brief (tor.pdf).
|
||
|
||
--- What We Ask ---
|
||
|
||
1. Confirm receipt within 5 business days and assign a tracker reference
|
||
(we understand Tor uses GitLab: gitlab.torproject.org).
|
||
2. Validate the patch against your CI / regression suite.
|
||
3. Assess whether this warrants a security advisory (CWE-407 — algorithmic complexity,
|
||
bootstrap latency degradation, directory authority availability impact).
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
This message is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
|
||
--- Attachment integrity ---
|
||
|
||
tor.pdf MD5: 15de40cac68482513013c5849001a685
|
||
Verify with: md5sum tor.pdf
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Solidity / Ethereum — solc-0001 + solc-0002 — Yul call graph + RJUMP 15.5x / 25.3x
|
||
|
||
**Priority:** 3
|
||
**Contact:** GitHub Security Advisory (primary): https://github.com/ethereum/solidity/security/advisories/new; fallback: bugs.ethereum.org
|
||
**Method:** GitHub Security Advisory
|
||
**Attachment:** `whitepaper/outreach/pdf/solidity.pdf` (MD5: `4f39cdc176bf70e8e674c143b85dcd56`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in Solidity compiler (solc-0001 CallGraphGenerator + solc-0002 RJUMP) — coordinated disclosure request
|
||
```
|
||
|
||
**Body (GitHub Advisory description field):**
|
||
```
|
||
## Summary
|
||
|
||
Two confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in the Solidity
|
||
compiler. Both patched. Patches ready for upstream review. One fires on every contract
|
||
compiled with `--via-ir` or `--optimize` — the standard flags for production Ethereum
|
||
deployment. The developer who introduced it left a `// TODO: This algorithm is
|
||
non-optimal.` comment in the same file acknowledging the issue.
|
||
|
||
We are requesting a 90-day coordinated disclosure window.
|
||
|
||
---
|
||
|
||
## solc-0001 — Yul call graph cycle detector (HIGH)
|
||
|
||
**File:** `libyul/optimiser/CallGraphGenerator.cpp`, line 49
|
||
|
||
```cpp
|
||
std::find(currentPath.begin(), currentPath.end(), function)
|
||
```
|
||
|
||
`currentPath` is a `std::vector<YulString>` tracking the current DFS path in the Yul
|
||
call graph cycle detector. For each function visited, the code scans the entire path to
|
||
detect cycles. Path length grows with call depth D. Over F functions: O(F × D).
|
||
|
||
In the worst case (a linear call chain), D reaches F: total O(F²).
|
||
|
||
The developer acknowledged this at line 36 of the same file:
|
||
```cpp
|
||
// TODO: This algorithm is non-optimal.
|
||
```
|
||
|
||
**Impact:** Fires on every contract compiled with `--via-ir` or `--optimize`. These are
|
||
the standard flags for:
|
||
- Production Ethereum mainnet deployment
|
||
- Every EVM-compatible chain: Polygon, BNB Chain, Avalanche, Arbitrum, Optimism, Base
|
||
- Smart contract audit toolchains (Slither, Echidna, Certora all shell out to `solc`)
|
||
- CI pipelines for every DeFi protocol and NFT platform
|
||
|
||
For a DeFi protocol with 200 internal Yul functions and call depth 50: 10,000 vector
|
||
scans per compilation. Production contracts (Uniswap v4 hooks, Aave v3, Compound v3)
|
||
compiled with `--via-ir --optimize` hit this path on every `solc` invocation.
|
||
|
||
**Fix:**
|
||
```cpp
|
||
// Before
|
||
std::vector<YulString> currentPath;
|
||
if (std::find(currentPath.begin(), currentPath.end(), function) != currentPath.end())
|
||
|
||
// After
|
||
std::vector<YulString> currentPath; // keep for backtracking order
|
||
std::unordered_set<YulString> currentPathSet; // add for O(1) membership
|
||
if (currentPathSet.count(function) > 0)
|
||
// on push: currentPath.push_back(f); currentPathSet.insert(f);
|
||
// on pop: currentPath.pop_back(); currentPathSet.erase(f);
|
||
```
|
||
|
||
**Patch:** `defects/solc/patch/solc-0001-callgraph-cyclefinder-uset.patch`
|
||
**Benchmark:** At F=D=32 — defective=15,872 comparisons, fixed=1,024 — **15.5x speedup**
|
||
|
||
---
|
||
|
||
## solc-0002 — EOF RJUMP resolution (MEDIUM)
|
||
|
||
**File:** `libevmasm/Assembly.cpp`, line 1077
|
||
|
||
```cpp
|
||
std::find(items.begin(), items.end(), ...)
|
||
```
|
||
|
||
Linear scan in EOF relative jump resolution. Fires during bytecode assembly for
|
||
contracts using the EOF container format. O(J²) where J = jump count.
|
||
|
||
**Impact:** Affects contracts using EOF (EVM Object Format), the new container format
|
||
being rolled out in upcoming Ethereum hard forks. This is the right time to fix it —
|
||
before EOF adoption scales.
|
||
|
||
**Fix:** Replace linear scan with `std::unordered_map` or `std::unordered_set` keyed on
|
||
the jump target identifier.
|
||
|
||
**Patch:** `defects/solc/patch/solc-0002-assembly-rjump-index.patch`
|
||
**Benchmark:** At J=N=100 — defective=5,050 comparisons, fixed=200 — **25.3x speedup**
|
||
|
||
---
|
||
|
||
## What We Ask
|
||
|
||
1. Confirm receipt within 5 business days and assign a GitHub issue reference
|
||
(ethereum/solidity).
|
||
2. Validate the patches against your CI / regression suite.
|
||
3. Assess severity — solc-0001 in particular has direct supply-chain reach across every
|
||
EVM chain and audit toolchain.
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
The full complexity proofs, before/after code, and benchmark methodology are in the
|
||
attached brief (solidity.pdf, MD5: 4f39cdc176bf70e8e674c143b85dcd56).
|
||
|
||
This report is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Apache Hive — hive-0001 + hive-0002 — MapReduce plan gen 50.3x
|
||
|
||
**Priority:** 4
|
||
**Contact:** security@apache.org with subject prefix `[HIVE]` (primary); fallback: https://issues.apache.org/jira/projects/HIVE (private security ticket)
|
||
**Method:** Email
|
||
**Attachment:** `whitepaper/outreach/pdf/hive.pdf` (MD5: `05a7abfaf6efc22a5f9b44fff35fdef9`)
|
||
|
||
**Subject:**
|
||
```
|
||
[HIVE] Pre-disclosure: CWE-407 in GenMRProcContext seenOps — coordinated disclosure request
|
||
```
|
||
|
||
**Body:**
|
||
```
|
||
To: security@apache.org
|
||
From: security@undefect.com
|
||
Subject: [HIVE] Pre-disclosure: CWE-407 in GenMRProcContext seenOps — coordinated disclosure request
|
||
|
||
Hello Apache Hive Security Team,
|
||
|
||
We have identified two confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in
|
||
Apache Hive's MapReduce plan generation. Patches are ready. We are requesting a 90-day
|
||
coordinated disclosure window before any public release.
|
||
|
||
--- The Defects ---
|
||
|
||
hive-0001: ql/src/java/org/apache/hadoop/hive/ql/optimizer/GenMRProcContext.java
|
||
|
||
private HashMap<Task<?>, List<Operator<? extends OperatorDesc>>> taskToSeenOps;
|
||
|
||
public boolean isSeenOp(Task task, Operator operator) {
|
||
List<Operator<?extends OperatorDesc>> seenOps = taskToSeenOps.get(task);
|
||
return seenOps != null && seenOps.contains(operator); // O(T) — ArrayList scan
|
||
}
|
||
|
||
`isSeenOp()` is called for every operator during MapReduce plan generation. For T
|
||
operators registered to a task, each new operator call scans the full list up to that
|
||
point. Total comparisons: T(T+1)/2 = O(T²) per task.
|
||
|
||
hive-0002: ql/src/java/org/apache/hadoop/hive/ql/optimizer/GenMRProcContext.java
|
||
|
||
private List<FileSinkOperator> seenFileSinkOps;
|
||
|
||
`GenMRFileSink1` calls `seenFileSinkOps.contains(fsOp)` during file sink operator
|
||
processing. Same O(n) per check pattern on an ArrayList. For F file sink operators
|
||
encountered: O(F²) total.
|
||
|
||
--- Impact ---
|
||
|
||
Both defects fire during MapReduce execution plan compilation in HiveQL query processing.
|
||
Affected deployments include:
|
||
|
||
- Any Hive installation generating MapReduce plans for multi-table queries
|
||
- Queries with many operators per task (JOINs, GROUP BYs, subqueries)
|
||
- ETL pipelines with multiple FileSink stages
|
||
- Large-scale batch queries on Hadoop clusters
|
||
|
||
The O(T²) cost in isSeenOp accumulates silently during query planning. On complex
|
||
queries with many operators per task, planning latency is materially higher than it
|
||
needs to be.
|
||
|
||
--- The Fix ---
|
||
|
||
hive-0001: Change `List<Operator<?>>` to `Set<Operator<?>>` in taskToSeenOps.
|
||
`taskToSeenOps.put(task, seenOps = new HashSet<>())`
|
||
`seenOps.contains(operator)` is now O(1).
|
||
|
||
hive-0002: Change `List<FileSinkOperator>` to `Set<FileSinkOperator>` in seenFileSinkOps.
|
||
`seenFSOps = new HashSet<FileSinkOperator>()`
|
||
`seenFSOps.contains(fsOp)` is now O(1).
|
||
|
||
Both fixes require updating the return types of `getSeenFileSinkOps()` and
|
||
`setSeenFileSinkOps()` accordingly — the patch handles this.
|
||
|
||
--- Benchmark ---
|
||
|
||
Patch: defects/hive/patch/hive-0001-0002-genmrproccontext-seenops-hashset.patch
|
||
|
||
Unit test testRatioAtScale (T=100):
|
||
defective: O(T²) comparisons — scales quadratically (verified: ratio >2.5x per doubling)
|
||
fixed: O(T) comparisons — scales linearly (verified: ratio ≈2x per doubling)
|
||
At T=100: >20x speedup confirmed. Reported field ratio: 50.3x at production query scale.
|
||
|
||
--- What We Ask ---
|
||
|
||
1. Confirm receipt within 5 business days and assign a Jira reference (HIVE project).
|
||
2. Validate the patch against your CI / regression suite.
|
||
3. Assess whether hive-0001/0002 warrants a CVE (CWE-407 — algorithmic complexity,
|
||
query planning latency degradation).
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
This message is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
|
||
--- Attachment integrity ---
|
||
|
||
hive.pdf MD5: 05a7abfaf6efc22a5f9b44fff35fdef9
|
||
Verify with: md5sum hive.pdf
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Apache Spark — spark-0001 — Analyzer window aggregates 93.4x
|
||
|
||
**Priority:** 5
|
||
**Contact:** security@apache.org with subject prefix `[SPARK]` (primary); fallback: https://issues.apache.org/jira/projects/SPARK (private security ticket)
|
||
**Method:** Email
|
||
**Attachment:** `whitepaper/outreach/pdf/spark.pdf` (MD5: `53b78a603117e72d837af479590d1740`)
|
||
|
||
**Subject:**
|
||
```
|
||
[SPARK] Pre-disclosure: CWE-407 in Analyzer seenWindowAggregates — coordinated disclosure request
|
||
```
|
||
|
||
**Body:**
|
||
```
|
||
To: security@apache.org
|
||
From: security@undefect.com
|
||
Subject: [SPARK] Pre-disclosure: CWE-407 in Analyzer seenWindowAggregates — coordinated disclosure request
|
||
|
||
Hello Apache Spark Security Team,
|
||
|
||
We have identified a confirmed CWE-407 (Inefficient Algorithmic Complexity) defect in
|
||
Apache Spark's SQL Catalyst Analyzer. A patch is ready. We are requesting a 90-day
|
||
coordinated disclosure window before any public release.
|
||
|
||
--- The Defect ---
|
||
|
||
spark-0001: sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala,
|
||
line 3283 (class Analyzer, ExtractWindowExpressions rule)
|
||
|
||
val seenWindowAggregates = new ArrayBuffer[AggregateExpression]
|
||
|
||
During window function extraction in the Catalyst Analyzer, `seenWindowAggregates` is
|
||
built as an `ArrayBuffer`. For each aggregate expression encountered during the `.map`
|
||
transform over `expressionsWithWindowFunctions`, the code calls `.contains(agg)` on this
|
||
buffer to detect duplicates.
|
||
|
||
`ArrayBuffer.contains` is a linear scan: O(W) per call, where W is the number of window
|
||
aggregates seen so far. For A aggregate expressions across W window functions:
|
||
total comparisons = O(A × W).
|
||
|
||
When A and W scale together (the common case in a query with many window functions), this
|
||
becomes O(W²) — quadratic in the number of distinct window aggregates.
|
||
|
||
--- Impact ---
|
||
|
||
Affects any Spark SQL query containing window functions with aggregates:
|
||
|
||
- `OVER (PARTITION BY ... ORDER BY ...)` with `SUM`, `COUNT`, `AVG`, `RANK`, etc.
|
||
- Analytical queries, dashboard aggregations, sessionization pipelines
|
||
- Any workload using multiple window expressions in the same query block
|
||
|
||
The Catalyst Analyzer runs on every query. For complex analytical queries with many
|
||
window aggregates — common in data warehousing and reporting workloads — the O(W²)
|
||
duplicate check adds unnecessary latency to query planning.
|
||
|
||
--- The Fix ---
|
||
|
||
Replace `ArrayBuffer[AggregateExpression]` with `mutable.LinkedHashSet[AggregateExpression]`:
|
||
|
||
// Before — O(W) per contains(), O(W²) total
|
||
val seenWindowAggregates = new ArrayBuffer[AggregateExpression]
|
||
|
||
// After — O(1) per contains(), O(W) total
|
||
// CWE-407 fix: LinkedHashSet for O(1) contains() instead of O(W) ArrayBuffer scan.
|
||
// Preserves insertion order for deterministic output; equality via AggregateExpression.equals.
|
||
val seenWindowAggregates = new mutable.LinkedHashSet[AggregateExpression]
|
||
|
||
`LinkedHashSet` preserves insertion order (ensuring deterministic query plan output) and
|
||
provides O(1) `contains()` via hashing. `AggregateExpression.equals` is already defined.
|
||
The change is a single-line substitution with no behavioral change.
|
||
|
||
--- Benchmark ---
|
||
|
||
Patch: defects/spark/patch/spark-0001-analyzer-seenwindowaggregates-linkedhashset.patch
|
||
|
||
Unit test testRatioAtScaleIsLarge (W=A=100):
|
||
defective: scales quadratically (ratio >2.5x per doubling confirmed)
|
||
fixed: exactly A comparisons regardless of W (1 per aggregate, O(1) hash lookup)
|
||
At W=A=100: >10x speedup threshold confirmed. Reported field ratio: 93.4x at
|
||
production query scale with large window aggregate counts.
|
||
|
||
--- What We Ask ---
|
||
|
||
1. Confirm receipt within 5 business days and assign a Jira reference (SPARK project).
|
||
2. Validate the patch against your CI / regression suite (ExtractWindowExpressions tests).
|
||
3. Assess whether spark-0001 warrants a CVE (CWE-407 — algorithmic complexity, query
|
||
planning latency degradation for analytical workloads).
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
This message is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
|
||
--- Attachment integrity ---
|
||
|
||
spark.pdf MD5: 53b78a603117e72d837af479590d1740
|
||
Verify with: md5sum spark.pdf
|
||
```
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## 6. Apache Kafka — kafka-0001 + kafka-0002 — StickyAssignor 300x / 50x
|
||
|
||
**Priority:** 6
|
||
**Contact:** security@apache.org with subject prefix `[KAFKA]` (primary); fallback: https://issues.apache.org/jira/projects/KAFKA
|
||
**Method:** Email
|
||
**Attachment:** `whitepaper/outreach/pdf/kafka.pdf` (MD5: `fc6179cd2c49520ec697736a11552c20`)
|
||
|
||
**Subject:**
|
||
```
|
||
[KAFKA] Pre-disclosure: CWE-407 in AbstractStickyAssignor — coordinated disclosure request
|
||
```
|
||
|
||
**Body:**
|
||
```
|
||
To: security@apache.org
|
||
From: security@undefect.com
|
||
Subject: [KAFKA] Pre-disclosure: CWE-407 in AbstractStickyAssignor — coordinated disclosure request
|
||
|
||
Hello Apache Kafka Security Team,
|
||
|
||
We have identified two confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in
|
||
Apache Kafka's sticky partition assignor. Patches are ready. We are requesting a 90-day
|
||
coordinated disclosure window before any public release.
|
||
|
||
--- The Defects ---
|
||
|
||
kafka-0001: clients/src/main/java/org/apache/kafka/clients/consumer/internals/AbstractStickyAssignor.java:1207
|
||
|
||
if (currentAssignment.get(consumer).contains(topicPartition)) { ... }
|
||
|
||
`currentAssignment.get(consumer)` returns a `List<TopicPartition>`. The `.contains()` call
|
||
performs a linear scan over previously-assigned partitions, called inside a triple-nested loop:
|
||
for each consumer C, for each topic T, for each partition P. Total cost per `isBalanced()` call:
|
||
O(C × T × P²).
|
||
|
||
kafka-0002: AbstractStickyAssignor.java:1267 and :1458
|
||
|
||
if (consumer2AllPotentialTopics.get(consumer).contains(partition.topic())) { ... }
|
||
|
||
`consumer2AllPotentialTopics` values are `List<String>`. The `.contains()` call scans T topic
|
||
strings per call, invoked P × C times: O(P × C × T). kafka-0003 (:1458) is the same field in
|
||
`reassignPartition()` — the kafka-0002 fix resolves it as a consequence.
|
||
|
||
--- Impact ---
|
||
|
||
Every Kafka consumer group rebalance hits `isBalanced()`. Sticky assignment is the default
|
||
`partition.assignment.strategy` as of Kafka 2.4+ (`CooperativeStickyAssignor`). Consumer groups
|
||
with many partitions and many consumers hit the worst case on every rebalance.
|
||
|
||
Consumer group rebalances occur at startup, on member join/leave (rolling deploy, pod restart),
|
||
on topic metadata change, and on consumer failure. In production Kafka clusters, rebalances are
|
||
frequent — this overhead runs on every one.
|
||
|
||
--- The Fix ---
|
||
|
||
kafka-0001: Snapshot to HashSet<TopicPartition> before inner loops:
|
||
|
||
// Before
|
||
if (currentAssignment.get(consumer).contains(topicPartition)) { ... }
|
||
|
||
// After — O(1) membership test
|
||
Set<TopicPartition> assignedSet = new HashSet<>(currentAssignment.get(consumer));
|
||
if (assignedSet.contains(topicPartition)) { ... }
|
||
|
||
kafka-0002/0003: Store consumer2AllPotentialTopics values as Set<String>:
|
||
|
||
// Before
|
||
private Map<String, List<String>> consumer2AllPotentialTopics;
|
||
|
||
// After — O(1) .contains()
|
||
private Map<String, Set<String>> consumer2AllPotentialTopics;
|
||
|
||
TopicPartition and String both implement equals()/hashCode() — no additional changes needed.
|
||
|
||
--- Benchmark ---
|
||
|
||
Patch: defects/kafka/patch/kafka-0001-0002-stickassignor-hashset.patch
|
||
|
||
Unit tests: 5/5 pass.
|
||
kafka-0001 at C=5, T=8, P=100: defective=1,201,000 comparisons, fixed=4,000 — 300× speedup.
|
||
kafka-0002 at T=100, P=50, C=10: defective=2,525,000, fixed=50,000 — 50× speedup.
|
||
|
||
The full complexity proof, before/after code, and benchmark methodology are in the attached
|
||
brief (kafka.pdf).
|
||
|
||
--- What We Ask ---
|
||
|
||
1. Confirm receipt within 5 business days and assign a JIRA reference (KAFKA project).
|
||
2. Validate the patch against your CI / regression suite.
|
||
3. Assess whether kafka-0001 warrants a CVE (CWE-407 — algorithmic complexity, consumer
|
||
group rebalance latency degradation).
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
This message is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
|
||
--- Attachment integrity ---
|
||
|
||
kafka.pdf MD5: fc6179cd2c49520ec697736a11552c20
|
||
Verify with: md5sum kafka.pdf
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Spring Framework — spring-0001 + spring-0002 — BeanFactory 200x
|
||
|
||
**Priority:** 7
|
||
**Contact:** GitHub Security Advisory: https://github.com/spring-projects/spring-framework/security/advisories/new
|
||
**Method:** GitHub Security Advisory
|
||
**Attachment:** `whitepaper/outreach/pdf/spring.pdf` (MD5: `d11c39095722c3f8209dcba1f262ddad`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in BeanFactoryUtils/ImportStack — coordinated disclosure request
|
||
```
|
||
|
||
**Body (GitHub Advisory description field):**
|
||
```
|
||
## Summary
|
||
|
||
Two confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in Spring Framework's
|
||
bean factory utilities and annotation configuration parser. Both patched. Patches ready for
|
||
upstream review. We are requesting a 90-day coordinated disclosure window.
|
||
|
||
---
|
||
|
||
## spring-0001 — BeanFactoryUtils.mergeNamesWithParent (HIGH)
|
||
|
||
**File:** `spring-context/src/main/java/org/springframework/context/support/BeanFactoryUtils.java:521`
|
||
|
||
```java
|
||
ArrayList<String> merged = new ArrayList<>(result.length + parentResult.length);
|
||
merged.addAll(Arrays.asList(result));
|
||
for (String beanName : parentResult) {
|
||
if (!merged.contains(beanName)) { // O(|merged|) linear scan per element
|
||
merged.add(beanName);
|
||
}
|
||
}
|
||
```
|
||
|
||
`merged.contains()` scans the full list for every element in `parentResult`. With B beans:
|
||
O(B²) total. This call is in `beanNamesForTypeIncludingAncestors()` — a Spring core API invoked
|
||
on every `@Autowired` resolution that spans a parent/child application context hierarchy.
|
||
|
||
**Impact:** Spring Boot applications with parent/child contexts (web + root context) call this
|
||
on every bean resolution across the hierarchy. Large enterprise applications with hundreds of
|
||
beans maximize B and hit worst case on every hierarchical resolution.
|
||
|
||
**Fix:**
|
||
```java
|
||
// Before — O(B²)
|
||
ArrayList<String> merged = new ArrayList<>(result.length + parentResult.length);
|
||
merged.addAll(Arrays.asList(result));
|
||
for (String beanName : parentResult) {
|
||
if (!merged.contains(beanName)) { merged.add(beanName); }
|
||
}
|
||
|
||
// After — O(B): LinkedHashSet preserves insertion order, O(1) contains()
|
||
// CWE-407 fix: LinkedHashSet for O(1) contains() and set dedup semantics.
|
||
LinkedHashSet<String> merged = new LinkedHashSet<>(Arrays.asList(result));
|
||
merged.addAll(Arrays.asList(parentResult));
|
||
```
|
||
|
||
**Patch:** `defects/spring/patch/spring-0001-0002-beanfactory-linkedhashset.patch`
|
||
**Benchmark:** At B=200 — defective=20,000 comparisons, fixed=200. **200× speedup.**
|
||
|
||
---
|
||
|
||
## spring-0002 — ConfigurationClassParser ImportStack (MEDIUM)
|
||
|
||
**File:** `spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java:422,653`
|
||
|
||
```java
|
||
private static class ImportStack extends ArrayDeque<ConfigurationClass>
|
||
implements ImportRegistry {
|
||
// ArrayDeque.contains() is O(n) — used in cycle detection:
|
||
// processMemberClasses() line 422 and isChainedImportOnStack() line 653
|
||
}
|
||
```
|
||
|
||
`ImportStack.contains()` is O(n) — called once per candidate import to detect cycles. With N
|
||
imports: O(N²) total. Affects every Spring Boot application using `@Import` chains.
|
||
|
||
**Fix:** Replace `ArrayDeque` with `LinkedHashSet`:
|
||
```java
|
||
// CWE-407 fix: LinkedHashSet for O(1) contains() with insertion-order iteration.
|
||
private static class ImportStack extends LinkedHashSet<ConfigurationClass>
|
||
```
|
||
|
||
---
|
||
|
||
## What We Ask
|
||
|
||
1. Confirm receipt within 5 business days and assign a GitHub Security Advisory reference
|
||
(spring-projects/spring-framework).
|
||
2. Validate the patches against your CI / regression suite.
|
||
3. Assess severity — spring-0001 fires on every hierarchical application context bean
|
||
resolution; spring-0002 on every @Import cycle check.
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
The full complexity proofs, before/after code, and benchmark methodology are in the attached
|
||
brief (spring.pdf, MD5: d11c39095722c3f8209dcba1f262ddad).
|
||
|
||
This report is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Presto — presto-0001 through 0004 — PushDownDereferences/PayloadJoin 100x
|
||
|
||
**Priority:** 8
|
||
**Contact:** GitHub Security Advisory: https://github.com/prestodb/presto/security/advisories/new; or GitHub issue
|
||
**Method:** GitHub Security Advisory / Issue
|
||
**Attachment:** `whitepaper/outreach/pdf/presto.pdf` (MD5: `8bcce0fe088f9b50b4dab1a48fe22daa`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in PushDownDereferences optimizer — coordinated disclosure request
|
||
```
|
||
|
||
**Body (GitHub Advisory description field):**
|
||
```
|
||
## Summary
|
||
|
||
Four confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in Presto's SQL query
|
||
optimizer. All patched. Patches ready for upstream review. Three are in `PushDownDereferences.java`
|
||
— dereference pushdown rules applied during query optimization. One is in `PayloadJoinOptimizer.java`.
|
||
We are requesting a 90-day coordinated disclosure window.
|
||
|
||
---
|
||
|
||
## presto-0001/0002/0003 — PushDownDereferences ImmutableList.contains (MEDIUM)
|
||
|
||
**Files:**
|
||
- `presto-main-base/.../iterative/rule/PushDownDereferences.java:206` (presto-0001)
|
||
- `PushDownDereferences.java:369` (presto-0002, identical pattern — second JoinNode rule)
|
||
- `PushDownDereferences.java:414` (presto-0003, SemiJoinNode rule)
|
||
|
||
```java
|
||
// joinNode.getLeft().getOutputVariables() returns ImmutableList
|
||
if (joinNode.getLeft().getOutputVariables().contains(baseVariable)) { ... }
|
||
```
|
||
|
||
`ImmutableList.contains()` is a linear scan. Called D times (once per dereference expression):
|
||
O(D × V) per rule invocation, where V = output variable count.
|
||
|
||
**Impact:** These rules run during query optimization for every query containing dereference
|
||
expressions (field access on row types, struct projections, nested column access). Complex
|
||
analytical queries with many output columns from wide row types maximize D×V. Common in data
|
||
lake workloads over Hive struct fields, nested JSON columns, Iceberg nested schemas.
|
||
|
||
**Fix:**
|
||
```java
|
||
// Before — O(V) per check
|
||
if (joinNode.getLeft().getOutputVariables().contains(baseVariable)) { ... }
|
||
|
||
// After — O(1) per check
|
||
// CWE-407 fix: snapshot to ImmutableSet before loop for O(1) contains().
|
||
Set<VariableReferenceExpression> leftOutputSet =
|
||
ImmutableSet.copyOf(joinNode.getLeft().getOutputVariables());
|
||
if (leftOutputSet.contains(baseVariable)) { ... }
|
||
```
|
||
|
||
Applied at all three sites. `VariableReferenceExpression` implements `equals()`/`hashCode()`.
|
||
|
||
---
|
||
|
||
## presto-0004 — PayloadJoinOptimizer stream filter (MEDIUM)
|
||
|
||
**File:** `presto-main-base/.../optimizations/PayloadJoinOptimizer.java:208`
|
||
|
||
```java
|
||
ImmutableSet<VariableReferenceExpression> rightJoinKeys = inputJoinKeys.stream()
|
||
.filter(key -> rightNode.getOutputVariables().contains(key)) // O(V) per key
|
||
.collect(toImmutableSet());
|
||
```
|
||
|
||
Same root cause — `getOutputVariables()` returns `ImmutableList`, O(V) per `.contains()`,
|
||
called K times per join: O(K × V).
|
||
|
||
**Fix:** Snapshot before stream:
|
||
```java
|
||
// CWE-407 fix: snapshot to ImmutableSet before stream for O(1) contains().
|
||
Set<VariableReferenceExpression> rightOutputSet =
|
||
ImmutableSet.copyOf(rightNode.getOutputVariables());
|
||
.filter(key -> rightOutputSet.contains(key))
|
||
```
|
||
|
||
---
|
||
|
||
## Benchmark
|
||
|
||
Patch: `defects/presto/patch/presto-0001-0004-pushdown-derefs-immutableset.patch`
|
||
|
||
Unit tests: 5/5 pass. At D=V=100: defective=10,000 comparisons, fixed=100. **100× speedup.**
|
||
|
||
The full complexity proofs, before/after code, and benchmark methodology are in the attached
|
||
brief (presto.pdf, MD5: 8bcce0fe088f9b50b4dab1a48fe22daa).
|
||
|
||
---
|
||
|
||
## What We Ask
|
||
|
||
1. Confirm receipt within 5 business days and assign a GitHub Security Advisory or issue
|
||
reference (prestodb/presto).
|
||
2. Validate the patches against your CI / regression suite.
|
||
3. Assess severity — presto-0001/0002/0003 fire on every query with dereference pushdown.
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
This report is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
```
|
||
|
||
---
|
||
|
||
## 9. webpack — webpack-0001/0002/0003 — HMR BFS/addAllToSet/require 100x
|
||
|
||
**Priority:** 9
|
||
**Contact:** GitHub Security Advisory: https://github.com/webpack/webpack/security/advisories/new
|
||
**Method:** GitHub Security Advisory
|
||
**Attachment:** `whitepaper/outreach/pdf/webpack.pdf` (MD5: `2058fb86c25785f883d3d4a1928e8259`)
|
||
|
||
**Subject:**
|
||
```
|
||
Pre-disclosure: CWE-407 in webpack HMR runtime — coordinated disclosure request
|
||
```
|
||
|
||
**Body (GitHub Advisory description field):**
|
||
```
|
||
## Summary
|
||
|
||
Three confirmed CWE-407 (Inefficient Algorithmic Complexity) defects in webpack's Hot Module
|
||
Replacement (HMR) runtime. All patched. Patches ready for upstream review. All three are in
|
||
the HMR runtime bundle — JavaScript shipped to and executed in the browser on every webpack
|
||
build with HMR enabled. We are requesting a 90-day coordinated disclosure window.
|
||
|
||
---
|
||
|
||
## webpack-0001 — HMR BFS outdatedModules (MEDIUM-HIGH)
|
||
|
||
**File:** `lib/hmr/JavascriptHotModuleReplacement.runtime.js:74`
|
||
|
||
```javascript
|
||
var outdatedModules = [moduleId];
|
||
// inside BFS over module dependency graph:
|
||
if (outdatedModules.indexOf(parentId) !== -1) continue; // O(M) per check
|
||
outdatedModules.push(parentId);
|
||
```
|
||
|
||
`Array.indexOf()` is O(M). Called per module per parent edge during BFS traversal. For M
|
||
affected modules: O(M²) total. Fires on every file save in webpack dev server.
|
||
|
||
**Fix:**
|
||
```javascript
|
||
// CWE-407 fix: shadow array with Set for O(1) dedup.
|
||
var outdatedModules = [];
|
||
var outdatedModulesSet = new Set([moduleId]);
|
||
outdatedModules.push(moduleId);
|
||
// Replace indexOf check:
|
||
if (outdatedModulesSet.has(parentId)) continue;
|
||
outdatedModulesSet.add(parentId);
|
||
outdatedModules.push(parentId);
|
||
```
|
||
|
||
**Benchmark:** At M=200 — defective=19,900 comparisons, fixed=200. **100× speedup.**
|
||
|
||
---
|
||
|
||
## webpack-0002 — addAllToSet helper (MEDIUM)
|
||
|
||
**File:** `JavascriptHotModuleReplacement.runtime.js:101`
|
||
|
||
```javascript
|
||
function addAllToSet(a, b) {
|
||
for (var i = 0; i < b.length; i++) {
|
||
var item = b[i];
|
||
if (a.indexOf(item) === -1) a.push(item); // O(N) per insertion
|
||
}
|
||
}
|
||
```
|
||
|
||
O(N²) across N items. Fix: companion Set alongside accumulator array:
|
||
|
||
```javascript
|
||
// CWE-407 fix: companion Set for O(1) dedup in addAllToSet.
|
||
function addAllToSet(a, b) {
|
||
if (!a._set) a._set = new Set(a);
|
||
for (var i = 0; i < b.length; i++) {
|
||
if (!a._set.has(b[i])) { a.push(b[i]); a._set.add(b[i]); }
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## webpack-0003 — Hot require() parents/children dedup (MEDIUM)
|
||
|
||
**File:** `lib/hmr/HotModuleReplacement.runtime.js:60,67`
|
||
|
||
```javascript
|
||
if (module.parents.indexOf(parentId) === -1) module.parents.push(parentId);
|
||
if (me.children.indexOf(request) === -1) me.children.push(request);
|
||
```
|
||
|
||
Every `require()` call deduplicates parents and children using `indexOf`. In a large module
|
||
graph: O(P² + C²). Fix: Set companions for parents and children arrays.
|
||
|
||
---
|
||
|
||
## Impact
|
||
|
||
webpack 5 powers millions of web applications. HMR is enabled by default in every webpack dev
|
||
server. `getAffectedModuleEffects()` executes on every file save during hot reload. Large
|
||
frontend applications (thousands of modules, monorepos, design systems) maximize M and hit
|
||
worst case on every hot reload — exactly where fast iteration is most important.
|
||
|
||
---
|
||
|
||
## What We Ask
|
||
|
||
1. Confirm receipt within 5 business days and assign a GitHub Security Advisory reference
|
||
(webpack/webpack).
|
||
2. Validate the patches against your CI / test suite.
|
||
3. Assess severity — webpack-0001 fires on every hot reload in webpack dev server.
|
||
4. Coordinate a disclosure date within the 90-day window.
|
||
|
||
Credit is optional — the goal is the fix.
|
||
|
||
The full complexity proofs, before/after code, and benchmark methodology are in the attached
|
||
brief (webpack.pdf, MD5: 2058fb86c25785f883d3d4a1928e8259).
|
||
|
||
Patch files:
|
||
- defects/webpack/patch/webpack-0001-hmr-outdated-set.patch
|
||
- defects/webpack/patch/webpack-0002-hmr-parents-children-set.patch
|
||
|
||
This report is confidential until coordinated disclosure.
|
||
|
||
— undefect.
|
||
security@undefect.com
|
||
https://undefect.com
|
||
```
|
||
|
||
---
|
||
|
||
## Pre-Send Checklist
|
||
|
||
| # | Target | PDF Ready | MD5 in Body | Contact Confirmed | Status |
|
||
|---|--------|-----------|-------------|-------------------|--------|
|
||
| 1 | FRRouting | yes — frrouting.pdf | 95f4c539... | security@frrouting.org | READY TO SEND |
|
||
| 2 | Tor Project | yes — tor.pdf | 15de40ca... | security@torproject.org | READY TO SEND |
|
||
| 3 | Solidity/Ethereum | yes — solidity.pdf | 4f39cdc1... | GitHub advisory form | READY TO SEND |
|
||
| 4 | Apache Hive | yes — hive.pdf | 05a7abfa... | security@apache.org [HIVE] | READY TO SEND |
|
||
| 5 | Apache Spark | yes — spark.pdf | 53b78a60... | security@apache.org [SPARK] | READY TO SEND |
|
||
| 6 | Apache Kafka | yes — kafka.pdf | fc6179cd... | security@apache.org [KAFKA] | READY TO SEND |
|
||
| 7 | Spring Framework | yes — spring.pdf | d11c3909... | GitHub security advisory | READY TO SEND |
|
||
| 8 | Presto | yes — presto.pdf | 8bcce0fe... | GitHub security advisory | READY TO SEND |
|
||
| 9 | webpack | yes — webpack.pdf | 2058fb86... | GitHub security advisory | READY TO SEND |
|