security: verify WorkerAnnouncement peer_id matches signer (#144)#151
Merged
Conversation
`parse_worker_message` previously discarded the verified Ed25519 signer
returned by `unpack_wire` and silently dropped `Announcement` and
`Departure` messages. While the Worker arm is still a no-op pending
WorkerCache integration, an unverified self-declared `peer_id` is a
trust bug: any signer could forge announcements (poisoning a
recipient's WorkerCache) or departures (evicting legitimate workers)
on behalf of a different peer.
Capture the signer from `unpack_wire`, compare it against the inner
`peer_id` for `Announcement` and `Departure`, and surface a new
`WorkerMessageAction::PeerIdMismatch { signer, claimed, kind }`
variant. The network actor logs the rejection at warn level with
both peer IDs so audit logs distinguish a *verified* drop from a
silent one. Genuine messages still parse to `Ignore` so the no-op
behavior is preserved until WorkerCache lands.
Add unit tests using real Ed25519 keypairs:
- happy path: signer == announcement.peer_id → accepted (Ignore)
- sad path: signer != announcement.peer_id → rejected (PeerIdMismatch)
- both paths covered for Announcement and Departure variants.
Closes #144.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 task
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
parse_worker_messagenow verifies the innerpeer_idofWorkerAnnouncementandWorkerWireMessage::Departureagainstthe Ed25519 signer returned by
unpack_wire.WorkerMessageAction::PeerIdMismatch { signer, claimed, kind }variant; the network actor logsthe rejection at
warnlevel (signer + claimed peer + kind).Ignoreso the existing no-opbehavior of the Worker arm is preserved until
WorkerCacheintegration lands — but it's now a verified drop, not a
silent one.
Threat addressed
Without this check, any signer on the
_willow_workerstopiccould forge:
WorkerAnnouncementfor a different peer → poison a recipient'sWorkerCache(when integrated) by impersonating an arbitraryworker's role/server list.
Departure { peer_id }for a different peer → silently evicta legitimate worker from a recipient's cache.
The Ed25519 signature already proved who sent the envelope; this
PR ties the self-declared identity inside the message to that
proven sender.
Found by security audit of fix/issue-108-final (#144).
Test plan
cargo test -p willow-worker --lib actors::network— 17/17 pass.just check(fmt + clippy + workspace tests + WASM check) — clean.parse_worker_announcement_ignored_when_peer_id_matches_signertest covers the happy path (real Ed25519 keypair,
pack_wire→parse_worker_message→Ignore).parse_worker_announcement_rejected_when_peer_id_mismatches_signertest covers the sad path and asserts the reported
signer,claimed, andkindfields.Departure.unsigned_bytes_rejected,non_worker_wire_message_ignored,and the request-path tests still pass — no behavior regression for
Request/Responseflows.Closes #144.
Generated with Claude Code