| 1 | # Cyclops v2 - validation record (2026-06-11) |
| 2 | |
| 3 | Every pillar exercised on real data, not asserted. Reproducible via the scripts named. |
| 4 | |
| 5 | ## Pillar 1 - Memory + anti-slop gate (`memory/selftest.py`) |
| 6 | 9/9 PASS: |
| 7 | - finding **REFUSED** without an execution proof (the core anti-slop rule) |
| 8 | - finding **ALLOWED** once an ASan-write proof is attached |
| 9 | - **DISPROVEN** hypothesis can never become a finding |
| 10 | - cleared-axis recall (anti-tunnel-vision) + redis cache/queue/dedup roundtrips |
| 11 | |
| 12 | ## Pillar 2 - Brain / CPG dataflow (`brain/`, run via `e2e_proof.sh`) |
| 13 | - Joern smoke test: traced `argv → strcpy`, `DATAFLOW_PATHS=2`. |
| 14 | - On **real cJSON source**: `c-memory-corruption.sc` found **103 reachable |
| 15 | source→sink memory-corruption paths** → 103 hypotheses written to the graph. |
| 16 | - Query library: **36 Semgrep rules** `--validate` clean + smoke-tested (14 rules |
| 17 | fire on the right sinks); 7 Joern dataflow scripts (`reachableByFlows`). |
| 18 | |
| 19 | ## Pillar 3 - Oracle / dynamic proof (`oracle/`, `crash_demo.py`) |
| 20 | - libFuzzer+ASan+UBSan harness **compiled and ran against real cJSON** (clang-14). |
| 21 | - On a hardened tag: **no crash → ZERO findings recorded** (refused to fabricate). |
| 22 | - Triage→gate on real ASan reports: |
| 23 | - heap **WRITE** → CRITICAL → **promoted to Finding** |
| 24 | - **use-after-free** → CRITICAL → **promoted to Finding** |
| 25 | - heap **READ** → MEDIUM → **CLEARED, NOT inflated to a P1** ← this exact |
| 26 | inflation (read-DoS→HIGH) was v1's audited failure mode; v2 refuses it. |
| 27 | - Graph held only the 2 RCE-capable findings; the READ went to ClearedAxis. |
| 28 | |
| 29 | ## Supporting - fresh-target feed (`orchestrator/feed.py`) |
| 30 | Pulled **17 real, days-old releases** from live GitHub, e.g. llama.cpp (0.3d old), |
| 31 | safetensors v0.8.0 (2.3d), transformers v5.11.0 (1.0d), langchain-core (0.4d), |
| 32 | grafana v13.0.2 (2.2d), jenkins (1.1d). Anti-"beaten-to-the-punch" hunting on live data. |
| 33 | |
| 34 | ## End state |
| 35 | Clean seeded graph (6 archetypes, 12 sink classes), **17 fresh targets queued**, |
| 36 | 0 fabricated findings. Engine on forge (CT236); repo+vault on CT215. |
| 37 | |
| 38 | ## Honest limits |
| 39 | - `rr` unavailable (unprivileged LXC, `perf_event_paranoid=4`) → GEF + ASan reports |
| 40 | for crash→exploit triage instead. |
| 41 | - Firecracker/microVM unavailable (no `/dev/kvm`) → Docker + detonation CT 302. |
| 42 | - Joern `.sc` scripts authored against the proven `reachableByFlows` form; the C |
| 43 | memory-corruption query is run-verified (103 paths), the rest compile-check on |
| 44 | first archetype run. Python/JS dynamic-dispatch dataflow can under-resolve |
| 45 | (documented in `brain/joern-queries/_runner.md`); the ASan oracle is the arbiter. |