| 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/3] 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/js.go | 70 +++++++++++++++++++++++++++------------------- |
| src/text/template/funcs.go | 8 +++--- |
| 2 files changed, 46 insertions(+), 32 deletions(-) |
| |
| 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/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 |