Skip to content

security: bind accept/revoke to authenticated identity, gate relayed approval, timestamp-independent replay (PPA-001/002/008) - #28

Closed
TeoSlayer wants to merge 3 commits into
mainfrom
ws5-handshake-hardening
Closed

TeoSlayer wants to merge 3 commits into
mainfrom
ws5-handshake-hardening

Conversation

@TeoSlayer

Copy link
Copy Markdown
Contributor

Closes the handshake findings from the PPA vulnerability register.

  • PPA-001: HandshakeAccept/HandshakeRevoke now require the claimed msg.NodeID to match the authenticated stream identity (stream.RemoteAddr().Node) — an attacker can no longer inject/revoke trust for an arbitrary node_id. Fail-closed on stream == nil. No new wire field.
  • PPA-002: processRelayedApproval drops any relayed approval with no matching outgoing request.
  • PPA-008: replay-set key is now sha256(Type ‖ challenge ‖ Signature) — the mutable, unsigned Timestamp no longer lets a captured signature evade the replay set.

Compat-safe: legitimate P2P Accept/Revoke arrive over the sender's own authenticated stream; only forged/relayed injection is blocked. Full go test ./... green.

🤖 Generated with Claude Code

teovl and others added 3 commits July 23, 2026 23:32
…ending cap, sanitize justification

Rejects HandshakeRequest messages with no pubkey/signature before they enter
the pending queue or auto-trust path. Bounds the pending map per source
(maxPendingPerSource=16) on top of the global cap to limit flood surface.
Sanitizes attacker-controlled justification before display. Adds WS5 flood test.

No enforcement flag is toggled; empty-pubkey reject is unconditional.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…approval, timestamp-independent replay key

Addresses reported vulnerabilities PPA-001/002/008 (replay-set), verified
against source.

- PPA-001: HandshakeAccept/HandshakeRevoke now require the claimed
  msg.NodeID to equal the AEAD-authenticated stream identity
  (stream.RemoteAddr().Node). A forged unsigned accept/revoke for a victim
  node arrives on the attacker's own authenticated stream and is rejected;
  honest accept/revoke (msg.NodeID == own id == authenticated peer) still
  complete. Closes the trust-injection / forced-revoke bypass that reached
  the accept/revoke handlers by choosing a message Type other than Request.
- PPA-002: processRelayedApproval requires a matching outgoing request
  before granting Mutual trust, so an unsolicited relayed approval for a
  peer we never contacted no longer establishes trust.
- PPA-008 (replay-set): the replay/dedup key is derived from
  signature-covered fields plus message Type instead of the full JSON
  (which included the mutable, unsigned Timestamp), so a captured signed
  message re-stamped with a fresh timestamp is caught. Including Type keeps
  a legitimate revoke following a request from being falsely deduped. The
  wire-breaking signed-freshness change (nonce inside the signed preimage)
  is deferred.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@TeoSlayer

Copy link
Copy Markdown
Contributor Author

Superseded — this hardening is already on main (accept/revoke identity binding, relayed-approval gate, timestamp-independent replay key) and shipped in v0.2.3/v0.2.4.

@TeoSlayer TeoSlayer closed this Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants