0.8.0 - 2026-08-24
Release Notes
Ten-agent full-product review remediation: security hardening, engine
performance overhaul, API polish, CLI/UX, frontend a11y, and release-chain
integrity. All gates green (361 lib + 35 CLI + 8 integration tests, clippy
-D warnings, cargo fmt, UI svelte-check strict, Playwright visual QA).
Added
- CLI: grouped
--helpsections (candidate/stopping/tuning/phase2/WARP),
--cap→max-probesand--target→stop-afteraliases,--warp-wgconf
alias,serve --open(cross-platform browser launch), TTY-only live
progress ticker for one-shot scans,--json-errorsmachine-readable
failures, help examples block. - API: machine-readable
codefield on every error envelope; typed WARP
registration errors now map to proper statuses (timeout→504,
rate-limit→429, rejection/server→502) instead of blanket 502; xray
download failures use the uniform error envelope (no more HTTP 200 with
{success:false}); SSE events carry an explicitretry:hint. - Resilience: SSE stream survives broadcast lag — it replays the last
terminal snapshot and keeps listening instead of closing (reconnect-storm
fix); UI re-hydrates status/results when EventSource reconnects and shows
an offline banner; EventSource handle is closed on teardown.
Changed
- Engine throughput: per-worker task queues replace the shared
mutex-guarded receiver (dispatch no longer serializes); producer uses
backpressuredsend().awaitinstead of a try_send/sleep poll; probe
futures race cancellation (select!) so Stop takes effect immediately
instead of after the in-flight timeout; result store flushes are O(1)
pushes with lazy sort-on-read (was O(found²) merge churn); broadcast
buffer 1024→4096; batch flush 64→256; per-port RNG hoisted out of hot
loops; phase-2 shares config/candidate sets viaArcacross workers. - WARP: server public key resolved once per scan (was one identity.json
read PER PROBE); socket cache is per-controller and injectable, never
holds its lock across.await, and the global static is gone; corrupt
persisted identity keys log a warning before falling back to bundled. - Fetch stack: ranges + xray downloads share one reqwest client whose
redirect policy enforces the SSRF guard per hop; ~200 lines of hand-rolled
TLS/HTTP/chunked fetch code deleted; TCP_NODELAY on probe sockets;
wait-for-xray polling backs off exponentially; trial-dir sweeps throttle
to once per stale window and guard cleanup leaves the runtime thread. - Frontend: latin-only Inter subsets (-83 KB dist), first-invalid focus
management,aria-describedbywiring on all field errors,aria-sorton
sortable buttons, checkbox focus rings, copy feedback viarole=status,
safe-area padding on the sticky action bar, live pace/ETA tick,
Copy-all respects active filters,tsconfignowstrict.
Security
--warp-wgconf-fileread capped at 64 KiB before parse (OOM guard).- Xray zip: archive and entry sizes capped at 64 MiB (zip-bomb guard);
cached-binary memo re-stats the file so a vanished/truncated binary
re-downloads instead of failing at spawn. Origin: nullrequests denied (sandboxed-frame CSRF surface); JSON body
rejection text sanitized + truncated before echoing into error envelopes.- Contract tightening:
deny_unknown_fieldson ScanConfig/Phase2/Warp
payloads, custom WARP endpoints capped (2048), raw port-array precheck
before dedupe sort, decoded SIP002 user-id cap, wg URI host grammar check,
profile-name traversal characters rejected. - npm wrapper verifies the downloaded archive against its published
.sha256(fail closed), extracts via argv-formspawnSync(no shell
interpolation), retries downloads once, requires Node ≥14.14. - CI gains a version-parity job (Cargo.toml == npm package.json ==
RELEASE_TAG) and a pinned rust-toolchain (1.88 = CI toolchain).
Fixed
- Ctrl+C hook failures are logged instead of silently leaving a scan
running (scan + wizard paths); wizard prompts moved off tokio workers
(spawn_blocking) and show a config summary before confirming. - Inline phase-2 verifier invariant violations return failed verdicts
instead of panicking a worker task; "every attempt failed" messages no
longer claim probes never ran when they simply did not pass; ephemeral
port errors carry their io::ErrorKind. - dgst parser is line-exact (
SHA2-256= <hex>[ <filename>]) so a long hex
comment cannot satisfy the checksum; bundled range pools assert non-empty
at test time; Windows token-size query validates ERROR_INSUFFICIENT_BUFFER
before sizing its buffer. - Stale docs/comments corrected (profiles persistence, spec/intent frontend
reality notes, CHANGELOG newest-first order restored).
Install cf-scanner 0.8.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/qmahyar/cf-scanner/releases/download/v0.8.0/cf-scanner-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/qmahyar/cf-scanner/releases/download/v0.8.0/cf-scanner-installer.ps1 | iex"Download cf-scanner 0.8.0
| File | Platform | Checksum |
|---|---|---|
| cf-scanner-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| cf-scanner-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| cf-scanner-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| cf-scanner-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |