Repository navigation
Closed
2 / 22 of 2 issues completedLabels
Description
Main @ 958e1ec6110e80e0c22104a7b18ed0fb4c60b723 (merge of #457). Prior audit @ 00aa515 (#437). Run via /general-audit.
Method
Per lessons #426 + #438 (orchestrator-direct default for small diffs, narrow agents only when justified, pre-fetch existing-issue lists, backfill timed-out concerns):
- 0 agents launched. 52-file diff right at threshold; orchestrator-direct sweep covered surface w/o context blow-up.
- Pre-fetched existing-issue lists for dedup:
/tmp/audit-issues.txt(19 entries),/tmp/techdebt-issues.txt(21),/tmp/security-issues.txt(30) → 69 unique titles. - Orchestrator ran cargo-audit directly (lesson Add deep-review skill for iterative code review #5). Clean vs CI ignore list (8 RUSTSEC IDs already tracked [DEP-01] rustls-webpki 0.103.10 has 3 open RUSTSEC advisories (name-constraint bypass + CRL panic) #223 [DEP-02] Three concurrent
randmajor versions + RUSTSEC-2026-0097 across all of them #246 [DEP-03] Workspace uses unmaintainedbincode 1.3for on-wire + on-disk serialization #247 [DEP-08] Unmaintainedpaste 1.0.15(RUSTSEC-2024-0436) — not in CI ignore list #316 [DEP-09] Unmaintainedproc-macro-error 0.4.12(RUSTSEC-2024-0370) — not in CI ignore list #317 [DEP-10] Unmaintainedatomic-polyfill 1.0.3(RUSTSEC-2023-0089) — not in CI ignore list #318). - Direct main-context sweeps for:
unsafe,dbg!/eprintln!/todo!/unimplemented!,Arc<Mutex>/Arc<RwLock>w/o lock-ok,panic!/unwrapin lib prod,js_sys::eval/innerHTML,TODO/FIXME/HACK,anyhow::in pure libs, vector caps in wire types,let _ = h.<method>().awaitswallow, swallowed errors in new code, docker pin/USER hardening. - Diff @ 00aa515..958e1ec: 37 commits / ~20 PRs / 52 files / +3525 −319. Touches: state caps (SEC-V-07 RotateChannelKey + Event.deps + per-author pending), relay TopicAnnounce caps, agent ReadOnly join-links gate (AUD-2 from general-audit: main @ 00aa515 (2026-04-27) #437 — fixed by fix(agent): readonly scope must deny join_links resource #450), state_bridge SAFETY comment (AUD-1 from general-audit: main @ 00aa515 (2026-04-27) #437 — fixed by docs(web): SAFETY comment for DerivedStateActor #445), service_worker_bridge extracted from main.rs w/ kind discriminator + module-local stash (issue [SEC-W-06] Service-worker
postMessagepayload accepted withoutkind/ origin check #244), invite topic-format validate, web error toast plumbing in handlers.rs ([GEN-07] All UI action handlers swallow errors with no toast / log #350), platform-aware key paths (chore(workers): platform-aware default paths #439), docker pin-by-digest + USER drop (DEP-02), workers untouched at root (chore(docker): drop root, run containers as willow user #434), in-browser test additions (+457 LOC), static_assets test (+164 LOC).
Concerns audited
| Concern | Method | Result |
|---|---|---|
| security: input-validation/DoS | direct | strong (caps verified) |
| security: auth/permissions | direct | strong (AUD-2 closed) |
| security: web/WASM | direct | strong; F2 found |
| security: deps/supply-chain | orchestrator (cargo audit) | clean vs ignore; F1 found |
| tech debt | direct | stable; existing trackers cover (#332 #320–#330) |
| architecture (spec drift) | direct | lock-ok comments still compliant w/ docs/specs/2026-04-26-state-management-model-design.md |
| general | direct | F2 |
| test coverage | direct sample | new tests landed alongside new code; existing tracker #418 #340 #341 covers gaps |
Strong areas (re-verified, no findings)
- state crate purity: zero
tokio/iroh/std::fs/SystemTime(rg "tokio::|std::fs|SystemTime|iroh::" crates/state/srcstill clean) - wire deserialize defense-in-depth:
MAX_DESER_SIZE = 256 KB+ per-variantWireMessage::max_size - event-DAG insert: signature + content-hash + new caps (
MAX_EVENT_DEPS = 64,MAX_ENCRYPTED_KEY_BYTES = 128) - pending-buffer cap: 10k total + per-author sub-cap (
max_entries / N— landed in5b78e61) - relay caps:
MAX_TOPICS = 10_000,MAX_TOPIC_LEN = 256,MAX_TOPICS_PER_ANNOUNCE = 64,MAX_TOPICS_PER_SIGNER = 100,MAX_CONCURRENT_BOOTSTRAP_CONNECTIONS = 1024,BOOTSTRAP_IO_TIMEOUT = 5s,BOOTSTRAP_DRAIN_BUFFER_CAP = 8 KiB - agent scope gate:
TokenScope::ReadOnly | Messagingdenywillow://server/join-links(AUD-2 closed via fix(agent): readonly scope must deny join_links resource #450; new e2e test asserts filter pipeline matches gate) - state_bridge SAFETY comment: documents
Sendinvariant forDerivedStateActor(AUD-1 closed via docs(web): SAFETY comment for DerivedStateActor #445) - service worker bridge:
kinddiscriminator + module-localRefCellstash (no globalwindow.__willowLastPush— closes [SEC-W-06] Service-workerpostMessagepayload accepted withoutkind/ origin check #244) - invite topic validation:
topic_matches_serverenforces{server_id}/prefix +MAX_TOPIC_LEN = 256+MAX_INVITE_CHANNELS = 1000(closes earlier topic-confusion concern) - platform-aware default key paths in
replay/storagemain.rs(dirs::config_dir()w//etc/willowfallback) - docker images: digest-pinned
rust:1.95-slim-bookworm+nginxinc/nginx-unprivileged:1.27-alpine, all containersUSER willow/USER nginx(closes DEP-02 + chore(docker): drop root, run containers as willow user #434) - lock-ok comments present on every legitimate lib-crate lock; new
client/src/{lib.rs,listeners.rs,mutations.rs}sites annotated - no
unimplemented!()/todo!()/dbg!()/eprintln!()/FIXME/HACKin lib code - web
js_sys::evalsites: 1 user-input-interpolated ([WS-1] Web: js_sys::eval(format!()) for pinned-message scroll uses band-aid sanitization #425 [WS-1] tracked), rest static-string (window.__WILLOW_RELAY_URLread,setTimeoutfocus shim) — no new XSS surface
Findings (2 child issues)
| # | Sev | Title |
|---|---|---|
| F1 | low | Docker web.Dockerfile installs trunk unpinned — sibling of closed #319 (different scope: docker pipeline, not deploy.yml) |
| F2 | medium | 11 web component handlers swallow client mutation errors w/ let _ = h.<method>().await — sibling of closed #350 (different scope: components/, not handlers.rs) |
Existing-issue overlap (not re-filed)
- AUD-1 (state_bridge SAFETY) → fixed by docs(web): SAFETY comment for DerivedStateActor #445 ✓
- AUD-2 (agent ReadOnly join-links) → fixed by fix(agent): readonly scope must deny join_links resource #450 ✓
- WS-1 (web
js_sys::eval(format!())for pinned scroll) → [WS-1] Web: js_sys::eval(format!()) for pinned-message scroll uses band-aid sanitization #425 - TD-14 (
anyhowin lib crates) → [TD-14] anyhow used in 8 library crates contradicts CLAUDE.md convention #332 - SEC-V-06 (TopicAnnounce caps) → [SEC-V-06]
TopicAnnounce.topics: Vec<String>has no element-count cap; enables relay CPU amplification + topic-slot exhaustion #235 (landed via 3ee8a98) - SEC-V-07 (Event.deps + RotateChannelKey caps) → [SEC-V-07]
RotateChannelKey.encrypted_keys+Event.depsvectors have no element caps #236 (landed via 7ee7e0a) - DEP-02 (docker pin) → [DEP-02] Docker images use unpinned
rust:latest/rust:slim/nginx:alpinetags #313 (landed via c479670) - TD-08 (storage clock) → fixed via 87c1648
- All cargo-audit warnings → [DEP-01] rustls-webpki 0.103.10 has 3 open RUSTSEC advisories (name-constraint bypass + CRL panic) #223 [DEP-02] Three concurrent
randmajor versions + RUSTSEC-2026-0097 across all of them #246 [DEP-03] Workspace uses unmaintainedbincode 1.3for on-wire + on-disk serialization #247 [DEP-08] Unmaintainedpaste 1.0.15(RUSTSEC-2024-0436) — not in CI ignore list #316 [DEP-09] Unmaintainedproc-macro-error 0.4.12(RUSTSEC-2024-0370) — not in CI ignore list #317 [DEP-10] Unmaintainedatomic-polyfill 1.0.3(RUSTSEC-2023-0089) — not in CI ignore list #318
Dropped findings (verified false during 2nd-pass grep)
None. Both surviving findings re-grep-verified before file:
- F1:
grep -n 'cargo install trunk' docker/web.Dockerfile→ 1 hit,.github/workflows/deploy.ymlalready uses pinnedtaiki-e/install-action@cf525cb...trunk@0.21.14 - F2:
rg -n "let _ = h\.[a-z_]+\(.*\)\.await" crates/web/src/components/→ 11 hits acrossroles.rs(4),channel_sidebar.rs(4),settings.rs(2),sync_queue_view.rs(1)
Method change vs #437
- Agents launched: 0 (same as general-audit: main @ 00aa515 (2026-04-27) #437)
- Findings filed: 2 child + 1 master + 1 lessons = 4 issues (same shape as general-audit: main @ 00aa515 (2026-04-27) #437)
- Time-to-finding: minutes
- Diff was bigger (52 vs 4 files) but orchestrator-direct still scaled — lesson-2 threshold (50 files) held up.
Lessons follow-up issue describes outcome.
Activity