From a402f4ad285514f5f3db90516d72047d591b307a Mon Sep 17 00:00:00 2001
From: Damien Neil <dneil@google.com>
Date: Tue, 30 Sep 2025 15:11:16 -0700
Subject: [PATCH] net/textproto: avoid quadratic complexity in
 Reader.ReadResponse

Reader.ReadResponse constructed a response string from repeated
string concatenation, permitting a malicious sender to cause excessive
memory allocation and CPU consumption by sending a response consisting
of many short lines.

Use a strings.Builder to construct the string instead.

Thanks to Jakub Ciolek for reporting this issue.

Fixes CVE-2025-61724
For #75716
Fixes #75717

Change-Id: I1a98ce85a21b830cb25799f9ac9333a67400d736
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2940
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2980
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709837
Reviewed-by: Carlos Amedee <carlos@golang.org>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>

CVE: CVE-2025-61724

Upstream-Status: Backport [https://github.com/golang/go/commit/a402f4ad285514f5f3db90516d72047d591b307a]

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 src/net/textproto/reader.go | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
index 7930211..0027efe 100644
--- a/src/net/textproto/reader.go
+++ b/src/net/textproto/reader.go
@@ -283,8 +283,10 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err err
 //
 // An expectCode <= 0 disables the check of the status code.
 func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) {
-	code, continued, message, err := r.readCodeLine(expectCode)
+	code, continued, first, err := r.readCodeLine(expectCode)
	multi := continued
+	var messageBuilder strings.Builder
+	messageBuilder.WriteString(first)
	for continued {
		line, err := r.ReadLine()
		if err != nil {
@@ -295,12 +297,15 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err err
		var moreMessage string
		code2, continued, moreMessage, err = parseCodeLine(line, 0)
		if err != nil || code2 != code {
-			message += "\n" + strings.TrimRight(line, "\r\n")
+			messageBuilder.WriteByte('\n')
+			messageBuilder.WriteString(strings.TrimRight(line, "\r\n"))
			continued = true
			continue
		}
-		message += "\n" + moreMessage
+		messageBuilder.WriteByte('\n')
+		messageBuilder.WriteString(moreMessage)
	}
+	message = messageBuilder.String()
	if err != nil && multi && message != "" {
		// replace one line error message with all lines (full message)
		err = &Error{code, message}
--
2.40.0
