Skip to content

fix(discord,gateway): inbound WS buffer overflow and WebChat drop - #81

Merged
adriannoes merged 2 commits into
developmentfrom
cursor/high-severity-issues-ffcf
Sep 14, 2026
Merged

adriannoes merged 2 commits into
developmentfrom
cursor/high-severity-issues-ffcf

Conversation

@cursor

@cursor cursor Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Summary

Two inbound WebSocket buffer bugs: Discord Gateway RX wrote a NUL one byte past the heap block, and dashboard WebChat silently dropped messages larger than one 256-byte LWS callback.

Bug 1 — Discord Gateway RX heap overflow (CRITICAL)

Bug 2 — WebChat inbound frames not reassembled (HIGH)

  • File/function: src/gateway/http.c protocols "ws" .rx_buffer_size = 256; src/gateway/http_lws.c ws_callback LWS_CALLBACK_RECEIVE
  • Trigger: Dashboard WebChat text ≳ ~220 characters ({"type":"message","text":"..."}). LWS splits at 256 bytes; each chunk is cJSON_Parsed as a complete object and fails; the user message is dropped.
  • Impact: Significant user-facing breakage: any non-trivial dashboard message never reaches the agent.
  • Distinct from fix(webchat): align WebSocket payload limit with agent response buffer #62: that PR changes outbound dequeue/frame size, not inbound rx_buffer_size or fragment reassembly.

Fix

  • Grow Discord RX when cap < rx_len + chunk + 1 (payload plus trailing NUL). Discard remaining fragments after overflow until lws_is_final_fragment.
  • Set WebChat rx_buffer_size to WS_RX_BUFFER_SIZE (32KiB) so a full frame at MSG_MAX plus JSON envelope arrives in one RECEIVE.

Validation

  • CI=true make test_discord_helpers (includes exact-fill 4095+1 and two 64KiB fragments)
  • GCC ASan/UBSan on test_discord_helpers
  • GATEWAY=1 compile of discord.c, http.c, http_lws.c
Open in Web View Automation 

Note

Medium Risk
Touches live Discord Gateway and dashboard WebSocket receive paths; fixes memory safety and message delivery but changes buffer sizing on long-running gateway threads.

Overview
Fixes two inbound WebSocket buffer bugs: a one-byte heap overflow on Discord Gateway reassembly and silent loss of longer dashboard WebChat messages.

Discord Gateway RX now grows the reassembly buffer when payload + trailing NUL would exceed capacity (e.g. two 64 KiB LWS chunks no longer skip a grow at exactly 128 KiB). Logic lives in testable discord_helpers_rx_append; on overflow the client resets and skips fragments until the final LWS fragment via rx_skip.

WebChat inbound raises the "ws" protocol rx_buffer_size from 256 bytes to WS_RX_BUFFER_SIZE (WS_TEXT_MAX + envelope), with a compile-time assert, so typical {"type":"message","text":...} frames arrive in one RECEIVE instead of failing partial JSON parses.

Unit tests cover NUL-after-fill and dual 64 KiB fragment cases plus max-cap rejection.

Reviewed by Cursor Bugbot for commit 08716db. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor
cursor Bot force-pushed the cursor/high-severity-issues-ffcf branch from 6fa01ac to 08716db Compare September 14, 2026 00:36
@cursor
cursor Bot changed the base branch from main to development September 14, 2026 00:36
@adriannoes
adriannoes marked this pull request as ready for review September 14, 2026 00:36
@adriannoes
adriannoes self-requested a review as a code owner September 14, 2026 00:36
adriannoes and others added 2 commits September 14, 2026 00:39
discord_rx_append grew only when cap < rx_len+len, then wrote a NUL at
rx_len+len. Two 64KiB LWS fragments filled a doubled buffer exactly, so
the terminator was one byte past the heap block (typical READY payloads).

Co-authored-by: Adrianno E. S. <adriannoes@users.noreply.github.com>
…split

LWS delivers at most rx_buffer_size bytes per RECEIVE. The ws protocol used
256 with no fragment reassembly, so dashboard messages over ~220 characters
were parsed as incomplete JSON and dropped. Size the buffer to fit a full
WebChat frame (WS_TEXT_MAX plus JSON envelope). Distinct from outbound #62.

