Using fmt.Sprintf() for HTML
Building HTML strings with fmt.Sprintf() containing user input.
XSS vulnerabilities occur when Go applications manually construct HTML using fmt.Sprintf() or string concatenation with user input, bypassing html/template's automatic escaping. This allows attackers to inject malicious scripts that execute in users' browsers, steal sessions, manipulate page content, or perform unauthorized actions.
package main
import (
"fmt"
"net/http"
)
func welcomeHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
// VULNERABLE: fmt.Sprintf with user input in HTML
htmlResponse := fmt.Sprintf(`<html><body>
<h1>Welcome %s!</h1>
</body></html>`, username)
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(htmlResponse))
}
func commentHandler(w http.ResponseWriter, r *http.Request) {
comment := r.FormValue("comment")
// VULNERABLE: String concatenation in HTML
html := "<div class='comment'>" + comment + "</div>"
fmt.Fprintf(w, "<html><body>%s</body></html>", html)
}
// Attack: username = "<script>alert('XSS')</script>"package main
import (
"html/template"
"net/http"
)
func welcomeHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
// SECURE: Use html/template for automatic escaping
tmpl := `<html><body>
<h1>Welcome {{.Username}}!</h1>
</body></html>`
t := template.Must(template.New("welcome").Parse(tmpl))
data := struct{ Username string }{username}
w.Header().Set("Content-Type", "text/html")
t.Execute(w, data)
}
func commentHandler(w http.ResponseWriter, r *http.Request) {
comment := r.FormValue("comment")
// SECURE: Template handles escaping
tmpl := `<html><body>
<div class="comment">{{.Comment}}</div>
</body></html>`
t := template.Must(template.New("comment").Parse(tmpl))
t.Execute(w, struct{ Comment string }{comment})
}The vulnerable code uses fmt.Sprintf() and string concatenation to build HTML with user input, bypassing escaping and allowing script injection. The secure version uses html/template which automatically escapes user input, preventing XSS attacks.
Building HTML strings with fmt.Sprintf() containing user input.
Sourcery automatically identifies cross-site scripting via manual html construction in go and many other security issues in your codebase.