Render User Data with Contextual HTML Escaping

Render untrusted names, bodies, and links through html/template so contextual escaping blocks script injection and bad URLs.

GoSecurity Boundaries

Code

snippet
package main

import (
	"bytes"
	"fmt"
	"html/template"
	"strings"
)

type Comment struct {
	Author string
	Body   string
	Link   string
}

func main() {
	page := template.Must(template.New("comment").Parse(
		`<article><h2>{{.Author}}</h2><p>{{.Body}}</p><a href="{{.Link}}">profile</a></article>`,
	))
	comment := Comment{
		Author: "<b>Mallory</b>",
		Body:   `<script>alert("x")</script>`,
		Link:   "javascript:alert(1)",
	}

	var output bytes.Buffer
	if err := page.Execute(&output, comment); err != nil {
		panic(err)
	}
	rendered := output.String()
	fmt.Println(rendered)

	if strings.Contains(rendered, "<script>") {
		panic("script tag was not escaped")
	}
	if !strings.Contains(rendered, "&lt;script&gt;") {
		panic("expected escaped body text")
	}
	if !strings.Contains(rendered, "#ZgotmplZ") {
		panic("expected dangerous URL to be blocked")
	}
}