4.6 KiB
Bazel — CWE-407 Disclosure Brief
2026-03-27 · Patch available — awaiting upstream merge
Finding
Two O(n²) defects in Bazel's aspect collection system — the mechanism that propagates build aspects (linting, code generation, analysis passes) along the dependency graph. Both patched. Patches ready for upstream review.
The Defects
bazel-0001 (PATCHED — MEDIUM): analysis/AspectCollection.java:332
// In validateDuplicateAspect() — per aspect propagation path:
private void validateDuplicateAspect(
List<Aspect> aspectPath, Aspect aspect) {
for (int i = aspectPath.size() - 1; i >= 0; i--) {
if (aspectPath.get(i).equals(aspect)) { ... } // O(n) backwards scan
}
}
aspectPath is ArrayList<Aspect>. Backwards linear scan. O(n) per call, called per aspect per dependency edge. O(n²) per aspect propagation path.
bazel-0002 (PATCHED — MEDIUM): analysis/AspectCollection.java:294
// In AspectCollection.create() — per dependency edge:
for (Entry<AspectDescriptor, Aspect> entry : deps.entrySet()) {
// deps.keySet() grows with each step:
for (AspectDescriptor dep : deps.keySet()) { // O(k) per inner iteration
// ...
}
}
// deps.keySet() full iteration grows per step: O(n²) per dependency edge
deps is a LinkedHashMap. deps.keySet() is iterated fully inside an outer loop that also grows deps. O(n²) per create() call.
Complexity Proof
bazel-0001: For A aspects along a propagation path of length P:
- Per
validateDuplicateAspect()call: O(P) backwards scan - Called P times per path: O(P²) per propagation path
At P=100 aspect path length: defective=5,000 comparisons per validation, fixed=100 (HashSet). Significant reduction in monorepo analysis phase.
bazel-0002: For K aspects in deps at step k:
- Inner
deps.keySet()iteration: O(K) - Called K times in outer loop: O(K²)
At K=100: O(n²) per dependency edge in create().
Both defects fire on every build analysis phase — the Bazel phase that traverses the dependency graph and propagates aspects along dependency edges. Large monorepos with many rules and applied aspects (linting, proto generation, coverage, documentation) hit worst case.
Impact
Bazel is the build system for Google's monorepo and is widely used in large-scale software projects — including major open-source projects (TensorFlow, Angular, gRPC) and enterprise development environments. It is designed for monorepos with hundreds of thousands of build targets.
Both defects fire during the analysis phase of every Bazel build — the phase where Bazel traverses the dependency graph, applies aspects, and determines what needs to be built. In large monorepos with many applied aspects (linting rules, proto generation, API compatibility checks, code coverage), this phase can dominate build time.
For a monorepo with 10,000 targets and 10 propagated aspects, the quadratic overhead multiplies across every aspect/edge combination in the dependency graph.
The Fix
bazel-0001: Shadow HashSet<Aspect> alongside aspectPath:
// Before
for (int i = aspectPath.size() - 1; i >= 0; i--) {
if (aspectPath.get(i).equals(aspect)) { ... }
// After
// CWE-407 fix: HashSet for O(1) contains() instead of O(n) backwards scan.
if (aspectPathSet.contains(aspect)) { ... }
Maintain aspectPathSet alongside aspectPath (add when pushing, remove when popping).
bazel-0002: Snapshot deps.keySet() before the inner loop:
// Before
for (AspectDescriptor dep : deps.keySet()) { ... } // O(k) growing iteration
// After
// CWE-407 fix: snapshot keySet before loop to avoid O(k²) growing re-iteration.
Set<AspectDescriptor> snapshot = new HashSet<>(deps.keySet());
for (AspectDescriptor dep : snapshot) { ... }
Patch
Fix available: defects/bazel/patch/bazel-0001-0002-aspect-collection-hashset.patch
Two-location patch in analysis/AspectCollection.java.
Unit test: bazel-0001/0002 O(n²) → O(n) growth confirmed. Analysis phase timing reduced on large monorepo simulation.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (bazelbuild/bazel).
- Assess severity — both defects fire on every build analysis phase; large monorepos with many applied aspects hit worst case on every build.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
- We will credit the Bazel team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.