Skip to content

p2p: bound relay address query responses - #4642

Open
pinebit wants to merge 1 commit into
mainfrom
pinebit/relay-response-size-limit
Open

p2p: bound relay address query responses#4642
pinebit wants to merge 1 commit into
mainfrom
pinebit/relay-response-size-limit

Conversation

@pinebit

@pinebit pinebit commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Relay address resolution read the HTTP response body with io.ReadAll and no size limit, using a zero-value http.Client with no timeout, in a loop that runs for the process lifetime. A configured relay returning an endless response body could therefore grow the heap until the node was OOM killed. Reported via the bug bounty program.

Limits the response to 64KB, which is well above a valid ENR string or multiaddr array, and rejects anything larger instead of parsing a truncated body. Adds a 10s per-attempt client timeout, since the request was previously bound only to the long-lived application context. Closes the response body on the non-2xx retry path, where it was leaked along with its connection on every retry.

Oversized responses warn and retry, matching how the existing non-2xx, JSON and multiaddr failures are handled; returning an error instead would make resolveRelay abandon the relay for the rest of the process lifetime.

Adds p2p/bootnode_internal_test.go, which had no coverage. TestQueryRelayAddrsBoundsResponse counts the bytes a streaming server manages to write and asserts a hard bound, so it exercises the size limit independently of the timeout. With the limit removed but the timeout in place, that server writes 2.8GB within the 10s window, so the timeout alone is not sufficient mitigation. The oversized case uses valid JSON padded past the limit so the size check rejects it rather than the parser, and a case at exactly the limit covers the boundary.

category: bug
ticket: none

Relay address resolution read the HTTP response body with io.ReadAll and no
size limit, using a zero-value http.Client with no timeout, in a loop that
runs for the process lifetime. A malicious or compromised configured relay
could stream an endless response and grow the heap until the node was
OOM killed.

Limit the response to 64KB, which is well above a valid ENR string or
multiaddr array, set a 10s per-attempt client timeout, and close the response
body on the non-2xx retry path where it was leaked.

category: bug
ticket: none
@pinebit
pinebit requested a lite review from Copilot August 12, 2026 08:07
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Mitigates a potential OOM/connection-leak issue in long-lived relay address resolution by bounding HTTP response body reads and adding a per-attempt HTTP client timeout, and adds regression tests to validate the bounds behavior.

Changes:

  • Bound relay address query response bodies to 64KiB and retry on oversized responses (instead of parsing truncated data).
  • Add a 10s per-attempt HTTP client timeout and ensure response bodies are closed on non-2xx retry paths.
  • Add internal tests covering valid, oversized, boundary-sized, unbounded streaming, and non-200 relay responses.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
p2p/bootnode.go Adds response size limiting, per-attempt timeout, and fixes response-body close on non-2xx retries in relay address resolution.
p2p/bootnode_internal_test.go Adds tests to ensure response reads are bounded and retries behave correctly across edge cases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@pinebit
pinebit requested a review from KaloyanTanev August 12, 2026 08:10
@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.26%. Comparing base (caefc2e) to head (d9008df).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4642      +/-   ##
==========================================
+ Coverage   58.16%   58.26%   +0.10%     
==========================================
  Files         247      247              
  Lines       34063    34069       +6     
==========================================
+ Hits        19814    19852      +38     
+ Misses      11774    11734      -40     
- Partials     2475     2483       +8     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@KaloyanTanev

Copy link
Copy Markdown
Collaborator

Do we have metrics from the size of the relay data that was exchanged? If so, is it the case that those limits would suffice? With both QUIC and TCP. I generally think this PR has higher ROI than the other transport-related PRs, as it is relay related.

@pinebit

pinebit commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Do we have metrics from the size of the relay data that was exchanged? If so, is it the case that those limits would suffice? With both QUIC and TCP. I generally think this PR has higher ROI than the other transport-related PRs, as it is relay related.

No, we don't have historical metrics.

I queried the production relays directly to get a real number:

The 64KB limit is ~350× the actual production response (~180 bytes) and would still fit ~600 multiaddrs, so it's safe for both transports and any plausible relay configuration. Note that the limit applies only to the HTTP address-discovery query; the relayed p2p traffic itself (QUIC or TCP) is unaffected.

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.

3 participants