go.lang.security.audit.xss.template-html-does-not-escape.unsafe-template-type
semgrep
Author
6,305
Download Count*
License
Semgrep could not determine that the argument to 'template.HTML()' is a constant. 'template.HTML()' and similar does not escape contents. Be absolutely sure there is no user-controlled data in this template. If user data can reach this template, you may have a XSS vulnerability. Instead, do not use this function and use 'template.Execute()'.
Run Locally
Run in CI
Defintion
rules:
- id: unsafe-template-type
message: Semgrep could not determine that the argument to 'template.HTML()' is a
constant. 'template.HTML()' and similar does not escape contents. Be
absolutely sure there is no user-controlled data in this template. If user
data can reach this template, you may have a XSS vulnerability. Instead,
do not use this function and use 'template.Execute()'.
metadata:
cwe:
- "CWE-79: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting')"
owasp:
- A07:2017 - Cross-Site Scripting (XSS)
- A03:2021 - Injection
references:
- https://golang.org/pkg/html/template/#HTML
- https://github.com/0c34/govwa/blob/139693e56406b5684d2a6ae22c0af90717e149b8/vulnerability/xss/xss.go#L33
category: security
technology:
- go
confidence: LOW
cwe2022-top25: true
cwe2021-top25: true
subcategory:
- audit
likelihood: LOW
impact: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
vulnerability_class:
- Cross-Site-Scripting (XSS)
languages:
- go
severity: WARNING
patterns:
- pattern-not: template.$ANY("..." + "...")
- pattern-not: template.$ANY("...")
- pattern-either:
- pattern: template.HTML(...)
- pattern: template.CSS(...)
- pattern: template.HTMLAttr(...)
- pattern: template.JS(...)
- pattern: template.JSStr(...)
- pattern: template.Srcset(...)
- pattern: template.URL(...)
Examples
template-html-does-not-escape.go
package main
import (
"fmt"
"html/template"
"net/http"
"strconv"
)
func Fine(r *http.Request) template.HTML {
// ok: unsafe-template-type
return template.HTML("<html><body><h1>Hello, world</h1></body></html>")
}
func AlsoFine(r *http.Request) template.HTML {
// ok: unsafe-template-type
return template.HTML("<html><body><h1>" + "Hello, world</h1></body></html>")
}
func OthersThatAreFine(r *http.Request) template.HTML {
// ok: unsafe-template-type
a := template.HTMLAttr("<html><body><h1>Hello, world</h1></body></html>")
// ok: unsafe-template-type
a := template.JS("<html><body><h1>Hello, world</h1></body></html>")
// ok: unsafe-template-type
a := template.URL("<html><body><h1>Hello, world</h1></body></html>")
// ok: unsafe-template-type
a := template.CSS("<html><body><h1>Hello, world</h1></body></html>")
// ok: unsafe-template-type
a := template.Srcset("<html><body><h1>Hello, world</h1></body></html>")
}
func OthersThatAreNOTFine(r *http.Request, data string) template.HTML {
// ruleid: unsafe-template-type
a := template.HTMLAttr(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", data))
// ruleid: unsafe-template-type
a := template.JS(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", data))
// ruleid: unsafe-template-type
a := template.URL(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", data))
// ruleid: unsafe-template-type
a := template.CSS(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", data))
// ruleid: unsafe-template-type
a := template.Srcset(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", data))
}
func Concat(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
tmpl := "<html><body><h1>" + customerId + "</h1></body></html>"
// ruleid: unsafe-template-type
return template.HTML(tmpl)
}
func ConcatBranch(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
doIt, err := strconv.ParseBool(r.URL.Query().Get("do"))
if err != nil {
return template.HTML("")
}
var tmpl string
if doIt {
tmpl = "<html><body><h1>" + customerId + "</h1></body></html>"
} else {
tmpl = ""
}
// ruleid: unsafe-template-type
return template.HTML(tmpl)
}
func ConcatInline(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: unsafe-template-type
return template.HTML("<html><body><h1>" + customerId + "</h1></body></html>")
}
func ConcatInlineOneside(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: unsafe-template-type
return template.HTML("<html><body><h1>" + customerId)
}
func Formatted(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
tmpl, err := fmt.Printf("<html><body><h1>%s</h1></body></html>", customerId)
if err != nil {
return template.HTML("")
}
// ruleid: unsafe-template-type
return template.HTML(tmpl)
}
func FormattedInline(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: unsafe-template-type
return template.HTML(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", customerId))
}
func main() {}
Short Link: https://sg.run/3xDb