summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch')
-rw-r--r--meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch635
1 files changed, 635 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch
new file mode 100644
index 0000000000..f200c41e16
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-24538-2.patch
@@ -0,0 +1,635 @@
+From 6fc21505614f36178df0dad7034b6b8e3f7588d5 Mon Sep 17 00:00:00 2001
+From: empijei <robclap8@gmail.com>
+Date: Fri, 27 Mar 2020 19:27:55 +0100
+Subject: [PATCH 2/6] html/template,text/template: switch to Unicode escapes
+ for JSON compatibility
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The existing implementation is not compatible with JSON
+escape as it uses hex escaping.
+Unicode escape, instead, is valid for both JSON and JS.
+This fix avoids creating a separate escaping context for
+scripts of type "application/ld+json" and it is more
+future-proof in case more JSON+JS contexts get added
+to the platform (e.g. import maps).
+
+Fixes #33671
+Fixes #37634
+
+Change-Id: Id6f6524b4abc52e81d9d744d46bbe5bf2e081543
+Reviewed-on: https://go-review.googlesource.com/c/go/+/226097
+Reviewed-by: Carl Johnson <me@carlmjohnson.net>
+Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
+Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
+TryBot-Result: Gobot Gobot <gobot@golang.org>
+
+Dependency Patch #2
+
+Upstream-Status: Backport from https://github.com/golang/go/commit/d4d298040d072ddacea0e0d6b55fb148fff18070
+CVE: CVE-2023-24538
+Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
+---
+ src/html/template/content_test.go | 70 +++++++++++++++++++-------------------
+ src/html/template/escape_test.go | 6 ++--
+ src/html/template/example_test.go | 6 ++--
+ src/html/template/js.go | 70 +++++++++++++++++++++++---------------
+ src/html/template/js_test.go | 68 ++++++++++++++++++------------------
+ src/html/template/template_test.go | 39 +++++++++++++++++++++
+ src/text/template/exec_test.go | 6 ++--
+ src/text/template/funcs.go | 8 ++---
+ 8 files changed, 163 insertions(+), 110 deletions(-)
+
+diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
+index 72d56f5..bd86527 100644
+--- a/src/html/template/content_test.go
++++ b/src/html/template/content_test.go
+@@ -18,7 +18,7 @@ func TestTypedContent(t *testing.T) {
+ HTML(`Hello, <b>World</b> &amp;tc!`),
+ HTMLAttr(` dir="ltr"`),
+ JS(`c && alert("Hello, World!");`),
+- JSStr(`Hello, World & O'Reilly\x21`),
++ JSStr(`Hello, World & O'Reilly\u0021`),
+ URL(`greeting=H%69,&addressee=(World)`),
+ Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`),
+ URL(`,foo/,`),
+@@ -70,7 +70,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello, <b>World</b> &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+- `Hello, World &amp; O&#39;Reilly\x21`,
++ `Hello, World &amp; O&#39;Reilly\u0021`,
+ `greeting=H%69,&amp;addressee=(World)`,
+ `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
+ `,foo/,`,
+@@ -100,7 +100,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello,&#32;World&#32;&amp;tc!`,
+ `&#32;dir&#61;&#34;ltr&#34;`,
+ `c&#32;&amp;&amp;&#32;alert(&#34;Hello,&#32;World!&#34;);`,
+- `Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\x21`,
++ `Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\u0021`,
+ `greeting&#61;H%69,&amp;addressee&#61;(World)`,
+ `greeting&#61;H%69,&amp;addressee&#61;(World)&#32;2x,&#32;https://golang.org/favicon.ico&#32;500.5w`,
+ `,foo/,`,
+@@ -115,7 +115,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello, World &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+- `Hello, World &amp; O&#39;Reilly\x21`,
++ `Hello, World &amp; O&#39;Reilly\u0021`,
+ `greeting=H%69,&amp;addressee=(World)`,
+ `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
+ `,foo/,`,
+@@ -130,7 +130,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello, &lt;b&gt;World&lt;/b&gt; &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+- `Hello, World &amp; O&#39;Reilly\x21`,
++ `Hello, World &amp; O&#39;Reilly\u0021`,
+ `greeting=H%69,&amp;addressee=(World)`,
+ `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
+ `,foo/,`,
+@@ -146,7 +146,7 @@ func TestTypedContent(t *testing.T) {
+ // Not escaped.
+ `c && alert("Hello, World!");`,
+ // Escape sequence not over-escaped.
+- `"Hello, World & O'Reilly\x21"`,
++ `"Hello, World & O'Reilly\u0021"`,
+ `"greeting=H%69,\u0026addressee=(World)"`,
+ `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
+ `",foo/,"`,
+@@ -162,7 +162,7 @@ func TestTypedContent(t *testing.T) {
+ // Not JS escaped but HTML escaped.
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ // Escape sequence not over-escaped.
+- `&#34;Hello, World &amp; O&#39;Reilly\x21&#34;`,
++ `&#34;Hello, World &amp; O&#39;Reilly\u0021&#34;`,
+ `&#34;greeting=H%69,\u0026addressee=(World)&#34;`,
+ `&#34;greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w&#34;`,
+ `&#34;,foo/,&#34;`,
+@@ -171,30 +171,30 @@ func TestTypedContent(t *testing.T) {
+ {
+ `<script>alert("{{.}}")</script>`,
+ []string{
+- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+- `a[href =~ \x22\/\/example.com\x22]#foo`,
+- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+- ` dir=\x22ltr\x22`,
+- `c \x26\x26 alert(\x22Hello, World!\x22);`,
++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
++ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
++ ` dir=\u0022ltr\u0022`,
++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
+ // Escape sequence not over-escaped.
+- `Hello, World \x26 O\x27Reilly\x21`,
+- `greeting=H%69,\x26addressee=(World)`,
+- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
++ `Hello, World \u0026 O\u0027Reilly\u0021`,
++ `greeting=H%69,\u0026addressee=(World)`,
++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
+ `,foo\/,`,
+ },
+ },
+ {
+ `<script type="text/javascript">alert("{{.}}")</script>`,
+ []string{
+- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+- `a[href =~ \x22\/\/example.com\x22]#foo`,
+- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+- ` dir=\x22ltr\x22`,
+- `c \x26\x26 alert(\x22Hello, World!\x22);`,
++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
++ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
++ ` dir=\u0022ltr\u0022`,
++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
+ // Escape sequence not over-escaped.
+- `Hello, World \x26 O\x27Reilly\x21`,
+- `greeting=H%69,\x26addressee=(World)`,
+- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
++ `Hello, World \u0026 O\u0027Reilly\u0021`,
++ `greeting=H%69,\u0026addressee=(World)`,
++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
+ `,foo\/,`,
+ },
+ },
+@@ -208,7 +208,7 @@ func TestTypedContent(t *testing.T) {
+ // Not escaped.
+ `c && alert("Hello, World!");`,
+ // Escape sequence not over-escaped.
+- `"Hello, World & O'Reilly\x21"`,
++ `"Hello, World & O'Reilly\u0021"`,
+ `"greeting=H%69,\u0026addressee=(World)"`,
+ `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
+ `",foo/,"`,
+@@ -224,7 +224,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello, <b>World</b> &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+- `Hello, World &amp; O&#39;Reilly\x21`,
++ `Hello, World &amp; O&#39;Reilly\u0021`,
+ `greeting=H%69,&amp;addressee=(World)`,
+ `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
+ `,foo/,`,
+@@ -233,15 +233,15 @@ func TestTypedContent(t *testing.T) {
+ {
+ `<button onclick='alert("{{.}}")'>`,
+ []string{
+- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+- `a[href =~ \x22\/\/example.com\x22]#foo`,
+- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+- ` dir=\x22ltr\x22`,
+- `c \x26\x26 alert(\x22Hello, World!\x22);`,
++ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
++ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
++ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
++ ` dir=\u0022ltr\u0022`,
++ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
+ // Escape sequence not over-escaped.
+- `Hello, World \x26 O\x27Reilly\x21`,
+- `greeting=H%69,\x26addressee=(World)`,
+- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
++ `Hello, World \u0026 O\u0027Reilly\u0021`,
++ `greeting=H%69,\u0026addressee=(World)`,
++ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
+ `,foo\/,`,
+ },
+ },
+@@ -253,7 +253,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
+ `%20dir%3d%22ltr%22`,
+ `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
+- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
++ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
+ // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done.
+ `greeting=H%69,&amp;addressee=%28World%29`,
+ `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
+@@ -268,7 +268,7 @@ func TestTypedContent(t *testing.T) {
+ `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
+ `%20dir%3d%22ltr%22`,
+ `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
+- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
++ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
+ // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done.
+ `greeting=H%69,&addressee=%28World%29`,
+ `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
+diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
+index e72a9ba..c709660 100644
+--- a/src/html/template/escape_test.go
++++ b/src/html/template/escape_test.go
+@@ -238,7 +238,7 @@ func TestEscape(t *testing.T) {
+ {
+ "jsStr",
+ "<button onclick='alert(&quot;{{.H}}&quot;)'>",
+- `<button onclick='alert(&quot;\x3cHello\x3e&quot;)'>`,
++ `<button onclick='alert(&quot;\u003cHello\u003e&quot;)'>`,
+ },
+ {
+ "badMarshaler",
+@@ -259,7 +259,7 @@ func TestEscape(t *testing.T) {
+ {
+ "jsRe",
+ `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`,
+- `<button onclick='alert(/foo\x2bbar/.test(""))'>`,
++ `<button onclick='alert(/foo\u002bbar/.test(""))'>`,
+ },
+ {
+ "jsReBlank",
+@@ -825,7 +825,7 @@ func TestEscapeSet(t *testing.T) {
+ "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`,
+ "helper": `{{11}} of {{"<100>"}}`,
+ },
+- `<button onclick="title='11 of \x3c100\x3e'; ...">11 of &lt;100&gt;</button>`,
++ `<button onclick="title='11 of \u003c100\u003e'; ...">11 of &lt;100&gt;</button>`,
+ },
+ // A non-recursive template that ends in a different context.
+ // helper starts in jsCtxRegexp and ends in jsCtxDivOp.
+diff --git a/src/html/template/example_test.go b/src/html/template/example_test.go
+index 9d965f1..6cf936f 100644
+--- a/src/html/template/example_test.go
++++ b/src/html/template/example_test.go
+@@ -116,9 +116,9 @@ func Example_escape() {
+ // &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
+ // &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
+ // &#34;Fran &amp; Freddie&#39;s Diner&#34;32&lt;tasty@example.com&gt;
+- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
+- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
+- // \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E
++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
++ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
++ // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E
+ // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
+
+ }
+diff --git a/src/html/template/js.go b/src/html/template/js.go
+index 0e91458..ea9c183 100644
+--- a/src/html/template/js.go
++++ b/src/html/template/js.go
+@@ -163,7 +163,6 @@ func jsValEscaper(args ...interface{}) string {
+ }
+ // TODO: detect cycles before calling Marshal which loops infinitely on
+ // cyclic data. This may be an unacceptable DoS risk.
+-
+ b, err := json.Marshal(a)
+ if err != nil {
+ // Put a space before comment so that if it is flush against
+@@ -178,8 +177,8 @@ func jsValEscaper(args ...interface{}) string {
+ // TODO: maybe post-process output to prevent it from containing
+ // "<!--", "-->", "<![CDATA[", "]]>", or "</script"
+ // in case custom marshalers produce output containing those.
+-
+- // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
++ // Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper
++ // supports ld+json content-type.
+ if len(b) == 0 {
+ // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should
+ // not cause the output `x=y/*z`.
+@@ -260,6 +259,8 @@ func replace(s string, replacementTable []string) string {
+ r, w = utf8.DecodeRuneInString(s[i:])
+ var repl string
+ switch {
++ case int(r) < len(lowUnicodeReplacementTable):
++ repl = lowUnicodeReplacementTable[r]
+ case int(r) < len(replacementTable) && replacementTable[r] != "":
+ repl = replacementTable[r]
+ case r == '\u2028':
+@@ -283,67 +284,80 @@ func replace(s string, replacementTable []string) string {
+ return b.String()
+ }
+
++var lowUnicodeReplacementTable = []string{
++ 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`,
++ '\a': `\u0007`,
++ '\b': `\u0008`,
++ '\t': `\t`,
++ '\n': `\n`,
++ '\v': `\u000b`, // "\v" == "v" on IE 6.
++ '\f': `\f`,
++ '\r': `\r`,
++ 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`,
++ 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`,
++ 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`,
++}
++
+ var jsStrReplacementTable = []string{
+- 0: `\0`,
++ 0: `\u0000`,
+ '\t': `\t`,
+ '\n': `\n`,
+- '\v': `\x0b`, // "\v" == "v" on IE 6.
++ '\v': `\u000b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+- '"': `\x22`,
+- '&': `\x26`,
+- '\'': `\x27`,
+- '+': `\x2b`,
++ '"': `\u0022`,
++ '&': `\u0026`,
++ '\'': `\u0027`,
++ '+': `\u002b`,
+ '/': `\/`,
+- '<': `\x3c`,
+- '>': `\x3e`,
++ '<': `\u003c`,
++ '>': `\u003e`,
+ '\\': `\\`,
+ }
+
+ // jsStrNormReplacementTable is like jsStrReplacementTable but does not
+ // overencode existing escapes since this table has no entry for `\`.
+ var jsStrNormReplacementTable = []string{
+- 0: `\0`,
++ 0: `\u0000`,
+ '\t': `\t`,
+ '\n': `\n`,
+- '\v': `\x0b`, // "\v" == "v" on IE 6.
++ '\v': `\u000b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+- '"': `\x22`,
+- '&': `\x26`,
+- '\'': `\x27`,
+- '+': `\x2b`,
++ '"': `\u0022`,
++ '&': `\u0026`,
++ '\'': `\u0027`,
++ '+': `\u002b`,
+ '/': `\/`,
+- '<': `\x3c`,
+- '>': `\x3e`,
++ '<': `\u003c`,
++ '>': `\u003e`,
+ }
+-
+ var jsRegexpReplacementTable = []string{
+- 0: `\0`,
++ 0: `\u0000`,
+ '\t': `\t`,
+ '\n': `\n`,
+- '\v': `\x0b`, // "\v" == "v" on IE 6.
++ '\v': `\u000b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+- '"': `\x22`,
++ '"': `\u0022`,
+ '$': `\$`,
+- '&': `\x26`,
+- '\'': `\x27`,
++ '&': `\u0026`,
++ '\'': `\u0027`,
+ '(': `\(`,
+ ')': `\)`,
+ '*': `\*`,
+- '+': `\x2b`,
++ '+': `\u002b`,
+ '-': `\-`,
+ '.': `\.`,
+ '/': `\/`,
+- '<': `\x3c`,
+- '>': `\x3e`,
++ '<': `\u003c`,
++ '>': `\u003e`,
+ '?': `\?`,
+ '[': `\[`,
+ '\\': `\\`,
+diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
+index 075adaa..d7ee47b 100644
+--- a/src/html/template/js_test.go
++++ b/src/html/template/js_test.go
+@@ -137,7 +137,7 @@ func TestJSValEscaper(t *testing.T) {
+ {"foo", `"foo"`},
+ // Newlines.
+ {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
+- // "\v" == "v" on IE 6 so use "\x0b" instead.
++ // "\v" == "v" on IE 6 so use "\u000b" instead.
+ {"\t\x0b", `"\t\u000b"`},
+ {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
+ {[]interface{}{}, "[]"},
+@@ -173,7 +173,7 @@ func TestJSStrEscaper(t *testing.T) {
+ }{
+ {"", ``},
+ {"foo", `foo`},
+- {"\u0000", `\0`},
++ {"\u0000", `\u0000`},
+ {"\t", `\t`},
+ {"\n", `\n`},
+ {"\r", `\r`},
+@@ -183,14 +183,14 @@ func TestJSStrEscaper(t *testing.T) {
+ {"\\n", `\\n`},
+ {"foo\r\nbar", `foo\r\nbar`},
+ // Preserve attribute boundaries.
+- {`"`, `\x22`},
+- {`'`, `\x27`},
++ {`"`, `\u0022`},
++ {`'`, `\u0027`},
+ // Allow embedding in HTML without further escaping.
+- {`&amp;`, `\x26amp;`},
++ {`&amp;`, `\u0026amp;`},
+ // Prevent breaking out of text node and element boundaries.
+- {"</script>", `\x3c\/script\x3e`},
+- {"<![CDATA[", `\x3c![CDATA[`},
+- {"]]>", `]]\x3e`},
++ {"</script>", `\u003c\/script\u003e`},
++ {"<![CDATA[", `\u003c![CDATA[`},
++ {"]]>", `]]\u003e`},
+ // https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span
+ // "The text in style, script, title, and textarea elements
+ // must not have an escaping text span start that is not
+@@ -201,11 +201,11 @@ func TestJSStrEscaper(t *testing.T) {
+ // allow regular text content to be interpreted as script
+ // allowing script execution via a combination of a JS string
+ // injection followed by an HTML text injection.
+- {"<!--", `\x3c!--`},
+- {"-->", `--\x3e`},
++ {"<!--", `\u003c!--`},
++ {"-->", `--\u003e`},
+ // From https://code.google.com/p/doctype/wiki/ArticleUtf7
+ {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
+- `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`,
++ `\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`,
+ },
+ // Invalid UTF-8 sequence
+ {"foo\xA0bar", "foo\xA0bar"},
+@@ -228,7 +228,7 @@ func TestJSRegexpEscaper(t *testing.T) {
+ }{
+ {"", `(?:)`},
+ {"foo", `foo`},
+- {"\u0000", `\0`},
++ {"\u0000", `\u0000`},
+ {"\t", `\t`},
+ {"\n", `\n`},
+ {"\r", `\r`},
+@@ -238,19 +238,19 @@ func TestJSRegexpEscaper(t *testing.T) {
+ {"\\n", `\\n`},
+ {"foo\r\nbar", `foo\r\nbar`},
+ // Preserve attribute boundaries.
+- {`"`, `\x22`},
+- {`'`, `\x27`},
++ {`"`, `\u0022`},
++ {`'`, `\u0027`},
+ // Allow embedding in HTML without further escaping.
+- {`&amp;`, `\x26amp;`},
++ {`&amp;`, `\u0026amp;`},
+ // Prevent breaking out of text node and element boundaries.
+- {"</script>", `\x3c\/script\x3e`},
+- {"<![CDATA[", `\x3c!\[CDATA\[`},
+- {"]]>", `\]\]\x3e`},
++ {"</script>", `\u003c\/script\u003e`},
++ {"<![CDATA[", `\u003c!\[CDATA\[`},
++ {"]]>", `\]\]\u003e`},
+ // Escaping text spans.
+- {"<!--", `\x3c!\-\-`},
+- {"-->", `\-\-\x3e`},
++ {"<!--", `\u003c!\-\-`},
++ {"-->", `\-\-\u003e`},
+ {"*", `\*`},
+- {"+", `\x2b`},
++ {"+", `\u002b`},
+ {"?", `\?`},
+ {"[](){}", `\[\]\(\)\{\}`},
+ {"$foo|x.y", `\$foo\|x\.y`},
+@@ -284,27 +284,27 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
+ {
+ "jsStrEscaper",
+ jsStrEscaper,
+- "\\0\x01\x02\x03\x04\x05\x06\x07" +
+- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
+- "\x10\x11\x12\x13\x14\x15\x16\x17" +
+- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+- ` !\x22#$%\x26\x27()*\x2b,-.\/` +
+- `0123456789:;\x3c=\x3e?` +
++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
++ `\u0008\t\n\u000b\f\r\u000e\u000f` +
++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
++ ` !\u0022#$%\u0026\u0027()*\u002b,-.\/` +
++ `0123456789:;\u003c=\u003e?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\\]^_` +
+ "`abcdefghijklmno" +
+- "pqrstuvwxyz{|}~\x7f" +
++ "pqrstuvwxyz{|}~\u007f" +
+ "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
+ },
+ {
+ "jsRegexpEscaper",
+ jsRegexpEscaper,
+- "\\0\x01\x02\x03\x04\x05\x06\x07" +
+- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
+- "\x10\x11\x12\x13\x14\x15\x16\x17" +
+- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+- ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` +
+- `0123456789:;\x3c=\x3e\?` +
++ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
++ `\u0008\t\n\u000b\f\r\u000e\u000f` +
++ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
++ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
++ ` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` +
++ `0123456789:;\u003c=\u003e\?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ\[\\\]\^_` +
+ "`abcdefghijklmno" +
+diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go
+index 13e6ba4..86bd4db 100644
+--- a/src/html/template/template_test.go
++++ b/src/html/template/template_test.go
+@@ -6,6 +6,7 @@ package template_test
+
+ import (
+ "bytes"
++ "encoding/json"
+ . "html/template"
+ "strings"
+ "testing"
+@@ -121,6 +122,44 @@ func TestNumbers(t *testing.T) {
+ c.mustExecute(c.root, nil, "12.34 7.5")
+ }
+
++func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) {
++ // See #33671 and #37634 for more context on this.
++ tests := []struct{ name, in string }{
++ {"empty", ""},
++ {"invalid", string(rune(-1))},
++ {"null", "\u0000"},
++ {"unit separator", "\u001F"},
++ {"tab", "\t"},
++ {"gt and lt", "<>"},
++ {"quotes", `'"`},
++ {"ASCII letters", "ASCII letters"},
++ {"Unicode", "ʕ⊙ϖ⊙ʔ"},
++ {"Pizza", "P"},
++ }
++ const (
++ prefix = `<script type="application/ld+json">`
++ suffix = `</script>`
++ templ = prefix + `"{{.}}"` + suffix
++ )
++ tpl := Must(New("JS string is JSON string").Parse(templ))
++ for _, tt := range tests {
++ t.Run(tt.name, func(t *testing.T) {
++ var buf bytes.Buffer
++ if err := tpl.Execute(&buf, tt.in); err != nil {
++ t.Fatalf("Cannot render template: %v", err)
++ }
++ trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix))
++ var got string
++ if err := json.Unmarshal(trimmed, &got); err != nil {
++ t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err)
++ }
++ if got != tt.in {
++ t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in)
++ }
++ })
++ }
++}
++
+ type testCase struct {
+ t *testing.T
+ root *Template
+diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
+index 77294ed..b8a809e 100644
+--- a/src/text/template/exec_test.go
++++ b/src/text/template/exec_test.go
+@@ -911,9 +911,9 @@ func TestJSEscaping(t *testing.T) {
+ {`Go "jump" \`, `Go \"jump\" \\`},
+ {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
+ {"unprintable \uFDFF", `unprintable \uFDFF`},
+- {`<html>`, `\x3Chtml\x3E`},
+- {`no = in attributes`, `no \x3D in attributes`},
+- {`&#x27; does not become HTML entity`, `\x26#x27; does not become HTML entity`},
++ {`<html>`, `\u003Chtml\u003E`},
++ {`no = in attributes`, `no \u003D in attributes`},
++ {`&#x27; does not become HTML entity`, `\u0026#x27; does not become HTML entity`},
+ }
+ for _, tc := range testCases {
+ s := JSEscapeString(tc.in)
+diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
+index 46125bc..f3de9fb 100644
+--- a/src/text/template/funcs.go
++++ b/src/text/template/funcs.go
+@@ -640,10 +640,10 @@ var (
+ jsBackslash = []byte(`\\`)
+ jsApos = []byte(`\'`)
+ jsQuot = []byte(`\"`)
+- jsLt = []byte(`\x3C`)
+- jsGt = []byte(`\x3E`)
+- jsAmp = []byte(`\x26`)
+- jsEq = []byte(`\x3D`)
++ jsLt = []byte(`\u003C`)
++ jsGt = []byte(`\u003E`)
++ jsAmp = []byte(`\u0026`)
++ jsEq = []byte(`\u003D`)
+ )
+
+ // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+--
+2.7.4