Skip to content

security: fix listener removal bug in WebsocketListeners#5562

Open
kolega-ai-dev wants to merge 1 commit intoHelicone:mainfrom
kolega-ai:v6-finding_3
Open

security: fix listener removal bug in WebsocketListeners#5562
kolega-ai-dev wants to merge 1 commit intoHelicone:mainfrom
kolega-ai:v6-finding_3

Conversation

@kolega-ai-dev
Copy link
Contributor

Vulnerability identified and fix provided by Kolega.dev

Ticket

Security finding: Listener Removal Bug in WebsocketListeners

Component/Service

  • Jawn (Backend)

Type of Change

  • Bug fix

Deployment Notes

  • No special deployment steps required

Context

The removeListener method in WebsocketListeners.ts (line 77) calls Array.filter() but discards the returned array — filter() returns a new array and the original array in the Map is never updated. This means WebSocket listeners are never actually removed when connections close.

Security implications:

  1. Memory leak / DoS vector: Closed WebSocket connections remain in the listeners Map indefinitely. An attacker who can establish WebSocket connections can exhaust server memory by repeatedly connecting and disconnecting.
  2. Stale auth data in memory: ConnectedRouterState objects containing AuthParams persist in memory after the connection is closed.

Fix Applied

Assigned the filtered result back to the Map using this.listeners.set(), matching the existing pattern already used in addListener (line 59). When the organizationId has no existing listeners, defaults to an empty array via the ?? [] fallback.

Tests/Linters Ran

  • TypeScript type check (npx tsc --noEmit): Passed with no errors
  • Jest test suite (npx jest --detectOpenHandles): Pre-existing failures unrelated to this change (emoji sanitization tests). Confirmed the same failures exist on main — test results are not affected by this fix.

Contribution Notes

Following the Contributing Guidelines: branched from main, code lints, change is minimal and focused on the security fix only.

Extra Notes

Single-line logical fix. The filter() call was already correct in its predicate — only the assignment of the result was missing.

The removeListener method called filter() but discarded the result,
since Array.filter() returns a new array. This left closed WebSocket
connections in memory indefinitely, enabling memory exhaustion via
repeated connect/disconnect cycles. The filtered result is now
assigned back to the Map.
@vercel
Copy link

vercel bot commented Feb 9, 2026

@FaizanKolega is attempting to deploy a commit to the Helicone Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@vercel
Copy link

vercel bot commented Feb 9, 2026

@FaizanKolega is attempting to deploy a commit to the Helicone Team on Vercel.

A member of the Team first needs to authorize it.

2 similar comments
@vercel
Copy link

vercel bot commented Feb 9, 2026

@FaizanKolega is attempting to deploy a commit to the Helicone Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link

vercel bot commented Feb 9, 2026

@FaizanKolega is attempting to deploy a commit to the Helicone Team on Vercel.

A member of the Team first needs to authorize it.

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