Skip to content

MF-M02: fix(rpc): release Serve wait group on processSink overflow#732

Merged
philanton merged 1 commit into
fix/audit-findings-finalfrom
fix/nitronode-mf-m02
May 11, 2026
Merged

MF-M02: fix(rpc): release Serve wait group on processSink overflow#732
philanton merged 1 commit into
fix/audit-findings-finalfrom
fix/nitronode-mf-m02

Conversation

@philanton
Copy link
Copy Markdown
Contributor

@philanton philanton commented May 8, 2026

Summary

  • readMessages returned without calling handleClosure when processSink was full, leaving the Serve wait group stuck at one outstanding Done. The parent closure callback never fired, the WebSocket was never closed, and the outer HTTP handler stayed blocked — connHub.Remove never ran. Unauthenticated clients could exhaust server resources by flooding messages faster than the queue drained.
  • Call handleClosure(nil) before returning from the queue-full branch so the wait group invariant (every early return decrements exactly once) holds.
  • Add a regression test that fills processSink without a consumer and asserts the parent closure fires and the underlying connection is closed.

Notes

  • Same fix already exists on fix/nitronode-mf-c01 (part of broader frame-size + rate-limiter hardening). Three-way merge between this branch and c01 is clean — identical line addition, non-overlapping hunks.
  • c01 also adds a parallel frameRateLimiter.Admit early-return path with the same handleClosure(nil) shape.

Test plan

  • go test ./pkg/rpc/... -count=1 passes
  • New test fails without the one-line fix (parent handleClosure not invoked after processSink overflow; goroutine leak)
  • go vet ./pkg/rpc/... clean
  • CI green

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a96f66ca-21ec-48d8-9843-bff0b0061843

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nitronode-mf-m02

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@philanton philanton changed the base branch from main to fix/audit-findings-final May 8, 2026 12:10
Copy link
Copy Markdown
Collaborator

@ihsraham ihsraham left a comment

Choose a reason for hiding this comment

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

approved for the m-02 fix. the queue-full read path now calls the shared closure hook before returning, so the connection wait group can finish and the outer handler can remove the websocket from the hub.

that closes the unauthenticated resource-exhaustion path from the finding, and the regression test covers the stuck cleanup case directly.

readMessages returned without invoking handleClosure when processSink
was full, leaving the Serve wait group stuck at one outstanding Done.
The parent closure callback never fired, the underlying WebSocket was
never closed, and the outer HTTP handler stayed blocked, preventing
its deferred connHub.Remove. An unauthenticated client could exhaust
server resources by sending messages faster than the queue drained.

Call handleClosure(nil) before returning from the queue-full branch
so the wait group invariant holds. Add a regression test that fills
processSink without a consumer and asserts the parent closure fires
plus the underlying connection is closed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@philanton philanton force-pushed the fix/nitronode-mf-m02 branch from 3f0abd4 to 3bbcab0 Compare May 11, 2026 13:31
@philanton philanton merged commit 8b4ad82 into fix/audit-findings-final May 11, 2026
3 checks passed
@philanton philanton deleted the fix/nitronode-mf-m02 branch May 11, 2026 13:33
nksazonov pushed a commit that referenced this pull request May 13, 2026
- MF-L01: fix(contracts/ChannelHub): cap ERC20 transfer returndata copy to 32 bytes (#726)                                                
- MF-H01: fix(nitronode): paginate get_last_key_states endpoints (#724)                                                                   
- MF-I01-I02: fix(contracts): address security audit findings I-01 and I-02 (#728)                                                        
- MF-C01: rpc: cap inbound WebSocket frame size and rate-limit per connection (#723)                                                      
- MF-L02: docs(protocol): qualify enforcement guarantee for intent-specific execution paths (#737)                                        
- MF-L02-I03-I04_I05: fix(contracts): add more Node trust assumptions and requirements (#738)                                             
- MF-M01: backfill state user_sig from on-chain events (#731)               
- MF-M02: fix(rpc): release Serve wait group on processSink overflow (#732)                                                               
- Fix SDK acknowledgement before home channel creation (#734)               
- MF-I06: fix(nitronode): gate escrow transitions on home channel onchain materialization (#730)                                          
- MF-M05: fix(nitronode): enforce TLS by default for Postgres (#733)                                                                      
- MF-M07: Unblock receiver states after finalized escrow operations (#735)
- MF-M04: feat: provide tooling for and enhance docs on ValidatorRegistered event (#744)                                                  
- MF-L04: fix(contracts): reject redundant native value (#741)              
- MF-H02: bind session key registration to a single owner per kind (#739)                                                                 
- MF-I07: fix(contracts): enforce max challenge duration (#752)             
- MF-M08: fix(rpc): replace Origin label with application_id on connection gauge (#745)                                                   
- MF-C02: fix(core): add ChannelStatusClosing to gate post-finalize state transitions (#746)                                              
- MF-L06: fix(contracts): clear stale challengeExpireAt on cooperative escrow finalization (#754)
- MF-I08: docs: document ChannelClosed event orientation ambiguity during abandoned migration (#755)                                      
- MF-M09: fix(nitronode): auto-challenge home channel on withheld escrow finalize (#753)
- MF-L09: fix(nitronode): validate parsed app session nonce (#751)                                                                        
- MF-L05: docs(contracts): document informational events not guaranteed to emit (#756)
- MF-L08: fix(nitronode/api): default get_last_key_states to active-only with include_inactive opt-in (#749)                              
- MF-L10: fix: emit escrowIds array in EscrowDepositsPurged event and handle it in Nitronode (#757)
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