Skip to content

fix(p2p): guard ENR address parsing against malformed TCP fields (A-1255)#24215

Draft
PhilWindle wants to merge 1 commit into
merge-train/spartan-v5from
phil/a-1255-p2pdiscv5-malformed-tcp-enr-crashes-unguarded-async-enradded
Draft

fix(p2p): guard ENR address parsing against malformed TCP fields (A-1255)#24215
PhilWindle wants to merge 1 commit into
merge-train/spartan-v5from
phil/a-1255-p2pdiscv5-malformed-tcp-enr-crashes-unguarded-async-enradded

Conversation

@PhilWindle

Copy link
Copy Markdown
Collaborator

Fixes A-1255.

Problem

A discovery peer can advertise a signed ENR with valid ip/udp contact data and the expected Aztec ENR version key, but a malformed tcp field (e.g. 3 bytes instead of a 2-byte port). DiscV5Service.validateEnr only checked the aztec key + version, so upstream discv5 accepted the session and emitted enrAdded. The unguarded async onEnrAdded listener then awaited enr.getFullMultiaddr('tcp'), which throws RangeError on the malformed value; as an async EventEmitter listener the rejection is unhandled and the node process exits. One malformed, UDP-contactable, same-version ENR crashes any p2p-enabled node.

Audit

A sweep of every getFullMultiaddr / getLocationMultiaddr call in p2p/src found the same unguarded-parse pattern in more than one place:

Site ENR source Crash today Action
discV5_service.ts onEnrAdded remote yes guard + drop
bootstrap.ts discovered listener remote yes (crashes the bootnode) guard + drop
peer_manager.ts handleDiscoveredPeer remote no (caught by wrapper) covered by validateEnr rejecting malformed-addr ENRs
peer_manager.ts / libp2p_service.ts preferredPeers config aborts setup skip + log

Fix

  • Guard onEnrAdded and the bootnode discovered listener so a parser exception is caught, logged, and the ENR dropped — no unhandled rejection.
  • validateEnr rejects an ENR whose TCP multiaddr won't parse, so it's never emitted as a full peer (PeerEvent.DISCOVERED) or re-parsed by handleDiscoveredPeer. A missing TCP addr stays allowed — those peers are simply skipped at dial time; only an unparseable one is rejected.
  • preferredPeers ENR parsing skips and logs a malformed configured ENR instead of aborting node / preferred-peer setup.

The self-ENR log line (discV5_service.ts:199-200) is intentionally left unguarded — it reads our own ENR, which we build and which can't be attacker-malformed.

Tests

discv5_service.test.ts: builds a same-version ENR with valid ip/udp and a 3-byte tcp value, and asserts (a) validateEnr rejects it while a valid control built from the same identity passes — isolating the TCP check — and (b) onEnrAdded resolves (no unhandled rejection, previously a RangeError) and never emits DISCOVERED.

Note: discV5_service.ts overlapped with the already-merged PR #24169; this branch is off the post-merge merge-train/spartan-v5, so no conflict.

…255)

A discovery peer could advertise a signed, same-version, UDP-contactable
ENR with a malformed TCP field (e.g. 3 bytes instead of a 2-byte port).
validateEnr only checked the aztec key + version, so discv5 emitted
enrAdded; the unguarded async onEnrAdded listener then awaited
getFullMultiaddr('tcp'), which threw RangeError, and as an async listener
the rejection was unhandled and crashed the node.

Audit of every getFullMultiaddr/getLocationMultiaddr site in p2p found
the same pattern on the bootnode's discovered listener (crashes the
bootnode) and config-provided preferredPeers parsing (aborts setup):

- Guard onEnrAdded and the bootstrap discovered listener so a parser
  exception is caught, logged and the ENR dropped (no process exit).
- validateEnr rejects an ENR whose TCP multiaddr won't parse, so it's
  never emitted as a full peer / re-parsed downstream. A missing TCP addr
  stays allowed (those peers are skipped at dial time).
- preferredPeers ENR parsing (peer_manager, libp2p_service) skips and logs
  a malformed configured ENR instead of aborting node setup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@PhilWindle PhilWindle added the ci-draft Run CI on draft PRs. label Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant