Repository navigation
Description
Finding (from PR review, never addressed)
World journal replication serves a world's complete journal to any Iroh peer that supplies a nonzero session nonce — no capability, membership, or admin credential is checked before the journal is opened and streamed. Omitting world even selects the default world. This bypasses the capability validation used for the existing records replication path and exposes journaled chat, inputs, and host events to nonmembers.
Raised independently by two reviewers on PR #4589:
- Codex (P1), 2026-11-02T21:31:55Z: feat(id): serve signed world journal replication (#806 phase 2) #4589 (comment) — "Authorize replication before exposing the journal" (
pkgs/id/src/world_replication_net.rs:114) - CodeRabbit (Major, Security & Privacy), 2026-11-02T21:37:25Z: feat(id): serve signed world journal replication (#806 phase 2) #4589 (comment) — after
ensure_nonce,serve_streamcallshub.lease(request.world.as_deref(), None)andreplication_feed(); neither checks the peer's identity or credentials; the nonce only rejects an all-zero value;REPLICATION_ALPNis also registered without an access policy (pkgs/id/src/commands/serve.rs:1145-1157). The participant projection hides chat and zeroes seeds for/id-world/1, but this stream sends raw journal bytes without that projection.
No-response evidence
- PR feat(id): serve signed world journal replication (#806 phase 2) #4589 (feat(id): serve signed world journal replication, id: F12.13 journal replication (read replicas over a signed stream) #806 phase 2) had a single commit; both comments predate the merge (merged 2026-11-02T22:21:20Z as-is).
- All 12 review threads on PR feat(id): serve signed world journal replication (#806 phase 2) #4589 are unresolved (GraphQL
reviewThreads, checked 2026-11-03); there are no replies to either comment.
Still live on current main (verified 2026-11-03 via gh api raw reads)
pkgs/id/src/world_replication_net.rs on main: serve_stream calls ensure_nonce(&request.session_nonce)? (:109), then hub.lease(request.world.as_deref(), None) (:110-113), then replication_feed() (:114) — still no authorization check between the nonce check and opening the feed.
Acceptance criteria
- Replication requires an authorized read credential/capability before the lease/feed is opened; unauthorized peers are rejected before any journal bytes are sent.
- A regression test covers an unauthorized peer being refused (including the default-world case when
worldis omitted). - Or: a documented decision on this issue explaining why unauthenticated replication is acceptable, with the exposure stated explicitly.
Found by the pr-comment-review job from an unaddressed PR review comment.
Activity
dezren39 commentedon Nov 3, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 3, 2026
🤖 Agent note · triage verdict: CONFIRMED
Verdict: CONFIRMED live on current main (
developing-today/codemain @22fd4a37aeeb, re-read fresh viagh apiraw contents this shift — an independent re-verification, not a copy of the packet):pkgs/id/src/world_replication_net.rsserve_stream::109ensure_nonce(&request.session_nonce)?— andensure_nonce(:181-186) rejects only an all-zero nonce.:110-113hub.lease(request.world.as_deref(), None),:114replication_feed(), after which the full snapshot and live tail stream to the peer.ReplicationRequest(:37-43) carries exactly two fields —world: Option<String>andsession_nonce— no credential, capability, or token field exists to check.remote_id/peer-identity use anywhere in the handler path), so there is nothing to authorize against even if a check were added downstream.WorldHub::lease(pkgs/id/src/world_hub.rs:503-517): the second parameter is an admin token that only gates creating a not-yet-existing world (create = admin.is_some_and(...)); for an existing world, naming it suffices — the hub's own test comment at:1001states "Once it exists, anyone may name it". PassingNonefrom the replication path therefore opens any existing world, and omittingworldselects the default world./id-world/1path applies capability validation and a participant projection (chat hidden, seeds zeroed); this stream sends raw journal bytes with neither.Disposition: this is a genuine P1 — unauthenticated disclosure of journaled chat, inputs, and host events to any peer that can reach the endpoint and name (or omit) a world. No documented-decision rationale exists on this issue or PR #4589. A fix task implementing issue #4723's acceptance criteria (authorized read credential/capability checked before the lease/feed opens; regression test for an unauthorized peer, including the omitted-world default case) has been enqueued from this triage.
18 remaining items
developing-today commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 50 (priority/high). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03
dezren39 commentedon Nov 4, 2026
agent-note:v1
event: picked_up
task: 7565 (repo-health-code-pilot; worker repo-worker-code; OpenChamber scheduled lane 335a5d1f-bfc1-4831-99ea-850c8939a727)
state: claimed for current-state triage.
verified: #4723 remains OPEN. Source PR #4589 is MERGED as-is. The fix path is already owned: PR #4744 (
fix/4723-world-replication-read-capability) is OPEN and authored by Drew; prior queue triage records fix task 6712 as its owner. I will not touch or duplicate that PR/task.next: record the fresh triage verdict and keep #4723 open until the existing authorization fix merges.
dezren39 commentedon Nov 4, 2026
Triage verdict — confirmed, fix already in canonical PR
Fresh check (2026-11-04): #4723 remains OPEN and the finding is still live on
main. A fresh read ofpkgs/id/src/world_replication_net.rsshowsserve_streamrunsensure_nonce, then openshub.lease(request.world.as_deref(), None), thenreplication_feed(); no authorization occurs before the journal feed opens. The source PR #4589 is MERGED as-is.Severity: P1 data disclosure. The raw replication stream exposes unprojected world-journal entries; the default-world case is reachable when
worldis omitted. The previously recorded fix decision remains appropriate: require the hub admin credential before resolving the lease/feed, rather than reusing participant capabilities that apply only to the projected records path.Existing fix path; no parallel work: PR #4744 (
fix(id): authorize raw world replication feed) is OPEN, authored by Drew, and its description matches the acceptance criteria: bounded admin credential checked beforehub.lease, omitted-world unauthorized-peer regression, and credential redaction. Queue fix task 6712 is alreadydonewith that PR as its outcome. This lane has not touched the PR or created duplicate work.Merge-validation gap to resolve on the owning PR: fresh
gh pr checksshows only CodeRabbit passing. The PR body notes.github/workflows/id-check.ymllacks apull_requesttrigger, so the id-crate PR checks did not run; local focused tests are recorded in the PR body but do not replace the missing CI coverage.Disposition: this triage is complete; leave #4723 OPEN until #4744 merges and required validation is satisfied. No new follow-up task filed.
dezren39 commentedon Nov 4, 2026
agent-note:v1
event: triaged
task: 7565 (repo-health-code-pilot; worker repo-worker-code; OpenChamber scheduled lane 335a5d1f-bfc1-4831-99ea-850c8939a727)
state: triage complete; #4723 remains OPEN pending the existing fix PR.
verified: current main still lacks authorization before the raw journal feed opens; canonical fix PR #4744 is OPEN and Drew-authored; its queue task 6712 is already done. Only CodeRabbit currently passes; id-check CI did not run.
next: owning PR lane resolves required CI coverage, then merge #4744; no parallel task filed.