]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: sanitize User-Agent header in request writer
authorDamien Neil <dneil@google.com>
Mon, 7 Aug 2023 22:57:54 +0000 (15:57 -0700)
committerDamien Neil <dneil@google.com>
Tue, 8 Aug 2023 23:10:58 +0000 (23:10 +0000)
Apply the same transformations to the User-Agent header value that we
do to other headers.

Avoids header and request smuggling in Request.Write and
Request.WriteProxy. RoundTrip already validates values in
Request.Header, and didn't allow bad User-Agent values to
make it as far as the request writer.

Fixes #61824

Change-Id: I360a915c7e08d014e0532bd5af196a5b59c89395
Reviewed-on: https://go-review.googlesource.com/c/go/+/516836
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Damien Neil <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/net/http/request.go
src/net/http/request_test.go

index d1fbd5df907c334eccd9010ee7f366daae6a7344..0fb73c12b55c54b8ad4b96b18621d18ccce99f81 100644 (file)
@@ -669,6 +669,8 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
                userAgent = r.Header.Get("User-Agent")
        }
        if userAgent != "" {
+               userAgent = headerNewlineToSpace.Replace(userAgent)
+               userAgent = textproto.TrimString(userAgent)
                _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent)
                if err != nil {
                        return err
index a32b583c116a1517caed4c43c1e61f7a24b26efb..571116489401084461cc8f3fc6a0375dd8ab6857 100644 (file)
@@ -787,6 +787,25 @@ func TestRequestBadHostHeader(t *testing.T) {
        }
 }
 
+func TestRequestBadUserAgent(t *testing.T) {
+       got := []string{}
+       req, err := NewRequest("GET", "http://foo/after", nil)
+       if err != nil {
+               t.Fatal(err)
+       }
+       req.Header.Set("User-Agent", "evil\r\nX-Evil: evil")
+       req.Write(logWrites{t, &got})
+       want := []string{
+               "GET /after HTTP/1.1\r\n",
+               "Host: foo\r\n",
+               "User-Agent: evil  X-Evil: evil\r\n",
+               "\r\n",
+       }
+       if !reflect.DeepEqual(got, want) {
+               t.Errorf("Writes = %q\n  Want = %q", got, want)
+       }
+}
+
 func TestStarRequest(t *testing.T) {
        req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
        if err != nil {