]> Cypherpunks.ru repositories - gostls13.git/commitdiff
text/template: harden JSEscape to also escape ampersand and equal
authorRoberto Clapis <robclap8@gmail.com>
Mon, 18 Nov 2019 09:05:07 +0000 (10:05 +0100)
committerFilippo Valsorda <filippo@golang.org>
Thu, 21 Nov 2019 22:20:17 +0000 (22:20 +0000)
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 <t1ddl3r@gmail.com> 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 <filippo@golang.org>
Reviewed-by: Mike Samuel <mikesamuel@gmail.com>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
src/html/template/example_test.go
src/text/template/exec_test.go
src/text/template/funcs.go

index 533c0dd9616a022b852a872708c351d10e525785..9d965f1943cfe95843e98485a71d26a4423e7569 100644 (file)
@@ -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 & Freddie\'s Diner\" \x3Ctasty@example.com\x3E
-       // \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E
-       // \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E
+       // \"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
        // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
 
 }
index 2b299b0bf613ea693f1e30df18cfd540794370a4..aa5cd4c5525c1801114d99dd16f729d6d630cf0b 100644 (file)
@@ -909,6 +909,8 @@ func TestJSEscaping(t *testing.T) {
                {`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`},
        }
        for _, tc := range testCases {
                s := JSEscapeString(tc.in)
index 0985eda31757c4906474ae9c8015350b06ea5647..0568c798a842cc5b77c05382154c36b0f84c66eb 100644 (file)
@@ -642,6 +642,8 @@ var (
        jsQuot      = []byte(`\"`)
        jsLt        = []byte(`\x3C`)
        jsGt        = []byte(`\x3E`)
+       jsAmp       = []byte(`\x26`)
+       jsEq        = []byte(`\x3D`)
 )
 
 // 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) {
                                w.Write(jsLt)
                        case '>':
                                w.Write(jsGt)
+                       case '&':
+                               w.Write(jsAmp)
+                       case '=':
+                               w.Write(jsEq)
                        default:
                                w.Write(jsLowUni)
                                t, b := c>>4, c&0x0f
@@ -704,7 +710,7 @@ func JSEscapeString(s string) string {
 
 func jsIsSpecial(r rune) bool {
        switch r {
-       case '\\', '\'', '"', '<', '>':
+       case '\\', '\'', '"', '<', '>', '&', '=':
                return true
        }
        return r < ' ' || utf8.RuneSelf <= r