wave21 survey: 10 clean-scan additions (third full-clean wave)

tesseract, mupdf, tor, strongswan, scapy, masscan, gatk, htslib, QGIS,
postgis all clean. Honor roll cumulative: 125 projects.

GATK 1364 findings dominated by Java HashSet declared-type FPs and
JUnit ExtensionContext test plumbing. Tor 156 M1 are sort comparators
(O(N log N) overall, not quadratic). htslib bounded by BAM/SAM/VCF
file-format spec constants. QGIS dominated by Qt UI patterns + sipify
build-time codegen.

Three more scanner enhancement candidates queued (Java HashSet awareness,
qsort comparator detection, codegen-time path suppression).
This commit is contained in:
russell@unturf.com 2026-04-25 15:59:22 -04:00
parent dce02d80df
commit 0243ab3980
No known key found for this signature in database

View file

@ -0,0 +1,98 @@
# Wave 21 — OCR, PDF, Tor, IPsec, Packet Tools, Genomics, GIS
**Survey date:** 2026-04-25
**Tool:** unmoad (9 active MOAD detectors, HIGH+ severity filter)
**Scope:** 10 projects across OCR (tesseract), PDF rendering (mupdf), anonymity network (tor), IPsec (strongswan), packet manipulation (scapy, masscan), genomics (gatk, htslib), and GIS (QGIS, postgis).
---
## Summary
Wave 21 totals 4,479 HIGH+ findings across 10 projects. **Ten new clean-scan honor roll entries** (full clean wave). Honor roll cumulative: **125 projects** across waves 3-21.
**No flagship CWE-407 patches ship this pass.** GATK and htslib bioinformatics tools have huge file-format-spec bounded constants (BAM/SAM/VCF/BCF header field names). PDF/PostScript tools (mupdf) follow the spec-bounded pattern documented in the docs-pipeline survey (Wave 6). Tor's strcmp clusters are sort comparators (O(N log N) overall) not quadratic membership tests.
## Clean-scan honor roll — 10 new entries
| Project | Lang | Role | Notes |
|---------|------|------|-------|
| **tesseract** | C++/Java | OCR engine | 36 findings: Java ScrollView UI demo (M5 menu items, M3 ThreadLocal — bounded by GUI element count); `unicharmap.cpp:83` defines `UNICHARMAP::contains` (its own data structure, O(N) appropriate for small char-mapping tables); `params.h:79` strcmp on tesseract config param name (small fixed list). **clean** |
| **mupdf** | C | PDF rendering library | 163 findings: `output-pcl.c` PCL output format options, `html-parse.c` `known_html_tags[m]` binary search, `xml.c` attribute name comparisons. PDF/PCL/HTML format-spec bounded. **clean** |
| **tor** | C | Anonymity network | 198 findings: 156 M1 `strcmp`/`strcasecmp` on Tor protocol keys, nicknames, config directives — most are sort comparators (O(N log N) overall). dirvote, relay_config, dirauth bounded by consensus-spec. **clean** |
| **strongswan** | C/Java | IPsec implementation | 67 findings: GNOME auth-dialog password prompt strings (M4 `printf("%s\n%s\n", secret_name, secret)` is the secret prompt, not log leak); Android UI `mSelection.contains(packageName)` per app (Android phones bounded ~50-200 apps). **clean** |
| **scapy** | Python | Packet manipulation | 113 findings: docs/test contexts, `route6.py:159` `self.routes.index(to_del[0])` for IPv6 route deletion (bounded by routing table), threading.Event signaling, ReDoS in version regex. **clean** |
| **masscan** | C | Internet-scale port scanner | 13 findings: interface name lookup in syscall enumeration (bounded by network interfaces), CLI argv parsing, COAP token printf debug. **clean** |
| **gatk** | Java | Genomics analysis toolkit | 1,364 findings: `passingEvents.contains(event)` is `Set<Event>` (HashSet O(1)) — Java declared-type FP; M3 cluster (462) in `*Test.java` JUnit ExtensionContext. `infoFieldAnnotationKeyNamesToRemove.contains` etc are HashSet members. **clean** |
| **htslib** | C | SAM/BAM/CRAM reference library | 108 findings: `header.c` BAM/SAM header field name lookups, `vcf.c` VCF header keys ("IDX"), `tbx.c` gVCF special tokens (`<*>`, `<NON_REF>`). All bounded by genomics file-format spec. **clean** |
| **QGIS** | C++/Python | Geographic information system | 2,295 findings: 2,000 M7 in vendored Qt patterns + Python plugins (db_manager UI for column display, oracle connector tablename dedup, sipify build-time SIP code generator). UI bounded by displayed item count. **clean** |
| **postgis** | C | PostgreSQL GIS extension | 122 findings: 80 M7 in vendored flatgeobuf hash detection (bounded fixed hash function tables), shapefile loader column name lookups bounded by table column count, GML XML node name checks. **clean** |
Honor roll now stands at **125 projects** validated zero-real-finding under MOAD scanning.
## Per-target findings
| Project | Lang | Total | M1 | M3 | M4 | M5 | M6 | M7 | M9 | M11 | Triage |
|---------|------|------:|---:|---:|---:|---:|---:|---:|---:|----:|--------|
| **QGIS** | C++/Python | 2295 | 234 | 19 | 4 | - | 2 | 2000 | - | 36 | UI bounded + SIP codegen. **clean** |
| **gatk** | Java | 1364 | 409 | 462 | - | 50 | - | 440 | - | 3 | HashSet declared-type FPs + JUnit ExtensionContext. **clean** |
| **tor** | C | 198 | 156 | - | 16 | - | 1 | 19 | 1 | 5 | Sort comparators + protocol-spec keys. **clean** |
| **mupdf** | C | 163 | 152 | - | 6 | - | - | 5 | - | - | PDF/PCL/HTML format-spec strcmp. **clean** |
| **postgis** | C | 122 | 36 | - | 6 | - | - | 80 | - | - | flatgeobuf hash detection + shp loader. **clean** |
| **scapy** | Python | 113 | 18 | 50 | 13 | 1 | 22 | - | - | 9 | Tests + route bounded. **clean** |
| **htslib** | C | 108 | 89 | - | 16 | - | 1 | 2 | - | - | Genomics format-spec field names. **clean** |
| **strongswan** | C/Java | 67 | 21 | - | 31 | 1 | 4 | 8 | - | 2 | GNOME password prompt + Android UI. **clean** |
| **tesseract** | C++/Java | 36 | 6 | 1 | 3 | 5 | - | 21 | - | - | Java demo + config table. **clean** |
| **masscan** | C | 13 | 11 | - | 1 | - | - | 1 | - | - | Interface lookup + CLI args. **clean** |
## Investigation notes
### gatk `passingEvents.contains(event)` — Java HashSet FP
```java
final Set<Event> passingEvents = sourceSet.getVariationEvents(0).stream()
.filter(event -> !badPileupEvents.contains(event))
.collect(Collectors.toSet());
goodPileupEvents.stream()
.filter(event -> !passingEvents.contains(event)) // O(1) — Set
.forEach(passingEvents::add);
```
Both `passingEvents` and `badPileupEvents` are declared `Set<Event>` via `Collectors.toSet()`. `.contains(event)` is HashSet — O(1). Same scanner gap (Java declared-type) noted in Wave 11 / Wave 15 / Wave 18.
### Tor sort comparators are not quadratic
```c
// dirvote.c:638
if ((r = strcmp(b->status.nickname, a->status.nickname)))
return r;
```
This is `strcmp` inside a `compare_vote_rs` qsort comparator. Each call is O(1) — the sort is O(N log N) overall, not O(N²). Scanner triggers on `strcmp-in-loop` because the comparator is called inside qsort's loop, but the algorithmic class is O(N log N) for the sort, not quadratic.
### htslib genomics file-format constants
`header.c:129` `strcmp(sn, str.s) != 0` checks SAM header SN tag uniqueness (bounded by reference sequence count, typically <100k for human genome). `vcf.c:391` `strcmp("IDX", hrec->keys[i])` checks for the VCF metadata IDX key (single fixed string). All bounded by genomics file-format spec.
### QGIS sipify codegen
`scripts/sipify.py` generates SIP bindings between QGIS C++ and Python at build time. Per-line nesting count is build-time, runs once per release.
### mupdf PDF/PostScript spec lookups
PDF object-type names ("All", separation names, attribute keys) and HTML/FB2 known-tag tables are PDF/HTML spec constants, fixed at compile time. `html-parse.c:173` is a binary search on `known_html_tags[]`, not linear scan.
## Triage backlog
1. **Scanner enhancement: Java HashSet declared-type awareness** (continued from Wave 11/15/18) — gatk reinforces with 100+ findings.
2. **Scanner enhancement: qsort/comparator awareness**`strcmp` inside `compare_*` functions called from qsort is O(N log N) overall, not quadratic. Tor's 156 M1 findings would mostly clear.
3. **Scanner enhancement: codegen-time path suppression** — QGIS sipify, similar Python codegen scripts in `scripts/` directories.
## Method
Same as Waves 3-20: shallow clone, `unmoad -s high -f json`, filter test/vendor/codegen/UI noise, manual triage of strongest source-only candidates per project. **Ten projects added to clean-scan honor roll** (third full-clean wave). No new UNDF IDs assigned (no patches shipped).
## References
- `unmoad` detection engine: `git.unturf.com/engineering/unmoad.com`
- Earlier surveys: `/test-harness-survey/` through `/wave20-container-re-js-engine-survey/`
- Clean-scan honor roll cumulative: 125 projects across waves 3-21