From 994692847a2cd3efd319f0cb61a07c0012c8a4ff Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Fri, 9 Jan 2026 11:12:01 -0800 Subject: [release-branch.go1.26] html/template: properly escape URLs in meta content attributes The meta tag can include a content attribute that contains URLs, which we currently don't escape if they are inserted via a template action. This can plausibly lead to XSS vulnerabilities if untrusted data is inserted there, the http-equiv attribute is set to "refresh", and the content attribute contains an action like `url={{.}}`. Track whether we are inside of a meta element, if we are inside of a content attribute, _and_ if the content attribute contains "url=". If all of those are true, then we will apply the same URL escaping that we use elsewhere. Also add a new GODEBUG, htmlmetacontenturlescape, to allow disabling this escaping for cases where this behavior is considered safe. The behavior can be disabled by setting htmlmetacontenturlescape=0. Updates #77954 Fixes #77972 Fixes CVE-2026-27142 Change-Id: I9bbca263be9894688e6ef1e9a8f8d2f4304f5873 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3360 Reviewed-by: Neal Patel Reviewed-by: Nicholas Husin Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3643 Reviewed-by: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/752081 Auto-Submit: Gopher Robot Reviewed-by: Cherry Mui TryBot-Bypass: Gopher Robot Reviewed-by: Dmitri Shuralyov --- src/html/template/escape_test.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src/html/template/escape_test.go') diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go index 003060e90f..49710c38b7 100644 --- a/src/html/template/escape_test.go +++ b/src/html/template/escape_test.go @@ -734,6 +734,16 @@ func TestEscape(t *testing.T) { "", "", }, + { + "meta content attribute url", + ``, + ``, + }, + { + "meta content string", + ``, + ``, + }, } for _, test := range tests { @@ -1016,6 +1026,14 @@ func TestErrors(t *testing.T) { "", ``, }, + { + `{{if eq "" ""}}{{end}}`, + ``, + }, + { + `{{if eq "" ""}}{{end}}`, + ``, + }, // Error cases. { @@ -2198,3 +2216,19 @@ func TestAliasedParseTreeDoesNotOverescape(t *testing.T) { t.Fatalf(`Template "foo" and "bar" rendered %q and %q respectively, expected equal values`, got1, got2) } } + +func TestMetaContentEscapeGODEBUG(t *testing.T) { + savedGODEBUG := os.Getenv("GODEBUG") + os.Setenv("GODEBUG", savedGODEBUG+",htmlmetacontenturlescape=0") + defer func() { os.Setenv("GODEBUG", savedGODEBUG) }() + + tmpl := Must(New("").Parse(``)) + var b strings.Builder + if err := tmpl.Execute(&b, nil); err != nil { + t.Fatalf("unexpected error: %s", err) + } + want := `` + if got := b.String(); got != want { + t.Fatalf("got %q, want %q", got, want) + } +} -- cgit v1.3