Skip to content

Commit 94e9a5e

Browse files
empijeiFiloSottile
authored andcommitted
text/template: harden JSEscape to also escape ampersand and equal
Ampersand and equal are not dangerous in a JS/JSString context but they might cause issues if interpolated in HTML attributes. This change makes it harder to introduce XSS by misusing escaping. Thanks to t1ddl3r <[email protected]> for reporting this common misuse scenario. Fixes #35665 Change-Id: Ice6416477bba4cb2ba2fe2cfdc20e027957255c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/207637 Reviewed-by: Filippo Valsorda <[email protected]> Reviewed-by: Mike Samuel <[email protected]> Reviewed-by: Andrew Bonventre <[email protected]> Reviewed-by: Daniel Martí <[email protected]>
1 parent f4a8bf1 commit 94e9a5e

File tree

3 files changed

+12
-4
lines changed

3 files changed

+12
-4
lines changed

src/html/template/example_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ func Example_escape() {
116116
// &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;[email protected]&gt;
117117
// &#34;Fran &amp; Freddie&#39;s Diner&#34; &lt;[email protected]&gt;
118118
// &#34;Fran &amp; Freddie&#39;s Diner&#34;32&lt;[email protected]&gt;
119-
// \"Fran & Freddie\'s Diner\" \[email protected]\x3E
120-
// \"Fran & Freddie\'s Diner\" \[email protected]\x3E
121-
// \"Fran & Freddie\'s Diner\"32\[email protected]\x3E
119+
// \"Fran \x26 Freddie\'s Diner\" \[email protected]\x3E
120+
// \"Fran \x26 Freddie\'s Diner\" \[email protected]\x3E
121+
// \"Fran \x26 Freddie\'s Diner\"32\[email protected]\x3E
122122
// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
123123

124124
}

src/text/template/exec_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,8 @@ func TestJSEscaping(t *testing.T) {
909909
{`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
910910
{"unprintable \uFDFF", `unprintable \uFDFF`},
911911
{`<html>`, `\x3Chtml\x3E`},
912+
{`no = in attributes`, `no \x3D in attributes`},
913+
{`&#x27; does not become HTML entity`, `\x26#x27; does not become HTML entity`},
912914
}
913915
for _, tc := range testCases {
914916
s := JSEscapeString(tc.in)

src/text/template/funcs.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,8 @@ var (
642642
jsQuot = []byte(`\"`)
643643
jsLt = []byte(`\x3C`)
644644
jsGt = []byte(`\x3E`)
645+
jsAmp = []byte(`\x26`)
646+
jsEq = []byte(`\x3D`)
645647
)
646648

647649
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
@@ -670,6 +672,10 @@ func JSEscape(w io.Writer, b []byte) {
670672
w.Write(jsLt)
671673
case '>':
672674
w.Write(jsGt)
675+
case '&':
676+
w.Write(jsAmp)
677+
case '=':
678+
w.Write(jsEq)
673679
default:
674680
w.Write(jsLowUni)
675681
t, b := c>>4, c&0x0f
@@ -704,7 +710,7 @@ func JSEscapeString(s string) string {
704710

705711
func jsIsSpecial(r rune) bool {
706712
switch r {
707-
case '\\', '\'', '"', '<', '>':
713+
case '\\', '\'', '"', '<', '>', '&', '=':
708714
return true
709715
}
710716
return r < ' ' || utf8.RuneSelf <= r

0 commit comments

Comments
 (0)