Skip to content

general-audit: main @ 958e1ec (2026-04-28) #474

@intendednull

Description

@intendednull

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):

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/src still clean)
  • wire deserialize defense-in-depth: MAX_DESER_SIZE = 256 KB + per-variant WireMessage::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 in 5b78e61)
  • 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 | Messaging deny willow://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 Send invariant for DerivedStateActor (AUD-1 closed via docs(web): SAFETY comment for DerivedStateActor #445)
  • service worker bridge: kind discriminator + module-local RefCell stash (no global window.__willowLastPush — closes [SEC-W-06] Service-worker postMessage payload accepted without kind / origin check #244)
  • invite topic validation: topic_matches_server enforces {server_id}/ prefix + MAX_TOPIC_LEN = 256 + MAX_INVITE_CHANNELS = 1000 (closes earlier topic-confusion concern)
  • platform-aware default key paths in replay/storage main.rs (dirs::config_dir() w/ /etc/willow fallback)
  • docker images: digest-pinned rust:1.95-slim-bookworm + nginxinc/nginx-unprivileged:1.27-alpine, all containers USER 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 / HACK in lib code
  • web js_sys::eval sites: 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_URL read, setTimeout focus 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)

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.yml already uses pinned taiki-e/install-action@cf525cb...trunk@0.21.14
  • F2: rg -n "let _ = h\.[a-z_]+\(.*\)\.await" crates/web/src/components/ → 11 hits across roles.rs (4), channel_sidebar.rs (4), settings.rs (2), sync_queue_view.rs (1)

Method change vs #437

Lessons follow-up issue describes outcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions