Using template.HTML with fmt.Sprintf
Formatting strings with user input then passing to template.HTML.
XSS vulnerabilities occur when formatted strings containing user input are passed to template.HTML, which bypasses Go's automatic HTML escaping. This allows attackers to inject malicious scripts that execute in users' browsers, steal sessions, manipulate DOM content, or perform unauthorized actions.
package main
import (
"fmt"
"html/template"
"net/http"
)
func profileHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
// VULNERABLE: template.HTML bypasses escaping
htmlContent := template.HTML(fmt.Sprintf("<h1>Welcome %s!</h1>", username))
tmpl := `<html><body>{{.Content}}</body></html>`
t := template.Must(template.New("profile").Parse(tmpl))
data := struct{ Content template.HTML }{htmlContent}
t.Execute(w, data)
}
// Attack: username = "<script>alert('XSS')</script>"
// Result: <h1>Welcome <script>alert('XSS')</script>!</h1>
// This executes the attacker's scriptpackage main
import (
"html/template"
"net/http"
)
func profileHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
// SECURE: Let template handle escaping automatically
tmpl := `<html><body><h1>Welcome {{.Username}}!</h1></body></html>`
t := template.Must(template.New("profile").Parse(tmpl))
data := struct{ Username string }{username}
t.Execute(w, data)
}The vulnerable code uses template.HTML with fmt.Sprintf(), bypassing automatic HTML escaping and allowing script injection. The secure version passes the username string directly to the template, letting html/template automatically escape special characters.
Formatting strings with user input then passing to template.HTML.
Sourcery automatically identifies cross-site scripting via template.html in go and many other security issues in your codebase.