fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 - #3128
Merged
Conversation
`ingest_event`'s durable write-path restriction gate exempts relay-admin kinds 9030-9033 so a *timed out* admin keeps its administrative capability. That exemption was ban-blind, and `handle_relay_admin_event` performed no restriction check of its own, so a **banned** admin or owner could still add/remove relay members, change member roles, and set the workspace icon via signed NIP-98 `POST /events` — including planting new members into `relay_members`, the table `moderation_authz` derives moderator capability from. Same class as BUZZ-SEC-007, which closed the equivalent hole for moderation command kinds 9040-9044 but left the relay-admin range open. Fix: enforce the ban inside `handle_relay_admin_event`, matching the `moderation_commands.rs` precedent, rather than dropping the ingest exemption — dropping it would also block timed-out admins and silently change policy. `handle_relay_admin_event` becomes a thin admission wrapper around the unchanged command body, so no future early return inside that body can precede the check. The refusal category is part of the security contract, so the handler now returns a typed `RelayAdminError` that ingest maps exhaustively: Banned -> AuthFailed "blocked: ..." / HTTP 403 Rejected -> Rejected "invalid: ..." / HTTP 400 (unchanged) Internal -> Internal "error: ..." / HTTP 500 Without the typed error a `blocked:` string would have kept the wire text but downgraded the status to 400, and a restriction-lookup outage would have been reported as a client-side bad request. The admission decision is a pure function over `RestrictionState` so banned/timed-out/clean are covered by the default test suite; that coverage is non-vacuous by mutation (neutering the helper body fails `banned_actor_is_not_admitted_to_a_relay_admin_command`). It does not prove handler wiring: the `#[ignore]`d live HTTP regression test is what checks linkage, proving all four exempt kinds are refused 403 over the real transport with no member/role/icon mutation. The 500 fail-closed path on a restriction-lookup outage was proven separately by manual fault injection (renaming `community_bans.banned` under the running relay), not by the committed test. Scope: relay-admin kinds only. Command kinds dispatched before the gate (e.g. 41010) are a separate instance of this class and are not addressed here. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Brings the branch up to `00ecf2c` before review. No conflicts: this branch touches `handlers/ingest.rs`, `handlers/relay_admin.rs`, and `tests/regression_relay_admin_ban_gate.rs`; none are modified by the eight incoming commits. Closest incoming change is `00ecf2c` "fix(security): authorize kind:9000 role changes in both directions", which hardens NIP-29 *channel* membership authorization in `buzz-db/src/channel.rs` and `handlers/side_effects.rs`. Disjoint from this fix, which gates NIP-43 *relay-admin* kinds 9030-9033 on the durable community ban. Different kinds, different tables, different call paths. * origin/main: fix(security): authorize kind:9000 role changes in both directions (#3017) feat(desktop): handle project work from Inbox (#3117) fix(desktop): clarify identity key button when key exists (#2357) Restore Goose and Buzz Agent to onboarding harness selection (#2731) fix(mobile): mitigate message-post delay with optimistic rendering (#3037) fix(desktop): render rich project work item content (#3100) chore(deps): update radix-ui-primitives monorepo (#3063) chore(deps): update dependency @tanstack/react-virtual to v3.14.8 (#3057) Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
The NIP-44 v2 decryption path in `nostr` reads a 2-byte unpadded-length prefix via `buffer[0..2]` without first checking the decrypted buffer holds 2 bytes. A sender holding the conversation key can craft a payload that decrypts to 0 or 1 bytes and panic the receiver — a remote DoS reachable through any relay that delivers the event. No key material or plaintext is exposed. Affects 0.26.0 through 0.44.4; fixed in 0.44.5. Lockfiles only. The manifest already declares `nostr = "0.44"`, so 0.44.6 is inside the existing range and no `Cargo.toml` edit is needed. Both lockfiles are bumped: Cargo.lock 0.44.3 -> 0.44.6 desktop/src-tauri/Cargo.lock 0.44.4 -> 0.44.6 The desktop lockfile matters and is easy to miss: `desktop/src-tauri` is excluded from the root workspace (Cargo.toml:31), so the `Security` CI job — which runs `cargo-deny check` at the repo root — never sees it. It pinned a vulnerable, yanked 0.44.4 that no check would have caught. Desktop calls `nip44::decrypt` in `commands/identity.rs:495`. Not optional maintenance: 0.44.0 through 0.44.4 are all yanked on crates.io. 0.44.5 and 0.44.6 are the only live versions in range. The desktop lockfile also repoints two existing dependency edges (`syn 2.0.118` -> `1.0.109` for nostr-derive, `getrandom 0.4.3` -> `0.3.4` for tempfile). No packages are added or removed — both versions were already in the graph — and the resolution is stable across repeated re-resolves. Verified at this commit: `cargo-deny check advisories` reports `advisories ok` (was `advisories FAILED` on the same tree before the bump), and `./scripts/run-tests.sh unit` passes all five packages. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
wpfleger96
pushed a commit
that referenced
this pull request
Jul 27, 2026
…DoS) (#3135) ## Summary `cargo-deny` started failing on **every** PR and on `main` when **RUSTSEC-2026-0216** was published mid-afternoon today. Nothing in the tree changed — cargo-deny fetches the advisory DB at run time, so main's own `Security` job passed at `00ecf2c` and then began failing on the same commit. ``` error[vulnerability]: Remote Denial of Service via malformed NIP-44 v2 payload Cargo.lock:432 nostr 0.44.3 — RUSTSEC-2026-0216 advisories FAILED, bans ok, licenses ok, sources ok ``` The `nostr` NIP-44 v2 decrypt path reads a 2-byte unpadded-length prefix via `buffer[0..2]` **after** the HMAC check passes, without verifying the decrypted buffer holds 2 bytes. A sender who holds the conversation key — i.e. any DM sender — can craft a payload that decrypts to 0 or 1 bytes and panic the receiver. Remote DoS through any relay that delivers the event. No key material, plaintext, or memory corruption. Affects `0.26.0` through `0.44.4`. Fixed in `0.44.5`. ## The change Lockfiles only, 6 insertions / 6 deletions. The manifest already declares `nostr = "0.44"` — a caret range — so `0.44.6` needs no `Cargo.toml` edit. | Lockfile | Before | After | |---|---|---| | `Cargo.lock` | 0.44.3 | 0.44.6 | | `desktop/src-tauri/Cargo.lock` | **0.44.4** | 0.44.6 | **The desktop lockfile is the part worth reviewing.** `desktop/src-tauri` is excluded from the root workspace (`Cargo.toml:31`), and the `Security` job runs `cargo-deny check` at the repo root — so it never sees that lockfile. It was pinning a vulnerable *and* yanked `0.44.4` that no CI check would ever have flagged. Desktop calls `nip44::decrypt` at `commands/identity.rs:495`. Credit to @eva for catching this; I'd have shipped the root-only fix and left it sitting there. **This isn't optional maintenance.** `0.44.0` through `0.44.4` are all yanked on crates.io. `0.44.5` and `0.44.6` are the only live versions in our range — staying put isn't an available option. ### On the two extra lines in the desktop lockfile The desktop bump also repoints two existing dependency edges: ``` nostr-derive: syn 2.0.118 -> syn 1.0.109 tempfile: getrandom 0.4.3 -> getrandom 0.3.4 ``` I checked these rather than waving them through: **no packages are added or removed** — both versions were already present in the graph, so only which edge points where changed. The resolution is stable across repeated re-resolves, and a plain re-resolve without the bump produces zero diff, so this isn't pre-existing lockfile staleness leaking in. ## Verification At this commit, in a clean worktree off `origin/main`: - `cargo-deny check advisories` → **`advisories ok`**, exit 0. The same tree before the bump reported `advisories FAILED` with this advisory, so the check is doing real work, not passing vacuously. - `./scripts/run-tests.sh unit` → all five packages pass. - `cargo test -p buzz-core` 229/229, `-p buzz-cli` 250/250, `-p buzz-relay --lib` 750 pass / 1 fail — the sole failure `api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo` is pre-existing and reproduces identically at unmodified `00ecf2c`. - `desktop-tauri-test` passed in the pre-push hook, which exercises the crate whose lockfile changed. ## Why not a `deny.toml` ignore Considered and rejected. This is a reachable panic triggerable by any DM sender, and buzz-acp agents decrypt DMs from arbitrary senders. Suppressing it would ship a live remote-DoS to every agent and client in order to make a dashboard green. ## Note on `spin` The yanked `spin 0.9.8` / `0.10.0` warnings in the same job are **not** what fails CI — the log has exactly one hard error, this one. They're `warning[yanked]`, and warnings don't fail the build. `spin` is also three levels transitive (`mesh-llm-host-runtime → mdns-sd → flume → spin`) under a dev-dependency, so it isn't ours to bump. Left alone deliberately. ## Follow-up Unblocks #3128 (relay-admin ban gate), which has a zero dependency-file delta and will inherit this cleanly once main is merged in. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub1jmc9dt2lyvzu3h0kxlwxt5zg4fxp9476awyxw6gwxn72g6cw7exqs64whm <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
wpfleger96
added a commit
to bcrdejong/buzz
that referenced
this pull request
Jul 27, 2026
* origin/main: (22 commits) feat(mobile): bring message actions to desktop parity (block#3070) feat(git): use agent display name as git author name (block#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (block#3128) chore(deps): update react monorepo to v19.2.8 (block#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (block#3135) docs(contributing): set PR expectations and require UI screenshots (block#3140) fix(desktop): read the newest pair-scoped harness log (block#3134) fix(security): authorize kind:9000 role changes in both directions (block#3017) feat(desktop): handle project work from Inbox (block#3117) fix(desktop): clarify identity key button when key exists (block#2357) Restore Goose and Buzz Agent to onboarding harness selection (block#2731) fix(mobile): mitigate message-post delay with optimistic rendering (block#3037) fix(desktop): render rich project work item content (block#3100) chore(deps): update radix-ui-primitives monorepo (block#3063) chore(deps): update dependency @tanstack/react-virtual to v3.14.8 (block#3057) feat(acp): bring your own harness (BYOH) — generic ACP runtime seam + settings gallery (block#2773) feat(desktop): use collective mesh routing for Auto (block#2825) fix(desktop): strip legacy baked team instructions from stored prompts (block#3035) Refine mobile community switching and discovery (block#2967) feat(agents): lower default agent parallelism from 24 to 10 (block#3038) ...
Merged
tellaho
pushed a commit
that referenced
this pull request
Jul 27, 2026
* origin/main: feat(desktop): add search to agent emoji picker (#2630) fix(desktop): keep identity key help dialog readable in dark mode (#2854) feat(acp): title agent sessions from the agent and channel name (#3028) feat(mobile): bring message actions to desktop parity (#3070) feat(git): use agent display name as git author name (#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (#3128) chore(deps): update react monorepo to v19.2.8 (#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (#3135) docs(contributing): set PR expectations and require UI screenshots (#3140) fix(desktop): read the newest pair-scoped harness log (#3134) fix(security): authorize kind:9000 role changes in both directions (#3017) feat(desktop): handle project work from Inbox (#3117) fix(desktop): clarify identity key button when key exists (#2357) Restore Goose and Buzz Agent to onboarding harness selection (#2731) fix(mobile): mitigate message-post delay with optimistic rendering (#3037) fix(desktop): render rich project work item content (#3100) chore(deps): update radix-ui-primitives monorepo (#3063) chore(deps): update dependency @tanstack/react-virtual to v3.14.8 (#3057) Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
wpfleger96
added a commit
to SeanGearin/buzz
that referenced
this pull request
Jul 27, 2026
* origin/main: (102 commits) chore(desktop): add AgentCreationPreview file-size override to unblock main CI (block#3154) fix(cli,relay): resolve agents by verified owner (block#2615) fix(desktop): make the test loader work on Windows (block#2758) fix(desktop): make lint and unit-test gates work on Windows (block#2943) feat(mobile): refactor Activity behavior and ui (block#2889) feat(desktop): add search to agent emoji picker (block#2630) fix(desktop): keep identity key help dialog readable in dark mode (block#2854) feat(acp): title agent sessions from the agent and channel name (block#3028) feat(mobile): bring message actions to desktop parity (block#3070) feat(git): use agent display name as git author name (block#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (block#3128) chore(deps): update react monorepo to v19.2.8 (block#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (block#3135) docs(contributing): set PR expectations and require UI screenshots (block#3140) fix(desktop): read the newest pair-scoped harness log (block#3134) fix(security): authorize kind:9000 role changes in both directions (block#3017) feat(desktop): handle project work from Inbox (block#3117) fix(desktop): clarify identity key button when key exists (block#2357) Restore Goose and Buzz Agent to onboarding harness selection (block#2731) fix(mobile): mitigate message-post delay with optimistic rendering (block#3037) ...
wpfleger96
added a commit
to SeanGearin/buzz
that referenced
this pull request
Jul 27, 2026
* origin/main: (102 commits) chore(desktop): add AgentCreationPreview file-size override to unblock main CI (block#3154) fix(cli,relay): resolve agents by verified owner (block#2615) fix(desktop): make the test loader work on Windows (block#2758) fix(desktop): make lint and unit-test gates work on Windows (block#2943) feat(mobile): refactor Activity behavior and ui (block#2889) feat(desktop): add search to agent emoji picker (block#2630) fix(desktop): keep identity key help dialog readable in dark mode (block#2854) feat(acp): title agent sessions from the agent and channel name (block#3028) feat(mobile): bring message actions to desktop parity (block#3070) feat(git): use agent display name as git author name (block#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (block#3128) chore(deps): update react monorepo to v19.2.8 (block#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (block#3135) docs(contributing): set PR expectations and require UI screenshots (block#3140) fix(desktop): read the newest pair-scoped harness log (block#3134) fix(security): authorize kind:9000 role changes in both directions (block#3017) feat(desktop): handle project work from Inbox (block#3117) fix(desktop): clarify identity key button when key exists (block#2357) Restore Goose and Buzz Agent to onboarding harness selection (block#2731) fix(mobile): mitigate message-post delay with optimistic rendering (block#3037) ...
wpfleger96
added a commit
to jatinder14/buzz
that referenced
this pull request
Jul 27, 2026
* origin/main: (22 commits) chore(desktop): add AgentCreationPreview file-size override to unblock main CI (block#3154) fix(cli,relay): resolve agents by verified owner (block#2615) fix(desktop): make the test loader work on Windows (block#2758) fix(desktop): make lint and unit-test gates work on Windows (block#2943) feat(mobile): refactor Activity behavior and ui (block#2889) feat(desktop): add search to agent emoji picker (block#2630) fix(desktop): keep identity key help dialog readable in dark mode (block#2854) feat(acp): title agent sessions from the agent and channel name (block#3028) feat(mobile): bring message actions to desktop parity (block#3070) feat(git): use agent display name as git author name (block#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (block#3128) chore(deps): update react monorepo to v19.2.8 (block#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (block#3135) docs(contributing): set PR expectations and require UI screenshots (block#3140) fix(desktop): read the newest pair-scoped harness log (block#3134) fix(security): authorize kind:9000 role changes in both directions (block#3017) feat(desktop): handle project work from Inbox (block#3117) fix(desktop): clarify identity key button when key exists (block#2357) Restore Goose and Buzz Agent to onboarding harness selection (block#2731) fix(mobile): mitigate message-post delay with optimistic rendering (block#3037) ...
tlongwell-block
added a commit
that referenced
this pull request
Jul 27, 2026
Fixes all six HIGH findings from the buzz security report, one commit per finding. Independently reviewed to approval by Max at `0158ae542`, plus a deep isolated live pass (clean-room compose stack, weird ports, full product matrix) at the same head — see the buzz-security thread for evidence. `fe65c07c3` merges current `origin/main` on top (new commit, no rebase), inheriting the nostr 0.44.6 bump (#3135) and relay-admin ban gate (#3128). ## Findings and fixes | Finding | Commit | Fix | |---|---|---| | 003 — quinn-proto RUSTSEC-2026-0185 | `e5dcdec72` | Bump quinn-proto 0.11.14 → 0.11.16 (lockfile-only) | | 002/004 — linkify-it quadratic-parse DoS (GHSA-22p9-wv53-3rq4, GHSA-v245-v573-v5vm) | `923b3c20f` | pnpm override `linkify-it: ^5.0.2`; `pnpm why` confirms a single 5.0.2 copy | | 001 — media reads served unauthenticated by default | `0f277e3e2` | Helm `requireMediaGetAuth` defaults to `true` + rendered-chart test pinning the default | | 006 — removed workflow owners retain webhook-exfiltration authority | `4749bd56c` | Fail-closed per-fire authority gate (current owner/admin membership) on **all four** trigger doors (on_event, scheduler pre-claim, manual trigger, webhook — masked as generic 404), save-time gate for `call_webhook` defs, durable disable-on-removal wired to kinds 9001 + 9022 | | 005 — git Smart-HTTP reads ignore channel membership | `e648f2dba` + `0158ae542` | `authorize_git_read`: caller's **current active membership** in the repo's bound channel, checked before any hydration/subprocess on all three read doors (`info_refs` for both services + `upload_pack` POST). Uniform generic 404 denials (no membership probing), no repo-owner bypass, first-`buzz-channel`-tag binding semantics fail closed on ambiguous duplicates (mutation-verified test). Resolution follows the live kind:30617 announcement, so deleted/replaced announcements deny immediately. The committed `e2e-git-perms.sh` guest scenario previously asserted the vulnerability — now asserts denial. | ## Behavior changes to be aware of 1. **Unbound repos fail closed for git reads.** `buzz repos create` emits no `buzz-channel` tag, so CLI-created repos without a binding are unreadable via git HTTP. Correct per finding 005's fail-closed posture; a follow-up could bind CLI-created repos at creation time. 2. **006 is conservative:** a workflow disabled on owner removal does not auto-re-enable if the owner is re-added — explicit re-enable required. 3. Merge conflict resolution in `fe65c07c3`: kept main's `@radix-ui/react-dismissable-layer` 1.1.19 bump alongside the linkify-it security override (`pnpm-workspace.yaml` + lockfile). ## Verification at the merge head `fe65c07c3` (same shell) - buzz-relay `--lib`: 761 passed / 1 failed — the lone red is the known pre-existing `mesh_demo::demo_join_forwarded_arm_round_trips_echo` 504 flake, present on main - SEC-005 module incl. PG behavioral matrix: 8/8 (removed-member, never-member, owner-no-bypass, deleted-30617, malformed/ambiguous binding, owner-mismatch all denied) - buzz-workflow 153/0, buzz-db 84/0; `clippy --all-targets -D warnings` + `fmt --check` clean - Desktop JS 3637/3637, tsc clean, biome clean, file-size/px-text/pubkey-truncation gates clean - `helm lint` + `helm unittest` (40/40) on `deploy/charts/buzz` - All five pre-push hooks green (desktop-check, desktop-test, rust-tests, desktop-tauri-test, branch-skew) Prior review evidence at `0158ae542` (pre-merge): Max's independent exact-head approval + clean-room live regression pass (`WORK_LOGS/2026-07-27_SECURITY_HIGH_LIVE_TEST.md` in his workspace). Max will re-run the deep local pass at this post-merge head before merge. --------- Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
NYTEMODEONLY
pushed a commit
to NYTEMODEONLY/buzz
that referenced
this pull request
Jul 27, 2026
…DoS) (block#3135) ## Summary `cargo-deny` started failing on **every** PR and on `main` when **RUSTSEC-2026-0216** was published mid-afternoon today. Nothing in the tree changed — cargo-deny fetches the advisory DB at run time, so main's own `Security` job passed at `00ecf2c` and then began failing on the same commit. ``` error[vulnerability]: Remote Denial of Service via malformed NIP-44 v2 payload Cargo.lock:432 nostr 0.44.3 — RUSTSEC-2026-0216 advisories FAILED, bans ok, licenses ok, sources ok ``` The `nostr` NIP-44 v2 decrypt path reads a 2-byte unpadded-length prefix via `buffer[0..2]` **after** the HMAC check passes, without verifying the decrypted buffer holds 2 bytes. A sender who holds the conversation key — i.e. any DM sender — can craft a payload that decrypts to 0 or 1 bytes and panic the receiver. Remote DoS through any relay that delivers the event. No key material, plaintext, or memory corruption. Affects `0.26.0` through `0.44.4`. Fixed in `0.44.5`. ## The change Lockfiles only, 6 insertions / 6 deletions. The manifest already declares `nostr = "0.44"` — a caret range — so `0.44.6` needs no `Cargo.toml` edit. | Lockfile | Before | After | |---|---|---| | `Cargo.lock` | 0.44.3 | 0.44.6 | | `desktop/src-tauri/Cargo.lock` | **0.44.4** | 0.44.6 | **The desktop lockfile is the part worth reviewing.** `desktop/src-tauri` is excluded from the root workspace (`Cargo.toml:31`), and the `Security` job runs `cargo-deny check` at the repo root — so it never sees that lockfile. It was pinning a vulnerable *and* yanked `0.44.4` that no CI check would ever have flagged. Desktop calls `nip44::decrypt` at `commands/identity.rs:495`. Credit to @eva for catching this; I'd have shipped the root-only fix and left it sitting there. **This isn't optional maintenance.** `0.44.0` through `0.44.4` are all yanked on crates.io. `0.44.5` and `0.44.6` are the only live versions in our range — staying put isn't an available option. ### On the two extra lines in the desktop lockfile The desktop bump also repoints two existing dependency edges: ``` nostr-derive: syn 2.0.118 -> syn 1.0.109 tempfile: getrandom 0.4.3 -> getrandom 0.3.4 ``` I checked these rather than waving them through: **no packages are added or removed** — both versions were already present in the graph, so only which edge points where changed. The resolution is stable across repeated re-resolves, and a plain re-resolve without the bump produces zero diff, so this isn't pre-existing lockfile staleness leaking in. ## Verification At this commit, in a clean worktree off `origin/main`: - `cargo-deny check advisories` → **`advisories ok`**, exit 0. The same tree before the bump reported `advisories FAILED` with this advisory, so the check is doing real work, not passing vacuously. - `./scripts/run-tests.sh unit` → all five packages pass. - `cargo test -p buzz-core` 229/229, `-p buzz-cli` 250/250, `-p buzz-relay --lib` 750 pass / 1 fail — the sole failure `api::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo` is pre-existing and reproduces identically at unmodified `00ecf2c`. - `desktop-tauri-test` passed in the pre-push hook, which exercises the crate whose lockfile changed. ## Why not a `deny.toml` ignore Considered and rejected. This is a reachable panic triggerable by any DM sender, and buzz-acp agents decrypt DMs from arbitrary senders. Suppressing it would ship a live remote-DoS to every agent and client in order to make a dashboard green. ## Note on `spin` The yanked `spin 0.9.8` / `0.10.0` warnings in the same job are **not** what fails CI — the log has exactly one hard error, this one. They're `warning[yanked]`, and warnings don't fail the build. `spin` is also three levels transitive (`mesh-llm-host-runtime → mdns-sd → flume → spin`) under a dev-dependency, so it isn't ours to bump. Left alone deliberately. ## Follow-up Unblocks block#3128 (relay-admin ban gate), which has a zero dependency-file delta and will inherit this cleanly once main is merged in. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz> Co-authored-by: npub1jmc9dt2lyvzu3h0kxlwxt5zg4fxp9476awyxw6gwxn72g6cw7exqs64whm <96f056ad5f2305c8ddf637dc65d048aa4c12d7daeb8867690e34fca46b0ef64c@buzz.block.builderlab.xyz> Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
jatinder14
pushed a commit
to jatinder14/buzz
that referenced
this pull request
Jul 28, 2026
* origin/main: (22 commits) chore(desktop): add AgentCreationPreview file-size override to unblock main CI (block#3154) fix(cli,relay): resolve agents by verified owner (block#2615) fix(desktop): make the test loader work on Windows (block#2758) fix(desktop): make lint and unit-test gates work on Windows (block#2943) feat(mobile): refactor Activity behavior and ui (block#2889) feat(desktop): add search to agent emoji picker (block#2630) fix(desktop): keep identity key help dialog readable in dark mode (block#2854) feat(acp): title agent sessions from the agent and channel name (block#3028) feat(mobile): bring message actions to desktop parity (block#3070) feat(git): use agent display name as git author name (block#3040) fix(security): enforce durable community ban on NIP-43 relay-admin kinds 9030-9033 (block#3128) chore(deps): update react monorepo to v19.2.8 (block#3064) fix(deps): bump nostr to 0.44.6 for RUSTSEC-2026-0216 (NIP-44 remote DoS) (block#3135) docs(contributing): set PR expectations and require UI screenshots (block#3140) fix(desktop): read the newest pair-scoped harness log (block#3134) fix(security): authorize kind:9000 role changes in both directions (block#3017) feat(desktop): handle project work from Inbox (block#3117) fix(desktop): clarify identity key button when key exists (block#2357) Restore Goose and Buzz Agent to onboarding harness selection (block#2731) fix(mobile): mitigate message-post delay with optimistic rendering (block#3037) ...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ingest_event's durable write-path restriction gate exempts NIP-43 relay-admin kinds 9030–9033, so that a timed-out admin keeps administrative capability. That exemption was ban-blind, andhandle_relay_admin_eventperformed no restriction check of its own. A banned admin or owner could still add members, remove members, change member roles, and set the workspace icon by posting a signed NIP-98 request toPOST /events. No open WebSocket required.Reported externally by Bilal Syed (also filed publicly as #3020 before he read
SECURITY.md). Verified true, reproduced live, and found slightly worse than reported.Same class as BUZZ-SEC-007, which PR #1915 closed for moderation command kinds 9040–9044. That fix was never extended to the 9030 range.
Why it worked
handlers/ingest.rs:1639skipped the restriction check whenis_relay_admin_kind(kind)was true.handlers/relay_admin.rsdid a freshness check and a role lookup only — zero restriction reads in the file.ban_member(buzz-db/src/moderation.rs:314) writes onlycommunity_bans, so therelay_membersadmin row survives.enforce_relay_membershipis a bareSELECT 1 FROM relay_members.Worse than reported: the report covered remove (9031) and icon (9033). Add (9030) works too, so a banned admin can plant new members. That matters because
moderation_authz.rs:163-170derives "an admin cannot ban an owner or fellow admin" fromrelay_members— the very table 9030/9031 mutate. A banned admin could seed accomplices into the roster the ban was meant to stop them touching.Also of note:
moderation_authz.rs:158-165already asserts in a comment that "The command handler separately rejects a banned actor on every transport."relay_admin.rswas the one command handler not holding that invariant.The fix
Enforce the durable ban inside
handle_relay_admin_event— the reporter's own suggested shape, and themoderation_commands.rs:99-108precedent.Deliberately not the one-token alternative of dropping
&& !is_relay_admin_kind(kind_u32)atingest.rs:1639: that would also start blocking timed-out admins, silently changing policy. Bans are refused; timeouts still administer, which is the entire reason the exemption exists.handle_relay_admin_eventbecomes a thin admission wrapper around an unchangedexecute_relay_admin_commandbody, so no future early return inside that body can precede the check. The check therefore also necessarily precedes the freshness check.The refusal category is part of the security contract, so this returns a typed
RelayAdminErrorrather than a string. Ablocked:string would have kept the right wire text but returned 400 instead of 403 (api/bridge.rs:845vs:858), and would have reported a restriction-DB outage as a client error:BannedAuthFailedblocked: you are banned from this communityRejected(..)Rejectedinvalid: …Internal(..)Internalerror: …(sanitized)Verification
Live over real HTTP against an isolated relay, all four exempt kinds refused, DB checked after each for non-mutation:
Victim still
member, planted key absent, role target unchanged, icon still NULL. 9032 required a banned owner to be a real test, since it is owner-only.admits_relay_admin_command(&RestrictionState), covered by the default suite. Neutering it failsbanned_actor_is_not_admitted_to_a_relay_admin_command. The first version of this patch would have stayed green if someone deleted the check — that gap is closed. The unit test does not prove handler wiring; the#[ignore]d live E2E is what checks linkage.community_bans.bannedout from under the running relay yields 500, no mutation, and no schema detail leaked to the client.invalid:/400.cargo fmt --all --check,cargo clippy -p buzz-relay --all-targets -D warnings,buzz-core229/229,buzz-cli250/250,run-tests.sh unitall five packages green.buzz-relay --lib: 756 passed / 1 failed. The sole failureapi::mesh_demo::tests::demo_join_forwarded_arm_round_trips_echo(504 vs 200) is pre-existing — reproduced identically in a detached worktree at merge base00ecf2c.Notes for the reviewer
origin/mainin as a merge commit rather than rebasing, per instruction. No conflicts; the eight incoming commits touch none of the three files here. Closest neighbour is00ecf2c(kind:9000 NIP-29 channel role authz) — disjoint from this NIP-43 relay-admin fix.is_command_kindfires atingest.rs:1561, ~80 lines before the restriction gate, andcommand_executor.rshas no restriction read. Measured live: a banned member can still open a DM (41010 → 200). 41011/41012/30620/46030/46031 unprobed. Needs per-kind semantics enumerated first (reports allowed while banned; moderation commands allow timeouts but reject bans; ordinary writes reject both).moderation_commands.rsmaps its own restriction-DB failure to 400, not 500, and leaks the raw Postgres message to the client.kind:9041, which is unban. The ban is 9040 (KIND_MODERATION_BAN,buzz-core/src/kind.rs:298). Following the steps verbatim yields a false negative.Co-authored-by: Tyler Longwell tlongwell@block.xyz
Signed-off-by: Tyler Longwell tlongwell@block.xyz