go.lang.security.audit.net.formatted-template-string.formatted-template-string
Community Favorite

Author
74,617
Download Count*
License
Found a formatted template string passed to 'template.HTML()'. 'template.HTML()' 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.
Run Locally
Run in CI
Defintion
rules:
- id: formatted-template-string
message: Found a formatted template string passed to 'template.HTML()'.
'template.HTML()' 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.
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
category: security
technology:
- go
confidence: MEDIUM
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.HTML("..." + "...")
- pattern-either:
- pattern: template.HTML($T + $X, ...)
- pattern: template.HTML(fmt.$P("...", ...), ...)
- pattern: |
$T = "..."
...
$T = $FXN(..., $T, ...)
...
template.HTML($T, ...)
- pattern: |
$T = fmt.$P("...", ...)
...
template.HTML($T, ...)
- pattern: |
$T, $ERR = fmt.$P("...", ...)
...
template.HTML($T, ...)
- pattern: |
$T = $X + $Y
...
template.HTML($T, ...)
- pattern: |-
$T = "..."
...
$OTHER, $ERR = fmt.$P(..., $T, ...)
...
template.HTML($OTHER, ...)
Examples
formatted-template-string.go
package main
import (
"fmt"
"html/template"
"net/http"
"strconv"
)
func Fine(r *http.Request) template.HTML {
// ok: formatted-template-string
return template.HTML("<html><body><h1>Hello, world</h1></body></html>")
}
func AlsoFine(r *http.Request) template.HTML {
// ok: formatted-template-string
return template.HTML("<html><body><h1>" + "Hello, world</h1></body></html>")
}
func Concat(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: formatted-template-string
tmpl := "<html><body><h1>" + customerId + "</h1></body></html>"
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 {
// todo: formatted-template-string
tmpl = "<html><body><h1>" + customerId + "</h1></body></html>"
} else {
tmpl = ""
}
return template.HTML(tmpl)
}
func ConcatInline(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: formatted-template-string
return template.HTML("<html><body><h1>" + customerId + "</h1></body></html>")
}
func ConcatInlineOneside(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: formatted-template-string
return template.HTML("<html><body><h1>" + customerId)
}
func Formatted(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: formatted-template-string
tmpl, err := fmt.Printf("<html><body><h1>%s</h1></body></html>", customerId)
if err != nil {
return template.HTML("")
}
return template.HTML(tmpl)
}
func FormattedInline(r *http.Request) template.HTML {
customerId := r.URL.Query().Get("id")
// ruleid: formatted-template-string
return template.HTML(fmt.Sprintf("<html><body><h1>%s</h1></body></html>", customerId))
}
func main() {}
Short Link: https://sg.run/weE0