all repos — gomponents @ 3e9e00ca0dc6b58e58694d84c97a1d2f2ab4002b

HTML components in pure Go

Escape Attr values (#77)

Because this can be a place of injection if untrusted data is passed, escape all attribute values.

Fixes #74.
Markus Wüstenberg markus@maragu.dk
Tue, 18 May 2021 14:21:53 +0200
commit

3e9e00ca0dc6b58e58694d84c97a1d2f2ab4002b

parent

ac7471aac69fcb4e9cd460dae39b0183ec3d10df

2 files changed, 15 insertions(+), 1 deletions(-)

jump to
M gomponents.gogomponents.go
@@ -160,7 +160,7 @@ if a.value == nil { 		_, err := w.Write([]byte(" " + a.name))
 		return err
 	}
-	_, err := w.Write([]byte(" " + a.name + `="` + *a.value + `"`))
+	_, err := w.Write([]byte(" " + a.name + `="` + template.HTMLEscapeString(*a.value) + `"`))
 	return err
 }
 
M gomponents_test.gogomponents_test.go
@@ -54,6 +54,11 @@ if s != " required" { 			t.FailNow()
 		}
 	})
+
+	t.Run("escapes attribute values", func(t *testing.T) {
+		a := g.Attr(`id`, `hat"><script`)
+		assert.Equal(t, ` id="hat&#34;&gt;&lt;script"`, a)
+	})
 }
 
 func BenchmarkAttr(b *testing.B) {
@@ -129,6 +134,15 @@ t.Run("returns render error on cannot write", func(t *testing.T) { 		e := g.El("div")
 		err := e.Render(&erroringWriter{})
 		assert.Error(t, err)
+	})
+}
+
+func BenchmarkEl(b *testing.B) {
+	b.Run("normal elements", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			e := g.El("div")
+			_ = e.Render(&strings.Builder{})
+		}
 	})
 }