Using template.URL with User Input
Passing user-controlled data to template.URL which bypasses escaping.
XSS vulnerabilities occur when untrusted data is passed to template.URL, which bypasses URL escaping. Attackers can inject malicious URL schemes like javascript: or data: that execute scripts when users click links or when URLs are loaded in iframes, leading to session theft, phishing, and data exfiltration.
package main
import (
"html/template"
"net/http"
)
func linkHandler(w http.ResponseWriter, r *http.Request) {
redirectURL := r.URL.Query().Get("url")
// VULNERABLE: template.URL bypasses escaping
safeURL := template.URL(redirectURL)
tmpl := `<html><body>
<a href="{{.URL}}">Click here</a>
</body></html>`
t := template.Must(template.New("link").Parse(tmpl))
t.Execute(w, struct{ URL template.URL }{safeURL})
}
// Attack: url=javascript:alert('XSS')
// Result: <a href="javascript:alert('XSS')">Click here</a>
// This executes JavaScript when clickedpackage main
import (
"html/template"
"net/http"
"net/url"
)
var allowedSchemes = map[string]bool{
"http": true,
"https": true,
"mailto": true,
}
func linkHandler(w http.ResponseWriter, r *http.Request) {
redirectURL := r.URL.Query().Get("url")
// SECURE: Validate URL scheme
if !isValidURL(redirectURL) {
http.Error(w, "Invalid URL", http.StatusBadRequest)
return
}
tmpl := `<html><body>
<a href="{{.URL}}">Click here</a>
</body></html>`
t := template.Must(template.New("link").Parse(tmpl))
// SAFE: Pass as string, template will escape
t.Execute(w, struct{ URL string }{redirectURL})
}
func isValidURL(urlStr string) bool {
parsedURL, err := url.Parse(urlStr)
if err != nil {
return false
}
// Check against scheme allowlist
return allowedSchemes[parsedURL.Scheme]
}The vulnerable code uses template.URL with user input, bypassing escaping and allowing javascript: or data: URL schemes that execute code. The secure version validates the URL scheme against an allowlist and passes the URL as a string for automatic escaping.
Passing user-controlled data to template.URL which bypasses escaping.
Sourcery automatically identifies cross-site scripting via template.url in go and many other security issues in your codebase.