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 @@
1From 6fc21505614f36178df0dad7034b6b8e3f7588d5 Mon Sep 17 00:00:00 2001
2From: empijei <robclap8@gmail.com>
3Date: Fri, 27 Mar 2020 19:27:55 +0100
4Subject: [PATCH 2/6] html/template,text/template: switch to Unicode escapes
5 for JSON compatibility
6MIME-Version: 1.0
7Content-Type: text/plain; charset=UTF-8
8Content-Transfer-Encoding: 8bit
9
10The existing implementation is not compatible with JSON
11escape as it uses hex escaping.
12Unicode escape, instead, is valid for both JSON and JS.
13This fix avoids creating a separate escaping context for
14scripts of type "application/ld+json" and it is more
15future-proof in case more JSON+JS contexts get added
16to the platform (e.g. import maps).
17
18Fixes #33671
19Fixes #37634
20
21Change-Id: Id6f6524b4abc52e81d9d744d46bbe5bf2e081543
22Reviewed-on: https://go-review.googlesource.com/c/go/+/226097
23Reviewed-by: Carl Johnson <me@carlmjohnson.net>
24Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
25Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
26TryBot-Result: Gobot Gobot <gobot@golang.org>
27
28Dependency Patch #2
29
30Upstream-Status: Backport from https://github.com/golang/go/commit/d4d298040d072ddacea0e0d6b55fb148fff18070
31CVE: CVE-2023-24538
32Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
33---
34 src/html/template/content_test.go | 70 +++++++++++++++++++-------------------
35 src/html/template/escape_test.go | 6 ++--
36 src/html/template/example_test.go | 6 ++--
37 src/html/template/js.go | 70 +++++++++++++++++++++++---------------
38 src/html/template/js_test.go | 68 ++++++++++++++++++------------------
39 src/html/template/template_test.go | 39 +++++++++++++++++++++
40 src/text/template/exec_test.go | 6 ++--
41 src/text/template/funcs.go | 8 ++---
42 8 files changed, 163 insertions(+), 110 deletions(-)
43
44diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
45index 72d56f5..bd86527 100644
46--- a/src/html/template/content_test.go
47+++ b/src/html/template/content_test.go
48@@ -18,7 +18,7 @@ func TestTypedContent(t *testing.T) {
49 HTML(`Hello, <b>World</b> &amp;tc!`),
50 HTMLAttr(` dir="ltr"`),
51 JS(`c && alert("Hello, World!");`),
52- JSStr(`Hello, World & O'Reilly\x21`),
53+ JSStr(`Hello, World & O'Reilly\u0021`),
54 URL(`greeting=H%69,&addressee=(World)`),
55 Srcset(`greeting=H%69,&addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`),
56 URL(`,foo/,`),
57@@ -70,7 +70,7 @@ func TestTypedContent(t *testing.T) {
58 `Hello, <b>World</b> &amp;tc!`,
59 ` dir=&#34;ltr&#34;`,
60 `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
61- `Hello, World &amp; O&#39;Reilly\x21`,
62+ `Hello, World &amp; O&#39;Reilly\u0021`,
63 `greeting=H%69,&amp;addressee=(World)`,
64 `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
65 `,foo/,`,
66@@ -100,7 +100,7 @@ func TestTypedContent(t *testing.T) {
67 `Hello,&#32;World&#32;&amp;tc!`,
68 `&#32;dir&#61;&#34;ltr&#34;`,
69 `c&#32;&amp;&amp;&#32;alert(&#34;Hello,&#32;World!&#34;);`,
70- `Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\x21`,
71+ `Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\u0021`,
72 `greeting&#61;H%69,&amp;addressee&#61;(World)`,
73 `greeting&#61;H%69,&amp;addressee&#61;(World)&#32;2x,&#32;https://golang.org/favicon.ico&#32;500.5w`,
74 `,foo/,`,
75@@ -115,7 +115,7 @@ func TestTypedContent(t *testing.T) {
76 `Hello, World &amp;tc!`,
77 ` dir=&#34;ltr&#34;`,
78 `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
79- `Hello, World &amp; O&#39;Reilly\x21`,
80+ `Hello, World &amp; O&#39;Reilly\u0021`,
81 `greeting=H%69,&amp;addressee=(World)`,
82 `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
83 `,foo/,`,
84@@ -130,7 +130,7 @@ func TestTypedContent(t *testing.T) {
85 `Hello, &lt;b&gt;World&lt;/b&gt; &amp;tc!`,
86 ` dir=&#34;ltr&#34;`,
87 `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
88- `Hello, World &amp; O&#39;Reilly\x21`,
89+ `Hello, World &amp; O&#39;Reilly\u0021`,
90 `greeting=H%69,&amp;addressee=(World)`,
91 `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
92 `,foo/,`,
93@@ -146,7 +146,7 @@ func TestTypedContent(t *testing.T) {
94 // Not escaped.
95 `c && alert("Hello, World!");`,
96 // Escape sequence not over-escaped.
97- `"Hello, World & O'Reilly\x21"`,
98+ `"Hello, World & O'Reilly\u0021"`,
99 `"greeting=H%69,\u0026addressee=(World)"`,
100 `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
101 `",foo/,"`,
102@@ -162,7 +162,7 @@ func TestTypedContent(t *testing.T) {
103 // Not JS escaped but HTML escaped.
104 `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
105 // Escape sequence not over-escaped.
106- `&#34;Hello, World &amp; O&#39;Reilly\x21&#34;`,
107+ `&#34;Hello, World &amp; O&#39;Reilly\u0021&#34;`,
108 `&#34;greeting=H%69,\u0026addressee=(World)&#34;`,
109 `&#34;greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w&#34;`,
110 `&#34;,foo/,&#34;`,
111@@ -171,30 +171,30 @@ func TestTypedContent(t *testing.T) {
112 {
113 `<script>alert("{{.}}")</script>`,
114 []string{
115- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
116- `a[href =~ \x22\/\/example.com\x22]#foo`,
117- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
118- ` dir=\x22ltr\x22`,
119- `c \x26\x26 alert(\x22Hello, World!\x22);`,
120+ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
121+ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
122+ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
123+ ` dir=\u0022ltr\u0022`,
124+ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
125 // Escape sequence not over-escaped.
126- `Hello, World \x26 O\x27Reilly\x21`,
127- `greeting=H%69,\x26addressee=(World)`,
128- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
129+ `Hello, World \u0026 O\u0027Reilly\u0021`,
130+ `greeting=H%69,\u0026addressee=(World)`,
131+ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
132 `,foo\/,`,
133 },
134 },
135 {
136 `<script type="text/javascript">alert("{{.}}")</script>`,
137 []string{
138- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
139- `a[href =~ \x22\/\/example.com\x22]#foo`,
140- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
141- ` dir=\x22ltr\x22`,
142- `c \x26\x26 alert(\x22Hello, World!\x22);`,
143+ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
144+ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
145+ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
146+ ` dir=\u0022ltr\u0022`,
147+ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
148 // Escape sequence not over-escaped.
149- `Hello, World \x26 O\x27Reilly\x21`,
150- `greeting=H%69,\x26addressee=(World)`,
151- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
152+ `Hello, World \u0026 O\u0027Reilly\u0021`,
153+ `greeting=H%69,\u0026addressee=(World)`,
154+ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
155 `,foo\/,`,
156 },
157 },
158@@ -208,7 +208,7 @@ func TestTypedContent(t *testing.T) {
159 // Not escaped.
160 `c && alert("Hello, World!");`,
161 // Escape sequence not over-escaped.
162- `"Hello, World & O'Reilly\x21"`,
163+ `"Hello, World & O'Reilly\u0021"`,
164 `"greeting=H%69,\u0026addressee=(World)"`,
165 `"greeting=H%69,\u0026addressee=(World) 2x, https://golang.org/favicon.ico 500.5w"`,
166 `",foo/,"`,
167@@ -224,7 +224,7 @@ func TestTypedContent(t *testing.T) {
168 `Hello, <b>World</b> &amp;tc!`,
169 ` dir=&#34;ltr&#34;`,
170 `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
171- `Hello, World &amp; O&#39;Reilly\x21`,
172+ `Hello, World &amp; O&#39;Reilly\u0021`,
173 `greeting=H%69,&amp;addressee=(World)`,
174 `greeting=H%69,&amp;addressee=(World) 2x, https://golang.org/favicon.ico 500.5w`,
175 `,foo/,`,
176@@ -233,15 +233,15 @@ func TestTypedContent(t *testing.T) {
177 {
178 `<button onclick='alert("{{.}}")'>`,
179 []string{
180- `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
181- `a[href =~ \x22\/\/example.com\x22]#foo`,
182- `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
183- ` dir=\x22ltr\x22`,
184- `c \x26\x26 alert(\x22Hello, World!\x22);`,
185+ `\u003cb\u003e \u0022foo%\u0022 O\u0027Reilly \u0026bar;`,
186+ `a[href =~ \u0022\/\/example.com\u0022]#foo`,
187+ `Hello, \u003cb\u003eWorld\u003c\/b\u003e \u0026amp;tc!`,
188+ ` dir=\u0022ltr\u0022`,
189+ `c \u0026\u0026 alert(\u0022Hello, World!\u0022);`,
190 // Escape sequence not over-escaped.
191- `Hello, World \x26 O\x27Reilly\x21`,
192- `greeting=H%69,\x26addressee=(World)`,
193- `greeting=H%69,\x26addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
194+ `Hello, World \u0026 O\u0027Reilly\u0021`,
195+ `greeting=H%69,\u0026addressee=(World)`,
196+ `greeting=H%69,\u0026addressee=(World) 2x, https:\/\/golang.org\/favicon.ico 500.5w`,
197 `,foo\/,`,
198 },
199 },
200@@ -253,7 +253,7 @@ func TestTypedContent(t *testing.T) {
201 `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
202 `%20dir%3d%22ltr%22`,
203 `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
204- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
205+ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
206 // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done.
207 `greeting=H%69,&amp;addressee=%28World%29`,
208 `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
209@@ -268,7 +268,7 @@ func TestTypedContent(t *testing.T) {
210 `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
211 `%20dir%3d%22ltr%22`,
212 `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
213- `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
214+ `Hello%2c%20World%20%26%20O%27Reilly%5cu0021`,
215 // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done.
216 `greeting=H%69,&addressee=%28World%29`,
217 `greeting%3dH%2569%2c%26addressee%3d%28World%29%202x%2c%20https%3a%2f%2fgolang.org%2ffavicon.ico%20500.5w`,
218diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
219index e72a9ba..c709660 100644
220--- a/src/html/template/escape_test.go
221+++ b/src/html/template/escape_test.go
222@@ -238,7 +238,7 @@ func TestEscape(t *testing.T) {
223 {
224 "jsStr",
225 "<button onclick='alert(&quot;{{.H}}&quot;)'>",
226- `<button onclick='alert(&quot;\x3cHello\x3e&quot;)'>`,
227+ `<button onclick='alert(&quot;\u003cHello\u003e&quot;)'>`,
228 },
229 {
230 "badMarshaler",
231@@ -259,7 +259,7 @@ func TestEscape(t *testing.T) {
232 {
233 "jsRe",
234 `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`,
235- `<button onclick='alert(/foo\x2bbar/.test(""))'>`,
236+ `<button onclick='alert(/foo\u002bbar/.test(""))'>`,
237 },
238 {
239 "jsReBlank",
240@@ -825,7 +825,7 @@ func TestEscapeSet(t *testing.T) {
241 "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`,
242 "helper": `{{11}} of {{"<100>"}}`,
243 },
244- `<button onclick="title='11 of \x3c100\x3e'; ...">11 of &lt;100&gt;</button>`,
245+ `<button onclick="title='11 of \u003c100\u003e'; ...">11 of &lt;100&gt;</button>`,
246 },
247 // A non-recursive template that ends in a different context.
248 // helper starts in jsCtxRegexp and ends in jsCtxDivOp.
249diff --git a/src/html/template/example_test.go b/src/html/template/example_test.go
250index 9d965f1..6cf936f 100644
251--- a/src/html/template/example_test.go
252+++ b/src/html/template/example_test.go
253@@ -116,9 +116,9 @@ func Example_escape() {
254 // &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
255 // &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;tasty@example.com&gt;
256 // &#34;Fran &amp; Freddie&#39;s Diner&#34;32&lt;tasty@example.com&gt;
257- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
258- // \"Fran \x26 Freddie\'s Diner\" \x3Ctasty@example.com\x3E
259- // \"Fran \x26 Freddie\'s Diner\"32\x3Ctasty@example.com\x3E
260+ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
261+ // \"Fran \u0026 Freddie\'s Diner\" \u003Ctasty@example.com\u003E
262+ // \"Fran \u0026 Freddie\'s Diner\"32\u003Ctasty@example.com\u003E
263 // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
264
265 }
266diff --git a/src/html/template/js.go b/src/html/template/js.go
267index 0e91458..ea9c183 100644
268--- a/src/html/template/js.go
269+++ b/src/html/template/js.go
270@@ -163,7 +163,6 @@ func jsValEscaper(args ...interface{}) string {
271 }
272 // TODO: detect cycles before calling Marshal which loops infinitely on
273 // cyclic data. This may be an unacceptable DoS risk.
274-
275 b, err := json.Marshal(a)
276 if err != nil {
277 // Put a space before comment so that if it is flush against
278@@ -178,8 +177,8 @@ func jsValEscaper(args ...interface{}) string {
279 // TODO: maybe post-process output to prevent it from containing
280 // "<!--", "-->", "<![CDATA[", "]]>", or "</script"
281 // in case custom marshalers produce output containing those.
282-
283- // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
284+ // Note: Do not use \x escaping to save bytes because it is not JSON compatible and this escaper
285+ // supports ld+json content-type.
286 if len(b) == 0 {
287 // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should
288 // not cause the output `x=y/*z`.
289@@ -260,6 +259,8 @@ func replace(s string, replacementTable []string) string {
290 r, w = utf8.DecodeRuneInString(s[i:])
291 var repl string
292 switch {
293+ case int(r) < len(lowUnicodeReplacementTable):
294+ repl = lowUnicodeReplacementTable[r]
295 case int(r) < len(replacementTable) && replacementTable[r] != "":
296 repl = replacementTable[r]
297 case r == '\u2028':
298@@ -283,67 +284,80 @@ func replace(s string, replacementTable []string) string {
299 return b.String()
300 }
301
302+var lowUnicodeReplacementTable = []string{
303+ 0: `\u0000`, 1: `\u0001`, 2: `\u0002`, 3: `\u0003`, 4: `\u0004`, 5: `\u0005`, 6: `\u0006`,
304+ '\a': `\u0007`,
305+ '\b': `\u0008`,
306+ '\t': `\t`,
307+ '\n': `\n`,
308+ '\v': `\u000b`, // "\v" == "v" on IE 6.
309+ '\f': `\f`,
310+ '\r': `\r`,
311+ 0xe: `\u000e`, 0xf: `\u000f`, 0x10: `\u0010`, 0x11: `\u0011`, 0x12: `\u0012`, 0x13: `\u0013`,
312+ 0x14: `\u0014`, 0x15: `\u0015`, 0x16: `\u0016`, 0x17: `\u0017`, 0x18: `\u0018`, 0x19: `\u0019`,
313+ 0x1a: `\u001a`, 0x1b: `\u001b`, 0x1c: `\u001c`, 0x1d: `\u001d`, 0x1e: `\u001e`, 0x1f: `\u001f`,
314+}
315+
316 var jsStrReplacementTable = []string{
317- 0: `\0`,
318+ 0: `\u0000`,
319 '\t': `\t`,
320 '\n': `\n`,
321- '\v': `\x0b`, // "\v" == "v" on IE 6.
322+ '\v': `\u000b`, // "\v" == "v" on IE 6.
323 '\f': `\f`,
324 '\r': `\r`,
325 // Encode HTML specials as hex so the output can be embedded
326 // in HTML attributes without further encoding.
327- '"': `\x22`,
328- '&': `\x26`,
329- '\'': `\x27`,
330- '+': `\x2b`,
331+ '"': `\u0022`,
332+ '&': `\u0026`,
333+ '\'': `\u0027`,
334+ '+': `\u002b`,
335 '/': `\/`,
336- '<': `\x3c`,
337- '>': `\x3e`,
338+ '<': `\u003c`,
339+ '>': `\u003e`,
340 '\\': `\\`,
341 }
342
343 // jsStrNormReplacementTable is like jsStrReplacementTable but does not
344 // overencode existing escapes since this table has no entry for `\`.
345 var jsStrNormReplacementTable = []string{
346- 0: `\0`,
347+ 0: `\u0000`,
348 '\t': `\t`,
349 '\n': `\n`,
350- '\v': `\x0b`, // "\v" == "v" on IE 6.
351+ '\v': `\u000b`, // "\v" == "v" on IE 6.
352 '\f': `\f`,
353 '\r': `\r`,
354 // Encode HTML specials as hex so the output can be embedded
355 // in HTML attributes without further encoding.
356- '"': `\x22`,
357- '&': `\x26`,
358- '\'': `\x27`,
359- '+': `\x2b`,
360+ '"': `\u0022`,
361+ '&': `\u0026`,
362+ '\'': `\u0027`,
363+ '+': `\u002b`,
364 '/': `\/`,
365- '<': `\x3c`,
366- '>': `\x3e`,
367+ '<': `\u003c`,
368+ '>': `\u003e`,
369 }
370-
371 var jsRegexpReplacementTable = []string{
372- 0: `\0`,
373+ 0: `\u0000`,
374 '\t': `\t`,
375 '\n': `\n`,
376- '\v': `\x0b`, // "\v" == "v" on IE 6.
377+ '\v': `\u000b`, // "\v" == "v" on IE 6.
378 '\f': `\f`,
379 '\r': `\r`,
380 // Encode HTML specials as hex so the output can be embedded
381 // in HTML attributes without further encoding.
382- '"': `\x22`,
383+ '"': `\u0022`,
384 '$': `\$`,
385- '&': `\x26`,
386- '\'': `\x27`,
387+ '&': `\u0026`,
388+ '\'': `\u0027`,
389 '(': `\(`,
390 ')': `\)`,
391 '*': `\*`,
392- '+': `\x2b`,
393+ '+': `\u002b`,
394 '-': `\-`,
395 '.': `\.`,
396 '/': `\/`,
397- '<': `\x3c`,
398- '>': `\x3e`,
399+ '<': `\u003c`,
400+ '>': `\u003e`,
401 '?': `\?`,
402 '[': `\[`,
403 '\\': `\\`,
404diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
405index 075adaa..d7ee47b 100644
406--- a/src/html/template/js_test.go
407+++ b/src/html/template/js_test.go
408@@ -137,7 +137,7 @@ func TestJSValEscaper(t *testing.T) {
409 {"foo", `"foo"`},
410 // Newlines.
411 {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
412- // "\v" == "v" on IE 6 so use "\x0b" instead.
413+ // "\v" == "v" on IE 6 so use "\u000b" instead.
414 {"\t\x0b", `"\t\u000b"`},
415 {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
416 {[]interface{}{}, "[]"},
417@@ -173,7 +173,7 @@ func TestJSStrEscaper(t *testing.T) {
418 }{
419 {"", ``},
420 {"foo", `foo`},
421- {"\u0000", `\0`},
422+ {"\u0000", `\u0000`},
423 {"\t", `\t`},
424 {"\n", `\n`},
425 {"\r", `\r`},
426@@ -183,14 +183,14 @@ func TestJSStrEscaper(t *testing.T) {
427 {"\\n", `\\n`},
428 {"foo\r\nbar", `foo\r\nbar`},
429 // Preserve attribute boundaries.
430- {`"`, `\x22`},
431- {`'`, `\x27`},
432+ {`"`, `\u0022`},
433+ {`'`, `\u0027`},
434 // Allow embedding in HTML without further escaping.
435- {`&amp;`, `\x26amp;`},
436+ {`&amp;`, `\u0026amp;`},
437 // Prevent breaking out of text node and element boundaries.
438- {"</script>", `\x3c\/script\x3e`},
439- {"<![CDATA[", `\x3c![CDATA[`},
440- {"]]>", `]]\x3e`},
441+ {"</script>", `\u003c\/script\u003e`},
442+ {"<![CDATA[", `\u003c![CDATA[`},
443+ {"]]>", `]]\u003e`},
444 // https://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span
445 // "The text in style, script, title, and textarea elements
446 // must not have an escaping text span start that is not
447@@ -201,11 +201,11 @@ func TestJSStrEscaper(t *testing.T) {
448 // allow regular text content to be interpreted as script
449 // allowing script execution via a combination of a JS string
450 // injection followed by an HTML text injection.
451- {"<!--", `\x3c!--`},
452- {"-->", `--\x3e`},
453+ {"<!--", `\u003c!--`},
454+ {"-->", `--\u003e`},
455 // From https://code.google.com/p/doctype/wiki/ArticleUtf7
456 {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
457- `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`,
458+ `\u002bADw-script\u002bAD4-alert(1)\u002bADw-\/script\u002bAD4-`,
459 },
460 // Invalid UTF-8 sequence
461 {"foo\xA0bar", "foo\xA0bar"},
462@@ -228,7 +228,7 @@ func TestJSRegexpEscaper(t *testing.T) {
463 }{
464 {"", `(?:)`},
465 {"foo", `foo`},
466- {"\u0000", `\0`},
467+ {"\u0000", `\u0000`},
468 {"\t", `\t`},
469 {"\n", `\n`},
470 {"\r", `\r`},
471@@ -238,19 +238,19 @@ func TestJSRegexpEscaper(t *testing.T) {
472 {"\\n", `\\n`},
473 {"foo\r\nbar", `foo\r\nbar`},
474 // Preserve attribute boundaries.
475- {`"`, `\x22`},
476- {`'`, `\x27`},
477+ {`"`, `\u0022`},
478+ {`'`, `\u0027`},
479 // Allow embedding in HTML without further escaping.
480- {`&amp;`, `\x26amp;`},
481+ {`&amp;`, `\u0026amp;`},
482 // Prevent breaking out of text node and element boundaries.
483- {"</script>", `\x3c\/script\x3e`},
484- {"<![CDATA[", `\x3c!\[CDATA\[`},
485- {"]]>", `\]\]\x3e`},
486+ {"</script>", `\u003c\/script\u003e`},
487+ {"<![CDATA[", `\u003c!\[CDATA\[`},
488+ {"]]>", `\]\]\u003e`},
489 // Escaping text spans.
490- {"<!--", `\x3c!\-\-`},
491- {"-->", `\-\-\x3e`},
492+ {"<!--", `\u003c!\-\-`},
493+ {"-->", `\-\-\u003e`},
494 {"*", `\*`},
495- {"+", `\x2b`},
496+ {"+", `\u002b`},
497 {"?", `\?`},
498 {"[](){}", `\[\]\(\)\{\}`},
499 {"$foo|x.y", `\$foo\|x\.y`},
500@@ -284,27 +284,27 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
501 {
502 "jsStrEscaper",
503 jsStrEscaper,
504- "\\0\x01\x02\x03\x04\x05\x06\x07" +
505- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
506- "\x10\x11\x12\x13\x14\x15\x16\x17" +
507- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
508- ` !\x22#$%\x26\x27()*\x2b,-.\/` +
509- `0123456789:;\x3c=\x3e?` +
510+ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
511+ `\u0008\t\n\u000b\f\r\u000e\u000f` +
512+ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
513+ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
514+ ` !\u0022#$%\u0026\u0027()*\u002b,-.\/` +
515+ `0123456789:;\u003c=\u003e?` +
516 `@ABCDEFGHIJKLMNO` +
517 `PQRSTUVWXYZ[\\]^_` +
518 "`abcdefghijklmno" +
519- "pqrstuvwxyz{|}~\x7f" +
520+ "pqrstuvwxyz{|}~\u007f" +
521 "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
522 },
523 {
524 "jsRegexpEscaper",
525 jsRegexpEscaper,
526- "\\0\x01\x02\x03\x04\x05\x06\x07" +
527- "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
528- "\x10\x11\x12\x13\x14\x15\x16\x17" +
529- "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
530- ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` +
531- `0123456789:;\x3c=\x3e\?` +
532+ `\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007` +
533+ `\u0008\t\n\u000b\f\r\u000e\u000f` +
534+ `\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017` +
535+ `\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f` +
536+ ` !\u0022#\$%\u0026\u0027\(\)\*\u002b,\-\.\/` +
537+ `0123456789:;\u003c=\u003e\?` +
538 `@ABCDEFGHIJKLMNO` +
539 `PQRSTUVWXYZ\[\\\]\^_` +
540 "`abcdefghijklmno" +
541diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go
542index 13e6ba4..86bd4db 100644
543--- a/src/html/template/template_test.go
544+++ b/src/html/template/template_test.go
545@@ -6,6 +6,7 @@ package template_test
546
547 import (
548 "bytes"
549+ "encoding/json"
550 . "html/template"
551 "strings"
552 "testing"
553@@ -121,6 +122,44 @@ func TestNumbers(t *testing.T) {
554 c.mustExecute(c.root, nil, "12.34 7.5")
555 }
556
557+func TestStringsInScriptsWithJsonContentTypeAreCorrectlyEscaped(t *testing.T) {
558+ // See #33671 and #37634 for more context on this.
559+ tests := []struct{ name, in string }{
560+ {"empty", ""},
561+ {"invalid", string(rune(-1))},
562+ {"null", "\u0000"},
563+ {"unit separator", "\u001F"},
564+ {"tab", "\t"},
565+ {"gt and lt", "<>"},
566+ {"quotes", `'"`},
567+ {"ASCII letters", "ASCII letters"},
568+ {"Unicode", "ʕ⊙ϖ⊙ʔ"},
569+ {"Pizza", "P"},
570+ }
571+ const (
572+ prefix = `<script type="application/ld+json">`
573+ suffix = `</script>`
574+ templ = prefix + `"{{.}}"` + suffix
575+ )
576+ tpl := Must(New("JS string is JSON string").Parse(templ))
577+ for _, tt := range tests {
578+ t.Run(tt.name, func(t *testing.T) {
579+ var buf bytes.Buffer
580+ if err := tpl.Execute(&buf, tt.in); err != nil {
581+ t.Fatalf("Cannot render template: %v", err)
582+ }
583+ trimmed := bytes.TrimSuffix(bytes.TrimPrefix(buf.Bytes(), []byte(prefix)), []byte(suffix))
584+ var got string
585+ if err := json.Unmarshal(trimmed, &got); err != nil {
586+ t.Fatalf("Cannot parse JS string %q as JSON: %v", trimmed[1:len(trimmed)-1], err)
587+ }
588+ if got != tt.in {
589+ t.Errorf("Serialization changed the string value: got %q want %q", got, tt.in)
590+ }
591+ })
592+ }
593+}
594+
595 type testCase struct {
596 t *testing.T
597 root *Template
598diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
599index 77294ed..b8a809e 100644
600--- a/src/text/template/exec_test.go
601+++ b/src/text/template/exec_test.go
602@@ -911,9 +911,9 @@ func TestJSEscaping(t *testing.T) {
603 {`Go "jump" \`, `Go \"jump\" \\`},
604 {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
605 {"unprintable \uFDFF", `unprintable \uFDFF`},
606- {`<html>`, `\x3Chtml\x3E`},
607- {`no = in attributes`, `no \x3D in attributes`},
608- {`&#x27; does not become HTML entity`, `\x26#x27; does not become HTML entity`},
609+ {`<html>`, `\u003Chtml\u003E`},
610+ {`no = in attributes`, `no \u003D in attributes`},
611+ {`&#x27; does not become HTML entity`, `\u0026#x27; does not become HTML entity`},
612 }
613 for _, tc := range testCases {
614 s := JSEscapeString(tc.in)
615diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
616index 46125bc..f3de9fb 100644
617--- a/src/text/template/funcs.go
618+++ b/src/text/template/funcs.go
619@@ -640,10 +640,10 @@ var (
620 jsBackslash = []byte(`\\`)
621 jsApos = []byte(`\'`)
622 jsQuot = []byte(`\"`)
623- jsLt = []byte(`\x3C`)
624- jsGt = []byte(`\x3E`)
625- jsAmp = []byte(`\x26`)
626- jsEq = []byte(`\x3D`)
627+ jsLt = []byte(`\u003C`)
628+ jsGt = []byte(`\u003E`)
629+ jsAmp = []byte(`\u0026`)
630+ jsEq = []byte(`\u003D`)
631 )
632
633 // JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
634--
6352.7.4