Cross-site scripting via HTML template escaping bypass¶
ID: go/html-template-escaping-bypass-xss
Kind: path-problem
Security severity: 6.1
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-079
- external/cwe/cwe-116
Query suites:
- go-code-scanning.qls
- go-security-extended.qls
- go-security-and-quality.qls
Click to see the query in the CodeQL repository
In Go, the html/template
package has a few special types (HTML
, HTMLAttr
, JS
, JSStr
, CSS
, Srcset
, and URL
) that allow values to be rendered as-is in the template, avoiding the escaping that all the other strings go through.
Using them on user-provided values allows for a cross-site scripting vulnerability.
Recommendation¶
Make sure to never use those types on untrusted content.
Example¶
In the first example you can see the special types and how they are used in a template:
package main
import (
"html/template"
"net/http"
)
func bad(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
tmpl, _ := template.New("test").Parse(`<b>Hi {{.}}</b>`)
tmpl.Execute(w, template.HTML(username))
}
To avoid XSS, all user input should be a normal string type.
package main
import (
"html/template"
"net/http"
)
func good(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
username := r.Form.Get("username")
tmpl, _ := template.New("test").Parse(`<b>Hi {{.}}</b>`)
tmpl.Execute(w, username)
}