From babb1c32c2e7ee7a1147e7e587d35c553fb693ad Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Mon, 23 Mar 2026 13:34:23 -0700 Subject: [release-branch.go1.26] html/template: properly track JS template literal brace depth across contexts Properly track JS template literal brace depth across branches/ranges, and prevent accidental re-use of escape analysis by including the brace depth in the stringification/mangling for contexts. Fixes #78331 Fixes CVE-2026-32289 Change-Id: I9f3f47c29e042220b18e4d3299db7a3fae4207fa Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3882 Reviewed-by: Neal Patel Reviewed-by: Nicholas Husin Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3983 Reviewed-by: Damien Neil Commit-Queue: Damien Neil Reviewed-on: https://go-review.googlesource.com/c/go/+/763543 Reviewed-by: Junyang Shao Reviewed-by: David Chase Auto-Submit: Gopher Robot TryBot-Bypass: Gopher Robot --- src/html/template/context.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/html/template/context.go') diff --git a/src/html/template/context.go b/src/html/template/context.go index 8b3af2feab..132ae2d28d 100644 --- a/src/html/template/context.go +++ b/src/html/template/context.go @@ -6,6 +6,7 @@ package template import ( "fmt" + "slices" "text/template/parse" ) @@ -37,7 +38,7 @@ func (c context) String() string { if c.err != nil { err = c.err } - return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, err) + return fmt.Sprintf("{%v %v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.jsBraceDepth, c.attr, c.element, err) } // eq reports whether two contexts are equal. @@ -46,6 +47,7 @@ func (c context) eq(d context) bool { c.delim == d.delim && c.urlPart == d.urlPart && c.jsCtx == d.jsCtx && + slices.Equal(c.jsBraceDepth, d.jsBraceDepth) && c.attr == d.attr && c.element == d.element && c.err == d.err @@ -68,6 +70,9 @@ func (c context) mangle(templateName string) string { if c.jsCtx != jsCtxRegexp { s += "_" + c.jsCtx.String() } + if c.jsBraceDepth != nil { + s += fmt.Sprintf("_jsBraceDepth(%v)", c.jsBraceDepth) + } if c.attr != attrNone { s += "_" + c.attr.String() } @@ -77,6 +82,13 @@ func (c context) mangle(templateName string) string { return s } +// clone returns a copy of c with the same field values. +func (c context) clone() context { + clone := c + clone.jsBraceDepth = slices.Clone(c.jsBraceDepth) + return clone +} + // state describes a high-level HTML parser state. // // It bounds the top of the element stack, and by extension the HTML insertion -- cgit v1.3