aboutsummaryrefslogtreecommitdiff
path: root/src/html/template/escape.go
diff options
context:
space:
mode:
authorRoland Shoemaker <bracewell@google.com>2026-01-09 11:12:01 -0800
committerGopher Robot <gobot@golang.org>2026-03-05 16:12:49 -0800
commit994692847a2cd3efd319f0cb61a07c0012c8a4ff (patch)
tree6420c79163711856095efff03655727438064651 /src/html/template/escape.go
parent65c7d7a9fb3a9d1fbf1e702a211b8cc3a7bedb53 (diff)
downloadgo-994692847a2cd3efd319f0cb61a07c0012c8a4ff.tar.xz
[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 <nealpatel@google.com> Reviewed-by: Nicholas Husin <husin@google.com> Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3643 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-on: https://go-review.googlesource.com/c/go/+/752081 Auto-Submit: Gopher Robot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Bypass: Gopher Robot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/html/template/escape.go')
-rw-r--r--src/html/template/escape.go14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 1f963e61b4..d8e1b8cb54 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -166,6 +166,8 @@ func (e *escaper) escape(c context, n parse.Node) context {
var debugAllowActionJSTmpl = godebug.New("jstmpllitinterp")
+var htmlmetacontenturlescape = godebug.New("htmlmetacontenturlescape")
+
// escapeAction escapes an action template node.
func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
if len(n.Pipe.Decl) != 0 {
@@ -223,6 +225,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
default:
panic(c.urlPart.String())
}
+ case stateMetaContent:
+ // Handled below in delim check.
+ case stateMetaContentURL:
+ if htmlmetacontenturlescape.Value() != "0" {
+ s = append(s, "_html_template_urlfilter")
+ } else {
+ // We don't have a great place to increment this, since it's hard to
+ // know if we actually escape any urls in _html_template_urlfilter,
+ // since it has no information about what context it is being
+ // executed in etc. This is probably the best we can do.
+ htmlmetacontenturlescape.IncNonDefault()
+ }
case stateJS:
s = append(s, "_html_template_jsvalescaper")
// A slash after a value starts a div operator.