Co-authored-by: Adrianno E. S. <adriannoes@users.noreply.github.com>
@cursor
cursor Bot force-pushed the cursor/high-severity-issues-ffcf branch from 08716db to d97452a Compare September 14, 2026 00:40

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Summary

This PR fixes two inbound WebSocket bugs that match the claimed intent. Discord Gateway RX now grows for the trailing NUL, so two 64 KiB libwebsockets fragments cannot write one byte past the heap block (typical READY). Dashboard WebChat raises ws rx_buffer_size from 256 to WS_TEXT_MAX + 64, which stops the deterministic drop of Chat JSON above ~220 characters. Helper tests for the exact-fill and dual-64 KiB cases pass locally under GCC ASan+UBSan. Required CI is red: make static fails cppcheck variableScope on the new helper.

Would be REQUEST_CHANGES if GitHub allowed it on this bot-authored PR. Do not merge until make static is green.

Must Fix

  1. src/channels/discord_helpers.c:148 — cppcheck variableScope on ncap fails make static (--error-exitcode=1). GitHub Actions static, test, release on 08716db stopped at this check (run 34793224931). Declare ncap and p inside if (*cap < need) so the next pass does not fail on p. Same class as #80.

Should Fix

  1. src/gateway/http.c / ws_callback RECEIVE still parses each callback as a complete JSON object. The buffer bump fixes the 256-byte LWS chunk split. It does not reassemble partial frames (lws_is_final_fragment). Discord already does. A split Chat frame can still be dropped.
  2. rx_skip in src/channels/discord.c is untested. Helper tests never walk overflow-on-non-final plus the following frame.
  3. WS_RX_BUFFER_SIZE = WS_TEXT_MAX + 64 does not cover JSON escape expansion (quotes, backslashes). Typical <input> Chat text is fine.

Nice to Have

  • Helper test for payload max_cap - 1 (NUL fits) vs payload max_cap (reject).
  • Keep WS_RX_BUFFER_SIZE next to WS_TEXT_MAX in ws.h instead of including ws.h from http_lws.h.
  • test_gateway_http still has no /ws case; GATEWAY=1 CI does not lock inbound Chat.
  • ncap *= 2 has no overflow guard. Production RX_MAX (512 KiB) is safe.

Positive Highlights

  • Moving grow-for-NUL into discord_helpers_rx_append is the right split: discord.c is already over the 1000-line mark, and the 4095+1 plus two 64 KiB tests actually hit the old OOB.
  • CHANGELOG Unreleased lines are present for both fixes (unlike several earlier bug-hunt PRs).
  • rx_skip until the final LWS fragment is the correct fail-closed follow-through after overflow.
  • Because tx_packet_size defaults to 0, the WebChat rx bump also sizes the send buffer, which is what lets a #62 32 KiB lws_write fit in one shot (ws_on_writable does not retry short writes).

Local check: helper tests passed when linked with -lm only (Makefile still passes -lcurl; this image has no curl import library). GCC ASan+UBSan detect_leaks=1 on test_discord_helpers passed. cppcheck is not installed here; the CI log is the oracle for variableScope.

Open in Web View Automation 

Sent by Cursor Automation: Adrianno’s personal code review

Comment thread src/channels/discord_helpers.c
Comment thread src/gateway/http.c
Comment thread src/channels/discord.c

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Could not approve: GitHub blocks self-approval on this cursor[bot] PR. Cursor Security Agent passed with no findings that need human review; Bugbot did not run on the current head, so that signal was skipped. adriannoes is already assigned; no additional reviewers were added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Could not approve: GitHub blocks self-approval on this cursor[bot] PR. Cursor Security Agent passed with no findings that need human review; Bugbot did not run on the current head, so that signal was skipped. adriannoes is already assigned; no additional reviewers were added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@adriannoes
adriannoes merged commit 19d4708 into development Sep 14, 2026
3 checks passed
@adriannoes
adriannoes deleted the cursor/high-severity-issues-ffcf branch September 22, 2026 21:17
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.

1 participant