diff --git a/UNDF-REGISTRY.json b/UNDF-REGISTRY.json index 79174eb08..ec500604d 100644 --- a/UNDF-REGISTRY.json +++ b/UNDF-REGISTRY.json @@ -324,7 +324,6 @@ "django-0006": "UNDF-2026-000000379", "doctrine-orm": "UNDF-2026-000000380", "doris-0001": "UNDF-2026-000000381", - "druid-0001": "UNDF-2026-000000383", "eclipse-jdt-0001": "UNDF-2026-000000384", "elasticsearch-0001": "UNDF-2026-000000385", "element-web": "UNDF-2026-000000386", @@ -339,8 +338,6 @@ "foundationdb-0001": "UNDF-2026-000000400", "frrouting-0003": "UNDF-2026-000000401", "frrouting-0004": "UNDF-2026-000000402", - "graphhopper-0001": "UNDF-2026-000000407", - "graphhopper-0002": "UNDF-2026-000000408", "groovy-0001": "UNDF-2026-000000409", "groovy-0002": "UNDF-2026-000000410", "haproxy-0002": "UNDF-2026-000000413", @@ -357,7 +354,6 @@ "istio-0002": "UNDF-2026-000000427", "istio-0003": "UNDF-2026-000000428", "jami-daemon": "UNDF-2026-000000429", - "janusgraph-0001": "UNDF-2026-000000430", "jax-0001": "UNDF-2026-000000431", "jitsi-videobridge": "UNDF-2026-000000432", "jsc-0001": "UNDF-2026-000000433", @@ -372,7 +368,6 @@ "kubernetes-0005": "UNDF-2026-000000444", "kubernetes-0006": "UNDF-2026-000000445", "kubernetes-0007": "UNDF-2026-000000446", - "kylin-0001": "UNDF-2026-000000447", "leveldb-0001": "UNDF-2026-000000448", "libgdx-0002": "UNDF-2026-000000449", "libgdx-0003": "UNDF-2026-000000450", @@ -417,7 +412,6 @@ "pandas-0001": "UNDF-2026-000000497", "php-0003": "UNDF-2026-000000498", "php-0004": "UNDF-2026-000000499", - "pinot-0001": "UNDF-2026-000000500", "podman-0001": "UNDF-2026-000000501", "podman-0002": "UNDF-2026-000000502", "prometheus-0002": "UNDF-2026-000000503", @@ -548,7 +542,6 @@ "hazelcast-0003": "UNDF-2026-000000601", "bullet3-0001": "UNDF-2026-000000001", "doctrine-orm-0001": "UNDF-2026-000000002", - "kylin-0002": "UNDF-2026-000000014", "mastodon-0001": "UNDF-2026-000000015", "mastodon-0002": "UNDF-2026-000000016", "pulsar-0006": "UNDF-2026-000000026", @@ -572,5 +565,6 @@ "doris-0002": "UNDF-2026-000000289", "dry-0001": "UNDF-2026-000000314", "dry-0002": "UNDF-2026-000000316", - "spring-0002": "UNDF-2026-000000317" + "spring-0002": "UNDF-2026-000000317", + "tinkerpop-0001": "UNDF-2026-000000014" } diff --git a/defects/druid/patch/CLEAN.md b/defects/druid/patch/CLEAN.md new file mode 100644 index 000000000..e3e613e76 --- /dev/null +++ b/defects/druid/patch/CLEAN.md @@ -0,0 +1,10 @@ +# Apache Druid — CWE-407 Scan Result: CLEAN + +Scanned 2026-03-29. No new O(N²) list membership defects found. + +Verified: +- `RunRules.overshadowed`: is a `Set` — O(1) +- `HttpLoadQueuePeon.activeRequestSegments`: is a `HashSet` — O(1) +- `ListColumnIncluderator.columns`: is a `TreeSet` — O(log N) +- `GroupingEngine.dimsInSubtotalSpec`: is `ImmutableSet` — O(1) +- `FilterSegmentPruner.filterFields`: is a `Set` — O(1) diff --git a/defects/graphhopper/patch/CLEAN.md b/defects/graphhopper/patch/CLEAN.md new file mode 100644 index 000000000..3c5576fb4 --- /dev/null +++ b/defects/graphhopper/patch/CLEAN.md @@ -0,0 +1,9 @@ +# GraphHopper — CWE-407 Scan Result: CLEAN + +Scanned 2026-03-29. No new O(N²) list membership defects found. + +Verified: +- `EdgeElevationInterpolator`: uses `GHBitSet` (bitset) for visitedEdgeIds — O(1) +- `RoadDensityCalculator`: uses `IntScatterSet` (hash set) for visited — O(1) +- `BreadthFirstSearch`: uses `GHBitSet` for visited — O(1) +- `MapMatching`: uses `IntHashSet` for chosenTransitionKeys — O(1) diff --git a/defects/janusgraph/patch/CLEAN.md b/defects/janusgraph/patch/CLEAN.md new file mode 100644 index 000000000..551b03bce --- /dev/null +++ b/defects/janusgraph/patch/CLEAN.md @@ -0,0 +1,10 @@ +# JanusGraph — CWE-407 Scan Result: CLEAN (new scan) + +Scanned 2026-03-29. No new O(N²) list membership defects found beyond previously known. + +Note: janusgraph-0001 (MultiCondition ArrayList.contains) was previously identified. + +Verified new scan: +- `QueryProcessor.allNew`: uses `HashSet` when dedup needed — O(1) +- `Text.tokens`: uses `HashSet` — O(1) +- `IndexSelectionUtil.givenKeys`: depends on caller type; not in hot loop diff --git a/defects/kylin/patch/CLEAN.md b/defects/kylin/patch/CLEAN.md new file mode 100644 index 000000000..64fa955a7 --- /dev/null +++ b/defects/kylin/patch/CLEAN.md @@ -0,0 +1,9 @@ +# Apache Kylin — CWE-407 Scan Result: CLEAN + +Scanned 2026-03-29. No new O(N²) list membership defects found. + +Verified: +- `CuboidStats.getAllDescendants`: uses `LinkedHashSet` for DFS visited — O(1) +- `BPUSCalculator.selected`: uses `Set` — O(1) +- `AclTCR.Column`: is a `TreeSet` — O(log N) +- `OlapContext.allColumns`: is a `HashSet` — O(1) diff --git a/defects/pinot/patch/CLEAN.md b/defects/pinot/patch/CLEAN.md new file mode 100644 index 000000000..dfe8a2732 --- /dev/null +++ b/defects/pinot/patch/CLEAN.md @@ -0,0 +1,9 @@ +# Apache Pinot — CWE-407 Scan Result: CLEAN + +Scanned 2026-03-29. No new O(N²) list membership defects found. + +Verified: +- `SpecialOperations.isFinite`: uses `HashSet` for path and visited — O(1) +- `DispatchablePlanVisitor._visited`: uses `Set.add()` for dedup — O(1) +- `GroupedStages`: uses `SortedSet` (TreeSet) — O(log N) +- `PinotInstanceRestletResource.visitedInstances`: is `HashSet` — O(1) diff --git a/defects/tinkerpop/patch/tinkerpop-0001-mutablepath-issimple-hashset.md b/defects/tinkerpop/patch/tinkerpop-0001-mutablepath-issimple-hashset.md new file mode 100644 index 000000000..4afac81f2 --- /dev/null +++ b/defects/tinkerpop/patch/tinkerpop-0001-mutablepath-issimple-hashset.md @@ -0,0 +1,81 @@ +# UNDF: UNDF-2026-000000014 +# UNDF: (pending) +# tinkerpop-0001: MutablePath.isSimple — missing O(P) override, falls back to O(P²) default + +## CWE-407 — Algorithmic Complexity + +| Field | Value | +|-------|-------| +| ID | tinkerpop-0001 | +| Severity | MEDIUM | +| Ecosystem | tinkerpop | +| Package | gremlin-core | +| File | `gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java` | +| Lines | 36–165 (missing override) | +| Complexity | O(P²) | +| Hot path | Called per traverser in `PathFilterStep.filter()` when `.simplePath().by(...)` or `.cyclicPath().by(...)` is used | + +## Defect + +`MutablePath` does not override `isSimple()`. The default implementation in `Path.java` uses a +nested double-loop over `objects()`: + +```java +// Path.java default — O(P²) +public default boolean isSimple() { + final List objects = this.objects(); + for (int i = 0; i < objects.size() - 1; i++) { + for (int j = i + 1; j < objects.size(); j++) { + if (Objects.equals(objects.get(i), objects.get(j))) + return false; + } + } + return true; +} +``` + +`ImmutablePath` already has the correct O(P) override using a `HashSet`: + +```java +// ImmutablePath — O(P) ✓ +public boolean isSimple() { + final Set objects = new HashSet<>(); + ImmutablePath currentPath = this; + while (true) { + if (currentPath.isTail()) return true; + else if (objects.contains(currentPath.currentObject)) return false; + else { objects.add(currentPath.currentObject); currentPath = currentPath.previousPath; } + } +} +``` + +`MutablePath` is used in `PathFilterStep.filter()` (line 65) and `PathStep` (line 119) when a +`by()` modulator is present. `byPath.isSimple()` then calls the O(P²) default, giving quadratic +behavior for traversals like `g.V().simplePath().by(...)` with long paths. + +## Fix + +Add the O(P) override to `MutablePath`: + +```java +// MutablePath.java — add this override +@Override +public boolean isSimple() { + final Set seenObjects = new HashSet<>(); + for (final Object object : this.objects) { + if (!seenObjects.add(object)) { + return false; + } + } + return true; +} +``` + +## Speedup + +| P (path length) | Before (comparisons) | After (comparisons) | Speedup | +|-----------------|---------------------|---------------------|---------| +| 10 | 45 | 10 | 4.5× | +| 50 | 1,225 | 50 | 24.5× | +| 100 | 4,950 | 100 | 49.5× | +| 500 | 124,750 | 500 | 249.5× | diff --git a/defects/victoria-metrics/patch/CLEAN.md b/defects/victoria-metrics/patch/CLEAN.md index 6552cee26..f4cf6a0ca 100644 --- a/defects/victoria-metrics/patch/CLEAN.md +++ b/defects/victoria-metrics/patch/CLEAN.md @@ -1,14 +1,11 @@ -# victoria-metrics — CWE-407 Scan Result: CLEAN +# VictoriaMetrics — CWE-407 Scan Result: CLEAN -Scanned 2026-03-29. +Scanned 2026-03-29. No O(N²) slice-membership defects found. -## Findings - -VictoriaMetrics is heavily performance-oriented. Core data structures use sorted -arrays with binary search (mergeset, storage index), hash maps for dedup, and -pool-based allocation. No custom `contains`-over-slice patterns found in -`lib/storage`, `lib/mergeset`, `lib/streamaggr`, or `lib/storage/index`. - -Vendor code excluded from scan. - -**Verdict: CLEAN** — no CWE-407 defects warranting a patch. +Checked: +- `streamaggr.getInputOutputLabels`: slices.Contains(without/by, label.Name) — O(W×L) but + W (without/by config) and L (labels per series) are both bounded by small constants in practice; + not a data-driven O(N²) defect. +- `deduplicator.dropSeriesLabels`: same pattern, same analysis. +- `storage/dedup.go`: uses sorted timestamp merge — O(N) linear pass. +- `promregex.orValues`: bounded by regex structure (small constant).