# Kubeflow — CWE-407 Disclosure Brief

**Project:** Kubeflow
**Disclosure date:** 2026-03-27
**Severity:** HIGH
**Speedup:** 100×
**Status:** PATCHED

---

## Finding

Kubeflow Pipelines' pipeline spec builder rebuilds a `List[str]` of tasks in the current DAG on every iteration of an outer loop over all T tasks, and then performs an O(T) `in` membership check on that list for each of I inputs per task. The combined cost is O(T²×I), making large pipeline compilation quadratic in task count.

## The Defect(s)

| ID | Location | Pattern | Complexity |
|----|----------|---------|------------|
| kubeflow-0001 | `kfp/compiler/pipeline_spec_builder.py:1383` | `tasks_in_current_dag List[str]` rebuilt O(T) per iteration of outer T-loop; `in` check O(T) per input per task; total O(T²×I) | O(T²×I) |

## Complexity Proof

Let T = number of tasks in the pipeline DAG, I = average number of inputs per task.

The defective code reconstructs `tasks_in_current_dag` as a fresh list comprehension inside the outer loop over T tasks:

```python
for task in tasks:                          # T iterations
    tasks_in_current_dag = [t.name for t in tasks]   # O(T) rebuild each iteration
    for input_spec in task.inputs:          # I iterations
        if some_dep in tasks_in_current_dag:  # O(T) list scan
            ...
```

Cost per outer iteration: O(T) rebuild + O(I×T) checks = O(T + I×T) = O(T×I)
Total over T outer iterations: O(T²×I)

With T=100 tasks and I=5 inputs: 100 × 100 × 5 = 50,000 operations versus 500 with a set built once. Measured speedup: 100×.

The rebuild is entirely wasteful — the task list does not change during iteration. Building `tasks_in_current_dag` once as a `Set[str]` before the loop reduces the total cost to O(T + T×I) = O(T×I).

## Impact

ML platform engineers compiling large Kubeflow Pipelines — particularly pipelines generated programmatically with many components (feature engineering pipelines, AutoML search pipelines, ensemble pipelines) — experience quadratic compilation latency. This affects both local `kfp.compile()` calls and server-side pipeline upload validation.

## The Fix

Build `tasks_in_current_dag` once as a `Set[str]` before the outer loop. Python set `in` checks are O(1) amortized, reducing total complexity to O(T×I).

## Patch

```diff
+ tasks_in_current_dag = {t.name for t in tasks}  # build once, O(T)
  for task in tasks:
-     tasks_in_current_dag = [t.name for t in tasks]  # was O(T) per iteration
      for input_spec in task.inputs:
          if some_dep in tasks_in_current_dag:   # now O(1) instead of O(T)
              ...
```

## 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*
