wave7 survey: 5 clean-scan additions (wireguard-go, longhorn-engine, tinygo, maddy, openbgpd-portable)

29 mail/DNS/storage/VPN/RTOS/pg-eco targets scanned. No flagship CWE-407 patches
this pass — strong M1 candidates resolved to bounded fixed config tables
(strcmp on rule lookups), already-optimal data structures (RoaringTreemap,
ObjHashSet), or query-shape constants too small to cross the wall-clock bar.

Honor roll: 30 projects cumulative across waves 3-7. questdb `recordViews`
borderline real defect (O(N²) view dedup on ObjList) logged for future pass.
This commit is contained in:
russell@unturf.com 2026-04-25 13:16:49 -04:00
parent 4c4a8ecac9
commit e7724fa3b7
No known key found for this signature in database

View file

@ -0,0 +1,99 @@
# Wave 7 — Mail, DNS, Storage, VPN, Audio, RTOS, Postgres ecosystem
**Survey date:** 2026-04-25
**Tool:** unmoad (9 active MOAD detectors, HIGH+ severity filter)
**Scope:** 29 projects across mail (maddy, neomutt), DNS (pdns, knot, nsd), VPN/routing (wireguard-go, libreswan, openbgpd-portable, gobgp), distributed storage (garage, longhorn-engine, openebs, glusterfs), time-series databases (timescaledb, questdb, m3), audio servers (pipewire, jack2, mpv), real-time OS (nuttx, RIOT), Go-on-microcontroller (tinygo), document/key-value stores (couchdb, surrealdb, KeyDB), and Postgres ecosystem tooling (patroni, pgbackrest, pgpool2, lxc).
---
## Summary
Wave 7 totals 4,116 HIGH+ findings across 29 projects. Five new clean-scan honor roll entries. **No flagship CWE-407 patches ship this pass** — the strong M1 candidates either resolve to bounded fixed config tables (compile-time small N), to data structures already optimal (HashSet, ObjHashSet, RoaringTreemap), or to query-shape constants too small to cross the wall-clock threshold.
This wave behaves like the docs-pipeline survey: mature C/C++/Rust infrastructure with already-optimized hot paths. Honest "investigated, no patch this pass" outcome.
## Clean-scan honor roll — 5 new entries
| Project | Lang | Role | Notes |
|---------|------|------|-------|
| **wireguard-go** | Go | Userspace WireGuard implementation | Zero HIGH+ across all 9 detectors. Tight crypto codebase. |
| **longhorn-engine** | Go | Rancher Longhorn block storage engine | Zero HIGH+. Distributed-storage core, well-disciplined. |
| **tinygo** | Go | LLVM-based Go compiler for microcontrollers | 5 M4 findings, all `token`/`Msg` in compiler error strings — credential-keyword false positives. |
| **maddy** | Go | Modular mail server | 4 M4 findings, all error/log strings naming protocol fields ("api_token", "password is expired") — string-literal false positives. |
| **openbgpd-portable** | C | OpenBSD BGP daemon (portable) | 2 M6 findings, both TCP-MD5 signing for BGP per RFC 2385 — protocol-mandated, not a defect. |
Honor roll now stands at **30 projects** validated zero-real-finding under MOAD scanning.
## Per-target findings
| Project | Lang | Total | M1 | M3 | M4 | M5 | M6 | M7 | M9 | M11 | Triage |
|---------|------|------:|---:|---:|---:|---:|---:|---:|---:|----:|--------|
| questdb | Java/Rust | 1840 | 344 | 962 | 35 | 142 | - | 357 | - | - | M1 hits in `qdbr/parquet_write/simd.rs` are bloom-filter `&[u64].contains` — the bloom array IS the data structure; replacing with HashSet would defeat SIMD layout. M3 cluster: `vec_docs.set` and similar — scanner FP on `.set(` literal. |
| surrealdb | Rust | 370 | 155 | - | 48 | 4 | - | 160 | - | 3 | HNSW `pending_docs.contains(doc_id)``pending_docs` is `RoaringTreemap` with O(1)-ish containment. NOT a defect. `computed_deps.rs:217` cycle-safety-net Vec.contains is real but only fires on cycle (caught at DEFINE time). |
| glusterfs | C | 320 | 294 | 12 | 13 | 1 | - | - | - | - | 90% strcmp-in-loop on fixed xlator/option tables. `extras/profiler/glusterfs-profiler` Python script hits — diagnostic tool, not hot path. |
| RIOT | C | 251 | 156 | 4 | 49 | - | 6 | 28 | 5 | 3 | Embedded RTOS — most M1 hits are static driver tables. |
| garage | Rust | 224 | 172 | - | 13 | 1 | 1 | 34 | - | 3 | `rpc_helper.rs:593` `nodes.contains(n)` inside replication-factor loop (typically ≤5) — bounded constant. `redoc.standalone.js` is vendored. |
| m3 | Go | 279 | 217 | 16 | 7 | 1 | - | 35 | - | 3 | `swagger-ui.js` vendored hits dominate. Native code mostly fixed-table strcmp. |
| mpv | C | 181 | 177 | - | - | - | - | 4 | - | - | Most M1 in `defaults.js` (player JS) are command-prefix scans on bounded option list. |
| nuttx | C | 169 | 145 | - | 13 | - | - | 7 | 1 | 3 | Asm `arch_strcmp.S` matched as linear-search-in-loop — these ARE the strcmp primitive. |
| pgpool2 | C | 151 | 94 | - | 44 | - | 13 | - | - | - | `pgindent` Perl tool grep-in-loop. M4 cluster: log strings with "password" literal in error templates. |
| pdns | C++ | 110 | 67 | 1 | 2 | 4 | 3 | 31 | - | 2 | `d3.v3.js` vendored. M7 cluster worth a deeper look (recursor flatland defects). |
| knot | C | 107 | 93 | - | 7 | - | 1 | 5 | - | 1 | DNS server — fixed RR-type tables drive most M1. |
| KeyDB | C | 96 | 84 | 1 | 7 | - | - | 2 | - | 2 | `redis-cli.c` argv parsing strcmp — fixed CLI option table. |
| timescaledb | C | 79 | 70 | - | 2 | - | - | 7 | - | - | PostgreSQL extension — `bgw_jobs.c` and similar mostly fixed config lookups. |
| neomutt | C | 76 | 29 | - | 43 | - | 4 | - | - | - | Mail client — M4 cluster is account/credential field NAMES in config-key strings. |
| patroni | Python | 69 | 3 | 49 | 7 | 2 | 3 | - | - | 5 | M3 cluster is `event.set()`/`self.set('key', val)` — scanner FP on literal `.set(`. |
| nsd | C | 61 | 26 | - | 35 | - | - | - | - | - | Authoritative DNS server — strcmp on RR/option tables. |
| couchdb | Erlang/JS | 59 | 27 | 3 | 7 | 2 | 16 | 4 | - | - | M6 weak-hash hits in legacy migration code. |
| lxc | C | 57 | 54 | - | 1 | - | - | 2 | - | - | Container manager — fixed cgroup/capability tables. |
| libreswan | C | 31 | 14 | 6 | 9 | - | - | - | 2 | - | IPsec daemon — fixed crypto algorithm tables. |
| pipewire | C | 30 | 21 | - | 3 | - | - | 6 | - | - | Audio server — fixed format/property tables. |
| jack2 | C/Python | 16 | 9 | - | - | - | 3 | - | - | 4 | `waflib/Tools/c_config.py` build-system Python — load-time. |
| pgbackrest | C | 15 | 15 | - | - | - | - | - | - | - | All 15 are strcmp on `parseRuleCommand`/`parseRuleOption` — fixed compile-time rule tables. |
| gobgp | Go | 11 | 10 | - | 1 | - | - | - | - | - | `slices.Contains(req.UUIDs, v)` worth investigation but UUID list bounded by API call shape. |
| openebs | Go | 9 | 4 | - | - | - | - | 5 | - | - | Container storage operator — small surface. |
| **wireguard-go** | Go | 0 | - | - | - | - | - | - | - | - | **clean** |
| **longhorn-engine** | Go | 0 | - | - | - | - | - | - | - | - | **clean** |
| **tinygo** | Go | 5 | - | - | 5 | - | - | - | - | - | **clean** (FPs only) |
| **maddy** | Go | 4 | - | - | 4 | - | - | - | - | - | **clean** (FPs only) |
| **openbgpd-portable** | C | 2 | - | - | - | - | 2 | - | - | - | **clean** (RFC-mandated TCP-MD5) |
## Investigations that did not patch-ship
### questdb `QueryModel.recordViews` — borderline real defect
`io.questdb.griffin.model.QueryModel.recordViews()` (line 1521 + 1532) iterates view definitions and dedupes by `referencedViews.contains(viewDefinition)` where `referencedViews` is `ObjList<ViewDefinition>` — a linear-scan list. Classic O(N²) dedup pattern.
Per-query cost is bounded by the query's chain depth: for typical analytical queries touching ≤20 views, the constant is invisible. For deeply chained materialized-view queries (50+ views) the cost becomes 2500 ops per call, called twice per query. Real but borderline.
**Not patch-shipped this pass.** The fix is mechanical (add a parallel `ObjHashSet<ViewDefinition>` for membership check, keep ObjList for ordered iteration), but the wall-clock impact at realistic query shapes does not cross the CWE-407 bar. Logged here so future scanner runs surface it again.
### surrealdb HNSW `pending_docs.contains`
Fully investigated. `pending_docs` is `RoaringTreemap` (Rust roaring crate) — already O(log n) or better depending on density. NOT a CWE-407 defect; the scanner does not yet model RoaringTreemap as a containment-optimal type.
### gobgp `slices.Contains(req.UUIDs, v)`
`req.UUIDs` length is bounded by API request shape (typically 1-100 UUIDs per gRPC call). Per-iteration cost on the inner loop dominates only for synthetic requests far above realistic API usage. Logged as low-priority, not patch-shipped.
### patroni M3 cluster (49 hits)
All 49 hits are `event.set()` (threading.Event signal flag — no leak) or `self.set('key', value)` on DCS clients (etcd/raft/k8s clients). Scanner false-positive on literal `.set(` regex match. Worth tightening the M3 detector to require ContextVar import context.
## Triage backlog
1. **questdb M3 cluster (962 hits)** — large enough to deserve its own pass. Most likely scanner FP on `.set(` literal in setter methods, but worth a detector-level tightening before re-scanning.
2. **questdb M7 cluster (357 hits)** — Flatland defect surface in SIMD/parquet code. Need to model the SIMD layout before claiming complexity-class change.
3. **pdns M7 cluster (31 hits)** — recursor candidates worth a focused pass.
4. **patroni M3 detector tightening** — add ContextVar/`from contextvars import` context check before flagging `.set(` on identifiers.
5. **scanner enhancement** — Roaring/Bitmap/HashSet type awareness in M1 detector to suppress these false positives at source.
## Method
Same as Waves 3-6: shallow clone, `unmoad -s high -f json`, filter test/vendor/docs noise, manual triage of the strongest source-only candidates per project. Five projects added to the clean-scan honor roll. No new UNDF IDs assigned this wave (no patches shipped).
## References
- `unmoad` detection engine: `git.unturf.com/engineering/unmoad.com`
- Earlier surveys: `/test-harness-survey/` (Wave 3), `/wave4-linter-ci-survey/`, `/wave5-cicd-iac-survey/`, `/wave6-docgen-webfw-tui-survey/`, `/docs-pipeline-survey/`
- Clean-scan honor roll cumulative: 30 projects across waves 3-7