From ac87c4e93557619f326275fbc7ef7431adecca4f Mon Sep 17 00:00:00 2001 From: AshSgDe29071999 Date: Mon, 31 Aug 2026 14:57:09 +0530 Subject: [PATCH] Bound CloseError.Error text to the control-frame limit Error() appended Text without a length cap. A CloseError with a huge Text (corrupt state or a caller-built value) could OOM while formatting the error. Truncate to maxControlFramePayloadSize, the protocol maximum for close-frame payloads. See #1002 --- conn.go | 6 +++++- conn_test.go | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/conn.go b/conn.go index 9562ffd4..38b9b5a6 100644 --- a/conn.go +++ b/conn.go @@ -140,7 +140,11 @@ func (e *CloseError) Error() string { } if e.Text != "" { s = append(s, ": "...) - s = append(s, e.Text...) + text := e.Text + if len(text) > maxControlFramePayloadSize { + text = text[:maxControlFramePayloadSize] + } + s = append(s, text...) } return string(s) } diff --git a/conn_test.go b/conn_test.go index 28f5c4a3..51cf15e0 100644 --- a/conn_test.go +++ b/conn_test.go @@ -12,6 +12,7 @@ import ( "io" "net" "reflect" + "strings" "sync" "testing" "testing/iotest" @@ -671,6 +672,18 @@ func TestCloseError(t *testing.T) { } } +func TestCloseErrorTextIsBounded(t *testing.T) { + huge := strings.Repeat("x", 1<<20) + err := &CloseError{Code: CloseNormalClosure, Text: huge} + msg := err.Error() + if len(msg) > 64+maxControlFramePayloadSize { + t.Fatalf("Error() length %d exceeds bound", len(msg)) + } + if !strings.Contains(msg, "websocket: close 1000") { + t.Fatalf("Error() = %q", msg) + } +} + var unexpectedCloseErrorTests = []struct { err error codes []int