go.lang.security.audit.xss.no-printf-in-responsewriter.no-printf-in-responsewriter

Author
5,552
Download Count*
License
Detected 'printf' or similar in 'http.ResponseWriter.write()'. This bypasses HTML escaping that prevents cross-site scripting vulnerabilities. Instead, use the 'html/template' package to render data to users.
Run Locally
Run in CI
Defintion
rules:
- id: no-printf-in-responsewriter
message: Detected 'printf' or similar in 'http.ResponseWriter.write()'. This
bypasses HTML escaping that prevents cross-site scripting vulnerabilities.
Instead, use the 'html/template' package to render data to users.
metadata:
owasp:
- A07:2017 - Cross-Site Scripting (XSS)
- A03:2021 - Injection
cwe:
- "CWE-79: Improper Neutralization of Input During Web Page Generation
('Cross-site Scripting')"
references:
- https://blogtitle.github.io/robn-go-security-pearls-cross-site-scripting-xss/
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]
severity: WARNING
patterns:
- pattern-either:
- pattern-inside: |
func $HANDLER(..., $WRITER http.ResponseWriter, ...) {
...
}
- pattern-inside: |
func(..., $WRITER http.ResponseWriter, ...) {
...
}
- pattern: |
$WRITER.Write(<... fmt.$PRINTF(...) ...>, ...)
languages:
- go
Examples
no-printf-in-responsewriter.go
package main
import (
"fmt"
"log"
"net/http"
)
func getMovieQuote() map[string]string {
m := make(map[string]string)
m["quote"] = "I'll be back."
m["movie"] = "The Terminator"
m["year"] = "1984"
return m
}
func indexPage(w http.ResponseWriter, r *http.Request) {
const tme = `<html>`
const template = `
<html>
<body>
<h1>Random Movie Quotes</h1>
<h2>%s</h2>
<h4>~%s, %s</h4>
</body>
</html>`
quote := getMovieQuote()
quoteText := quote["quote"]
movie := quote["movie"]
year := quote["year"]
w.WriteHeader(http.StatusAccepted)
// ruleid: no-printf-in-responsewriter
w.Write([]byte(fmt.Sprintf(template, quoteText, movie, year)))
}
func errorPage(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
urls, ok := params["url"]
if !ok {
log.Println("Error")
return
}
url := urls[0]
const template = `
<html>
<body>
<h1>error; page not found. <a href="%s">go back</a></h1>
</body>
</html>`
w.WriteHeader(http.StatusAccepted)
// ruleid: no-printf-in-responsewriter
w.Write([]byte(fmt.Sprintf(template, url)))
}
func main() {
http.HandleFunc("/", indexPage)
http.HandleFunc("/error", errorPage)
http.ListenAndServe(":8080", nil)
}
Short Link: https://sg.run/Q5BP