From ac82cff86585a2773116419d68f0a4b8e28c476c Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sun, 29 Mar 2026 19:51:31 -0400 Subject: [PATCH] =?UTF-8?q?php-cluster:=20doctrine-orm-0001=20+=20composer?= =?UTF-8?q?-0003=20CWE-407=20defects;=20count=20668=E2=86=92670?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit doctrine-orm-0001: ClassMetadata::addSubClass in_array O(S²) subclasses list HIGH - src/Mapping/ClassMetadata.php addSubClass() scans plain $subClasses list - addSubClasses($parent->subClasses) called in doLoadMetadata: O(S²) per class - Fix: parallel $subClassesSet hash for O(1) membership; 500x at S=1000 composer-0003: InstalledRepository::getDependents in_array O(P²) needles list MEDIUM - needles array grows during foreach($packages) loop, in_array scan 3 sites - $packagesFoundSet already exists for cycle-detection but needles is separate - Fix: add $needlesSet = array_fill_keys($needles, true), mirror growth; 1000x at P=1000 cayley: CLEAN (confirmed -- map-based seen/pathMap throughout) tinkerpop: CLEAN (confirmed -- existing CLEAN.md valid, sort ArrayList is query-plan-time only) --- defects/actix-web/patch/CLEAN.md | 12 ++ defects/allegro5/patch/allegro5-0001.patch | 2 +- defects/axum/patch/CLEAN.md | 12 ++ defects/bevy/patch/CLEAN.md | 19 +++ ...-mini-miner-delete-ancestor-linear-scan.md | 2 +- .../patch/ceph-0001-osdmap-underfull-set.md | 2 +- .../ceph-0001-osdmap-underfull-set.patch | 2 +- ...ser-0003-installed-repo-needles-inarray.md | 76 +++++++++ defects/diesel/patch/CLEAN.md | 12 ++ ...ctrine-orm-0001-subclasses-list-inarray.md | 93 +++++++++++ ...agonfly-0001-missing-migrations-hashset.md | 2 +- defects/nmap/patch/nmap-0001.patch | 2 +- ...rm-0001-rbac-role-hierarchy-diamond-bfs.md | 147 ++++++++++++++++++ defects/tokio/patch/CLEAN.md | 11 ++ defects/tonic/patch/CLEAN.md | 12 ++ .../patch/tor-0001-routerlist-digestset.patch | 2 +- .../tor-0002-nodelist-family-id-strmap.patch | 2 +- .../tor-0003-kist-readd-heap-idx-o1.patch | 2 +- defects/wasmer/patch/CLEAN.md | 12 ++ defects/wasmtime/patch/CLEAN.md | 12 ++ 20 files changed, 427 insertions(+), 9 deletions(-) create mode 100644 defects/actix-web/patch/CLEAN.md create mode 100644 defects/axum/patch/CLEAN.md create mode 100644 defects/bevy/patch/CLEAN.md create mode 100644 defects/composer/patch/composer-0003-installed-repo-needles-inarray.md create mode 100644 defects/diesel/patch/CLEAN.md create mode 100644 defects/doctrine-orm/patch/doctrine-orm-0001-subclasses-list-inarray.md create mode 100644 defects/sea-orm/patch/sea-orm-0001-rbac-role-hierarchy-diamond-bfs.md create mode 100644 defects/tokio/patch/CLEAN.md create mode 100644 defects/tonic/patch/CLEAN.md create mode 100644 defects/wasmer/patch/CLEAN.md create mode 100644 defects/wasmtime/patch/CLEAN.md diff --git a/defects/actix-web/patch/CLEAN.md b/defects/actix-web/patch/CLEAN.md new file mode 100644 index 000000000..ed966936b --- /dev/null +++ b/defects/actix-web/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — actix-web + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `actix-web/src/middleware/logger.rs` — `exclude` is `HashSet`: O(1) per-request lookup. CLEAN. +- `actix-web/src/http/header/accept_encoding.rs` — `supported_set` collected as `HashSet<&Encoding>` before iteration. CLEAN. +- `actix-web/src/introspection.rs` — `update_unique` uses `Vec::contains()` for HTTP methods/guards/patterns, but these lists are bounded to <10 items each and only called once at app startup (route registration), not per request. Not actionable. +- All other `contains()` calls use bitflags, ranges, or string substring checks — not collection membership. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/allegro5/patch/allegro5-0001.patch b/defects/allegro5/patch/allegro5-0001.patch index f4ed22644..7c168f497 100644 --- a/defects/allegro5/patch/allegro5-0001.patch +++ b/defects/allegro5/patch/allegro5-0001.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000002 +# UNDF: UNDF-2026-000000011 --- a/addons/audio/kcm_sample.c +++ b/addons/audio/kcm_sample.c @@ -38,6 +38,8 @@ typedef struct { diff --git a/defects/axum/patch/CLEAN.md b/defects/axum/patch/CLEAN.md new file mode 100644 index 000000000..07ab30dcc --- /dev/null +++ b/defects/axum/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — axum + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `axum/src/extract/ws.rs` — `sec_websocket_protocol: BTreeSet`. CLEAN. +- `axum/src/routing/method_filter.rs` — `MethodFilter` is a `u16` bitfield; `.contains()` is a bitwise AND. CLEAN. +- `axum/src/routing/method_routing.rs` — `endpoint_filter` is `MethodFilter` bitfield. CLEAN. +- All other `contains()` calls are substring checks on strings. CLEAN. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/bevy/patch/CLEAN.md b/defects/bevy/patch/CLEAN.md new file mode 100644 index 000000000..204bb26ab --- /dev/null +++ b/defects/bevy/patch/CLEAN.md @@ -0,0 +1,19 @@ +# CLEAN — bevy + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `bevy_ecs/src/schedule/graph/graph_map.rs` — cycle detection uses `HashSet` for `blocked` and `maybe_in_more_cycles`. CLEAN. +- `bevy_ecs/src/schedule/graph/dag.rs` — transitive reduction uses `FixedBitSet` for `visited`. CLEAN. +- `bevy_ecs/src/schedule/auto_insert_apply_deferred.rs` — `no_sync_edges` is `BTreeSet`. CLEAN. +- `bevy_ecs/src/schedule/node.rs` — `ambiguous_with_all: &HashSet`, `ignored_ambiguities: &BTreeSet`. CLEAN. +- `bevy_gltf/src/loader/gltf_ext/scene.rs` — uses `FixedBitSet` and `HashSet` for visited tracking. CLEAN. +- `bevy_ui/src/stack.rs` — `visited_root_nodes: Local>`. CLEAN. +- `bevy_picking/src/hover.rs` — `hover_ancestors: EntityHashSet`. CLEAN. +- `bevy_render/src/view/window/screenshot.rs` — `seen_targets: Local>`. CLEAN. +- `bevy_pbr/src/render/light.rs` — `all_cascades_seen: HashSet`. CLEAN. +- `bevy_ecs/src/bundle/info.rs` — `explicit_component_ids: IndexSet<_, FixedHasher>`. CLEAN. +- `bevy_ecs/src/world/entity_access/world_mut.rs` — `contributed_components()` slice `.contains()` called during archetype migration (not per-frame hot path), N bounded to component count per entity. Not actionable. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/bitcoin/patch/bitcoin-0001-mini-miner-delete-ancestor-linear-scan.md b/defects/bitcoin/patch/bitcoin-0001-mini-miner-delete-ancestor-linear-scan.md index 20b3b49e1..9b643be57 100644 --- a/defects/bitcoin/patch/bitcoin-0001-mini-miner-delete-ancestor-linear-scan.md +++ b/defects/bitcoin/patch/bitcoin-0001-mini-miner-delete-ancestor-linear-scan.md @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000357 +# UNDF: UNDF-2026-000000043 # bitcoin-0001: MiniMiner DeleteAncestorPackage O(A×E) std::find in Outer Loop ## Classification diff --git a/defects/ceph/patch/ceph-0001-osdmap-underfull-set.md b/defects/ceph/patch/ceph-0001-osdmap-underfull-set.md index 0216c2b0b..3e4d05ade 100644 --- a/defects/ceph/patch/ceph-0001-osdmap-underfull-set.md +++ b/defects/ceph/patch/ceph-0001-osdmap-underfull-set.md @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000026 +# UNDF: UNDF-2026-000000044 # ceph-0001 — `OSDMap::calc_pg_upmaps`: O(N×U) `std::find` on `underfull` vector inside OSD scan loop ## Status diff --git a/defects/ceph/patch/ceph-0001-osdmap-underfull-set.patch b/defects/ceph/patch/ceph-0001-osdmap-underfull-set.patch index 37a84765d..94a5dc59f 100644 --- a/defects/ceph/patch/ceph-0001-osdmap-underfull-set.patch +++ b/defects/ceph/patch/ceph-0001-osdmap-underfull-set.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000026 +# UNDF: UNDF-2026-000000044 diff --git a/src/osd/OSDMap.cc b/src/osd/OSDMap.cc --- a/src/osd/OSDMap.cc +++ b/src/osd/OSDMap.cc diff --git a/defects/composer/patch/composer-0003-installed-repo-needles-inarray.md b/defects/composer/patch/composer-0003-installed-repo-needles-inarray.md new file mode 100644 index 000000000..215cdac14 --- /dev/null +++ b/defects/composer/patch/composer-0003-installed-repo-needles-inarray.md @@ -0,0 +1,76 @@ +# UNDF: UNDF-2026-000000045 +# UNDF: (pending) +# composer-0003: InstalledRepository::getDependents — O(P²) in_array on growing needles list + +## CWE-407 — Algorithmic Complexity + +| Field | Value | +|-------|-------| +| ID | composer-0003 | +| Severity | MEDIUM | +| Ecosystem | composer | +| Package | composer/composer | +| File | `src/Composer/Repository/InstalledRepository.php` | +| Lines | 177, 190, 201 | +| Complexity | O(P·N) → O(P²) where P = installed packages, N = needles (grows during loop) | +| Hot path | `composer why` / `composer why-not` — invoked for every dependency resolution query | + +## Defect + +```php +// BEFORE — O(P²): in_array($x, $needles) is O(N) inside foreach($this->getPackages()) O(P). +// $needles starts as the query needle set but GROWS during the loop (line 144): +// $needles[] = $link->getTarget(); +// So at iteration i, len($needles) can be up to i, making total cost O(P²). + +// Note: $packagesFoundSet already provides O(1) cycle-detection, but $needles is a +// separate plain PHP array with no hash index. + +foreach ($this->getPackages() as $package) { + // ... + if ($invert && in_array($package->getName(), $needles, true)) { // O(N) scan, line 177 + // ... + } + foreach ($package->getConflicts() as $link) { + if (in_array($link->getTarget(), $needles, true)) { // O(N) scan, line 190 + // ... + } + } + if ($invert && $constraint && in_array($package->getName(), $needles, true) ...) { // O(N) scan, line 201 + // ... + } +} +``` + +## Fix + +```php +// AFTER — O(1) lookup: build a parallel $needlesSet hash alongside $needles. +// Update $needlesSet whenever $needles grows. + +$needles = array_map('strtolower', (array) $needle); +$needlesSet = array_fill_keys($needles, true); // O(1) lookup companion + +// ... +// Where needles grows (line 144), mirror the addition: +$needles[] = $link->getTarget(); +$needlesSet[$link->getTarget()] = true; // O(1) insert + +// Replace all three in_array() calls: +if ($invert && isset($needlesSet[$package->getName()])) { // O(1) — was line 177 +if (isset($needlesSet[$link->getTarget()])) { // O(1) — was line 190 +if ($invert && $constraint && isset($needlesSet[$package->getName()])) { // O(1) — was line 201 +``` + +## Speedup + +| P (packages) | Before (ops) | After (ops) | Speedup | +|--------------|-------------|-------------|---------| +| 50 | 2,500 | 50 | 50× | +| 100 | 10,000 | 100 | 100× | +| 500 | 250,000 | 500 | 500× | +| 1,000 | 1,000,000 | 1,000 | 1,000× | + +A large monorepo with 500 installed packages incurs 250,000 membership scans on +`composer why` (invert mode) instead of 500. This command is run frequently during +debugging and CI dependency audits. diff --git a/defects/diesel/patch/CLEAN.md b/defects/diesel/patch/CLEAN.md new file mode 100644 index 000000000..5155d074a --- /dev/null +++ b/defects/diesel/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — diesel + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `diesel_derives/src/sql_function.rs` — `arguments_with_generic_types` and `variadic_generic_indexes` are `Vec` with `.contains()` in proc-macro code, run once at compile time with N bounded to function argument count. Not a runtime defect. +- `diesel_cli/src/infer_schema_internals/foreign_keys.rs` — `safe_tables: &[TableName]` with `.contains()`: called during `diesel print-schema` CLI execution (once per run). Not a runtime hot path. +- `diesel_cli/src/print_schema.rs` — BFS graph traversal uses `BTreeSet` for `visited`. CLEAN. +- All other `contains()` calls are on `HashSet`/`BTreeSet` or string substring checks. CLEAN. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/doctrine-orm/patch/doctrine-orm-0001-subclasses-list-inarray.md b/defects/doctrine-orm/patch/doctrine-orm-0001-subclasses-list-inarray.md new file mode 100644 index 000000000..346300159 --- /dev/null +++ b/defects/doctrine-orm/patch/doctrine-orm-0001-subclasses-list-inarray.md @@ -0,0 +1,93 @@ +# UNDF: UNDF-2026-000000002 +# UNDF: (pending) +# doctrine-orm-0001: ClassMetadata::addSubClass — O(N²) in_array on subClasses list + +## CWE-407 — Algorithmic Complexity + +| Field | Value | +|-------|-------| +| ID | doctrine-orm-0001 | +| Severity | HIGH | +| Ecosystem | doctrine-orm | +| Package | doctrine/orm | +| File | `src/Mapping/ClassMetadata.php` | +| Lines | 2308–2315 | +| Complexity | O(S²) per hierarchy, O(N·S²) total metadata load | +| Hot path | EntityManager::getMetadataFactory()->getMetadataFor() — called on every entity operation | + +## Defect + +```php +// BEFORE — O(S²): in_array() is O(S) inside addSubClasses() which iterates S entries +// Called from ClassMetadataFactory::doLoadMetadata() during metadata bootstrap. +// addSubClasses($parent->subClasses) copies parent's S subclasses into child, each +// call doing an O(S) scan, yielding O(S²) per class and O(N·S²) across N entities. + +public function addSubClass(string $className): void +{ + if (is_subclass_of($className, $this->name) && ! in_array($className, $this->subClasses, true)) { + $this->subClasses[] = $className; // O(S) scan each insertion + } +} +``` + +Called from `ClassMetadataFactory::doLoadMetadata` (line 152): + +```php +$class->addSubClasses($parent->subClasses); // iterates S entries × O(S) each = O(S²) +``` + +And from the parent-class scan loop (line 386): + +```php +foreach ($parentClasses as $parentClass) { + $rootEntityClass->addSubClass($parentClass); // O(S) scan per parent +} +``` + +`subClasses` is declared as a plain `list` with no parallel hash index: + +```php +// src/Mapping/ClassMetadata.php line 314 +public array $subClasses = []; +``` + +## Fix + +```php +// AFTER — O(1) lookup: maintain a parallel hash-keyed set alongside the list. +// The list is kept for ordered serialization/BC; the set provides O(1) membership. + +// Add alongside $subClasses (line ~314): +/** @phpstan-var array */ +public array $subClassesSet = []; + +public function addSubClass(string $className): void +{ + if (is_subclass_of($className, $this->name) && !isset($this->subClassesSet[$className])) { + $this->subClassesSet[$className] = true; // O(1) hash insert + $this->subClasses[] = $className; // preserve ordered list for BC + } +} +``` + +`$subClassesSet` must also be hydrated on deserialization (in `__wakeup` / `__clone`): + +```php +// Rebuild set after deserialization: +$this->subClassesSet = array_fill_keys($this->subClasses, true); +``` + +## Speedup + +| S (subclasses) | Before (ops) | After (ops) | Speedup | +|----------------|-------------|-------------|---------| +| 50 | 1,275 | 50 | 25× | +| 100 | 5,050 | 100 | 50× | +| 500 | 125,250 | 500 | 250× | +| 1,000 | 500,500 | 1,000 | 500× | + +A Doctrine application with a 100-subclass STI (Single-Table Inheritance) hierarchy +pays 5,050 membership scans on every cold metadata bootstrap instead of 100. +With warm OPcache this runs once per process, but in serverless / high-churn deployments +it hits on every cold start. diff --git a/defects/dragonfly/patch/dragonfly-0001-missing-migrations-hashset.md b/defects/dragonfly/patch/dragonfly-0001-missing-migrations-hashset.md index 426857d50..acd54588b 100644 --- a/defects/dragonfly/patch/dragonfly-0001-missing-migrations-hashset.md +++ b/defects/dragonfly/patch/dragonfly-0001-missing-migrations-hashset.md @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000382 +# UNDF: UNDF-2026-000000104 # dragonfly-0001: GetMissingMigrations O(M²) std::find → O(M log M) set_difference ## Classification diff --git a/defects/nmap/patch/nmap-0001.patch b/defects/nmap/patch/nmap-0001.patch index dabc6782f..cbb15f47e 100644 --- a/defects/nmap/patch/nmap-0001.patch +++ b/defects/nmap/patch/nmap-0001.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000187 +# UNDF: UNDF-2026-000000105 --- a/service_scan.h +++ b/service_scan.h @@ -280,8 +280,8 @@ class ServiceProbe { diff --git a/defects/sea-orm/patch/sea-orm-0001-rbac-role-hierarchy-diamond-bfs.md b/defects/sea-orm/patch/sea-orm-0001-rbac-role-hierarchy-diamond-bfs.md new file mode 100644 index 000000000..ac26efa88 --- /dev/null +++ b/defects/sea-orm/patch/sea-orm-0001-rbac-role-hierarchy-diamond-bfs.md @@ -0,0 +1,147 @@ +# UNDF: UNDF-2026-000000054 +# UNDF: (pending) +# sea-orm-0001: enumerate_role / list_role_hierarchy_edges — O(2^D) diamond BFS + +## CWE-407 — Algorithmic Complexity: Quadratic/Exponential Traversal of Role Hierarchy + +| Field | Value | +|-------|-------| +| ID | sea-orm-0001 | +| Severity | HIGH | +| Ecosystem | Rust | +| Package | sea-orm (rbac feature) | +| File | `src/rbac/engine/role_hierarchy_impl.rs` | +| Lines | 9–65 | +| Complexity | O(2^D) where D is diamond depth | +| Hot path | `user_can()` → `get_user_role_ids()` → `enumerate_role()` — called on every authorization check | + +## Defect + +Both `enumerate_role` and `list_role_hierarchy_edges` implement a BFS over the role +hierarchy using a `seen` HashSet to prevent re-visiting nodes. However, the guard +has a critical omission: child roles are checked against `seen` before enqueueing, +but **never inserted into `seen` at enqueue time**. Only the root node is inserted +at startup. + +```rust +// BROKEN: seen is only populated with the root role +queue.push_back(role); +seen.insert(role); // only root + +while let Some(role) = queue.pop_front() { + roles.push(role); + if let Some(children) = role_hierarchy.get(&role) { + for child in children { + if !seen.contains(child) { // checks seen... + queue.push_back(*child); // ...but never inserts child into seen! + } + } + } +} +``` + +Because `seen.insert(child)` is absent, when two parents both point to the same +child role (a diamond), that child passes the `!seen.contains(child)` test from +both parents and is enqueued twice. Every role below the merge point is then +processed once per path that reaches it — O(2^D) total work for D diamond levels. + +**Diamond trace** for A → [B, C], B → [D], C → [D]: + +| Step | Queue | seen | roles | +|------|-------|------|-------| +| init | [A] | {A} | [] | +| pop A | push B (ok), push C (ok) → [B, C] | {A} | [A] | +| pop B | push D (D ∉ seen, enqueue, no insert) → [C, D] | {A} | [A,B] | +| pop C | push D again (D ∉ seen!) → [D, D] | {A} | [A,B,C] | +| pop D | → [D] | {A} | [A,B,C,D] | +| pop D | → [] | {A} | [A,B,C,D,**D**] | + +D is visited twice. With depth D=10 (realistic RBAC hierarchy), a single +`user_can()` call triggers 2^10 = 1,024 role visits instead of R. + +The same bug is present in both `enumerate_role` (returns `Vec`) and +`list_role_hierarchy_edges` (returns edges). Both files are identical between +`sea-orm` and `sea-orm-sync`: + +- `src/rbac/engine/role_hierarchy_impl.rs` +- `sea-orm-sync/src/rbac/engine/role_hierarchy_impl.rs` + +## Fix + +Insert each child into `seen` **at enqueue time**, not at dequeue time: + +```rust +pub fn enumerate_role(role: RoleId, role_hierarchy: &RoleHierarchyMap) -> Vec { + let mut roles = Vec::new(); + let mut queue = VecDeque::new(); + let mut seen = HashSet::new(); + + queue.push_back(role); + seen.insert(role); + + while let Some(role) = queue.pop_front() { + roles.push(role); + if let Some(children) = role_hierarchy.get(&role) { + for child in children { + if seen.insert(*child) { // insert returns true if newly added + queue.push_back(*child); // only enqueue if not already seen + } + } + } + } + + roles +} +``` + +Same fix applies identically to `list_role_hierarchy_edges` (the `seen.insert(*child)` +guard around `queue.push_back`; the `edges.push(...)` call outside the guard is +intentional and should remain unconditional to capture all hierarchy edges). + +```rust +pub fn list_role_hierarchy_edges( + role: RoleId, + role_hierarchy: &RoleHierarchyMap, +) -> Vec { + let mut edges = Vec::new(); + let mut roles = Vec::new(); + let mut queue = VecDeque::new(); + let mut seen = HashSet::new(); + + queue.push_back(role); + seen.insert(role); + + while let Some(role) = queue.pop_front() { + roles.push(role); + if let Some(children) = role_hierarchy.get(&role) { + for child in children { + if seen.insert(*child) { // fix: insert at enqueue + queue.push_back(*child); + } + edges.push(RoleHierarchy { // edge record stays unconditional + super_role_id: role, + role_id: *child, + }); + } + } + } + + edges +} +``` + +## Speedup + +| Diamond depth D | Roles visited (before) | Roles visited (after) | Speedup | +|-----------------|------------------------|----------------------|---------| +| 5 | 32 (2^5) | 6 | 5× | +| 10 | 1,024 (2^10) | 11 | 93× | +| 15 | 32,768 (2^15) | 16 | 2,048× | +| 20 | 1,048,576 (2^20) | 21 | ~50,000× | + +For a flat chain (no diamonds) the fix is neutral — same O(R) traversal. +For real-world RBAC hierarchies with role sharing (e.g. `viewer` role inherited +by many specialized roles), the speedup is O(2^sharing_depth) vs O(R). + +The fix also eliminates duplicate entries in the returned `Vec`, which +could cause double-counting of role grants in `get_roles_and_ranks()`. diff --git a/defects/tokio/patch/CLEAN.md b/defects/tokio/patch/CLEAN.md new file mode 100644 index 000000000..03c893fbe --- /dev/null +++ b/defects/tokio/patch/CLEAN.md @@ -0,0 +1,11 @@ +# CLEAN — tokio + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `tokio/src/runtime/scheduler/multi_thread/idle.rs` — `sleepers: Vec` with `.contains()` in `is_parked()`: N is bounded to the worker thread count (typically 1–32). Called once per work-steal attempt, not in a loop over workers. Not actionable. +- `tokio-util/src/codec/any_delimiter_codec.rs` — `seek_delimiters: Vec` contains check per byte in buffer: D (delimiter count) is user-configured and typically 1–3. This is O(B×D) but D is constant and tiny. Not actionable. +- All other `contains()` calls use bitflags or range containment. CLEAN. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/tonic/patch/CLEAN.md b/defects/tonic/patch/CLEAN.md new file mode 100644 index 000000000..fd393f77a --- /dev/null +++ b/defects/tonic/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — tonic + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `tonic-build/src/client.rs`, `server.rs` — `disable_comments` is `&HashSet`. CLEAN. +- `tonic/src/codec/compression.rs` — `EnabledCompressionEncodings.inner` is a fixed-size `[Option; 3]` array. CLEAN. +- `grpc/src/client/load_balancing/round_robin.rs` — `TestSubchannelList::contains` only appears in test code. CLEAN. +- `xds-client/src/client/worker.rs` — `received_names` is `HashSet`. CLEAN. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/tor/patch/tor-0001-routerlist-digestset.patch b/defects/tor/patch/tor-0001-routerlist-digestset.patch index e666c76c7..05f0d18e3 100644 --- a/defects/tor/patch/tor-0001-routerlist-digestset.patch +++ b/defects/tor/patch/tor-0001-routerlist-digestset.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000316 +# UNDF: UNDF-2026-000000106 diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 3f82d45..c1e8b9f 100644 --- a/src/feature/nodelist/routerlist.c diff --git a/defects/tor/patch/tor-0002-nodelist-family-id-strmap.patch b/defects/tor/patch/tor-0002-nodelist-family-id-strmap.patch index af1b89687..784649ff0 100644 --- a/defects/tor/patch/tor-0002-nodelist-family-id-strmap.patch +++ b/defects/tor/patch/tor-0002-nodelist-family-id-strmap.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000317 +# UNDF: UNDF-2026-000000187 diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c index abc1234..def5678 100644 --- a/src/feature/nodelist/nodelist.c diff --git a/defects/tor/patch/tor-0003-kist-readd-heap-idx-o1.patch b/defects/tor/patch/tor-0003-kist-readd-heap-idx-o1.patch index 1e94d702c..0ef8b5c73 100644 --- a/defects/tor/patch/tor-0003-kist-readd-heap-idx-o1.patch +++ b/defects/tor/patch/tor-0003-kist-readd-heap-idx-o1.patch @@ -1,4 +1,4 @@ -# UNDF: UNDF-2026-000000318 +# UNDF: UNDF-2026-000000231 diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c index abc1234..def5678 100644 --- a/src/core/or/scheduler_kist.c diff --git a/defects/wasmer/patch/CLEAN.md b/defects/wasmer/patch/CLEAN.md new file mode 100644 index 000000000..69a71cd8a --- /dev/null +++ b/defects/wasmer/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — wasmer + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `lib/wasix/src/os/task/thread.rs` — `signals: Vec` with `.contains()`: POSIX signal space is 1–31 values; N is strictly bounded. Not actionable. +- `lib/package/src/package/volume/fs.rs` — `intermediate_directories` and `metadata_files` are `BTreeSet`. CLEAN. +- `lib/compiler-llvm/src/object_file.rs` — `visited: HashSet` with `insert()` return value used as guard before recursion. Correct pattern. CLEAN. +- All other `contains()` calls are on bitflags or string substring checks. CLEAN. + +**Result: No actionable CWE-407 defects.** diff --git a/defects/wasmtime/patch/CLEAN.md b/defects/wasmtime/patch/CLEAN.md new file mode 100644 index 000000000..11e939d7f --- /dev/null +++ b/defects/wasmtime/patch/CLEAN.md @@ -0,0 +1,12 @@ +# CLEAN — wasmtime + +Scanned 2026-03-29 for CWE-407 (algorithmic complexity). + +## Findings + +- `crates/environ/src/graphs/scc.rs` — SCC algorithm uses `EntitySet` (a sparse set abstraction) for `on_stack`. CLEAN. +- `crates/environ/src/fact/trampoline.rs` — `ancestors: Vec` with `.contains()` for reentrance guard: WebAssembly Component Model instance nesting depth is bounded in practice (typically 2–5 levels). Called once per adapter compilation (not per Wasm call). Not actionable. +- `crates/wasmtime/src/compile.rs` — `trampoline_types_seen: HashSet`. CLEAN. +- `crates/environ/src/compile/module_types.rs` — `already_seen: HashMap` for rec group deduplication. CLEAN. + +**Result: No actionable CWE-407 defects.**