XSS prevention for Go net/http
This is a cross-site scripting (XSS) prevention cheat sheet by Semgrep, Inc. It contains code patterns of potential XSS in an application. Instead of scrutinizing code for exploitable vulnerabilities, the recommendations in this cheat sheet pave a safe road for developers that mitigate the possibility of XSS in your code. By following these recommendations, you can be reasonably sure your code is free of XSS.
Mitigation summary
The Go template engine in html/template
does automatic and contextual autoescaping, which mitigates many common XSS mistakes. Some aspects of the engine are confusingly named; therefore, proper use of the library should be enforced using code scanners. You may also consider using a stricter alternative, such as safehtml
.
Check your project using Semgrep
The following command runs an optimized set of rules for your project:
semgrep --config p/default
1. Server code: Unescaped content
1.A. Using the text/template
package
text/template
does not perform any HTML escaping.
Example:
import "text/template"
References
Mitigation
Ban text/template
. Alternatively, use html/template
, or a stricter alternative such as safehtml
.
Semgrep rule
go.lang.security.audit.xss.import-text-template.import-text-template1.B. Escaped types: template.HTML
template.HTML
is a special type which instructs the template engine not to escape the content.
Example:
content := template.HTML("<div>" + user.name + "</div>")
References
Mitigation
Ban template.HTML
. Alternatively, if necessary, review each case carefully and exempt with # nosemgrep
.
Semgrep rule
go.lang.security.audit.xss.template-html-does-not-escape.unsafe-template-type1.C. Escaped types: template.HTMLAttr
template.HTMLAttr
is a special type which instructs the template engine not to escape the content.
Example:
content := template.HTMLAttr("class=" + user.role)
References
Mitigation
Ban template.HTMLAttr
. Alternatively, prefer template.HTML
, only if necessary.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates1.D. Escaped types: template.CSS
template.CSS
is a special type which instructs the template engine not to escape the content in CSS contexts.
Example:
content := template.CSS("body { color: black; }")
References
Mitigation
Ban template.CSS
. Alternatively, if necessary, review each case carefully and exempt with # nosemgrep
.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates1.E. Escaped types: template.JS
The template.JS
is a special type which instructs the template engine not to escape the content in JavaScript contexts, such as between script
tags.
Example:
content := template.JS("var name = " + user.name)
References
Mitigation
Ban template.JS
. Alternatively, place JavaScript code in files separate from HTML and serve them using the src
attribute.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates1.F. Escaped types: template.JSStr
The template.JSStr
is a special type which instructs the template engine not to escape the content when in JavaScript contexts and in a string.
Example:
content := template.JSStr("Error by: " + user.name)
References
Mitigation
Ban template.JSStr
. Alternatively, place JavaScript code in files separate from HTML and serve them using the src
attribute.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates1.G. Escaped types: template.Srcset
template.Srcset
is a special type which instructs the template engine not to escape the content.
Example:
content := template.Srcset("https://" + user.stylepageurl)
References
Mitigation
Ban template.Srcset
. Alternatively, prefer template.HTML
, only if necessary.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates1.H. Escaped types: template.URL
The template.URL
is a special type which instructs the template engine not to escape the content.
Example:
content := template.URL("https://" + user.stylepageurl)
References
Mitigation
Ban template.URL
. Alternatively, if necessary, review each case carefully and exempt with # nosem
.
Semgrep rule
go.template.security.insecure-types.go-insecure-templates2. Server code: Bypassing the template engine
2.A. Writing directly to the response object: fmt.Fprintf()
Writing directly to the response object bypasses the template engine which means content will not be autoescaped. This could introduce a XSS vulnerability.
Example:
fmt.Fprintf(w, "<div>" + user.name + "</div>")
References
Mitigation
Ban using fmt.Printf
with the HTTP response writer. Alternatively, use html/template
to render data to users.
Semgrep rule
go.lang.security.audit.xss.no-fprintf-to-responsewriter.no-fprintf-to-responsewriter2.C. Writing directly to the response object: io.WriteString()
Writing directly to the response object bypasses the template engine which means content will not be autoescaped. This could introduce a XSS vulnerability.
Example:
io.WriteString(w, "<div>" + user.name + "</div>")
References
Mitigation
Ban using io.WriteString
with the HTTP response writer. Alternatively, use html/template
to render data to users.
Semgrep rule
go.lang.security.audit.xss.no-io-writestring-to-responsewriter.no-io-writestring-to-responsewriter2.C. Writing directly to the response object: w.Write() method
Writing directly to the response object bypasses the template engine which means content will not be autoescaped. This could introduce a XSS vulnerability.
Example:
writer.Write([]byte("<div>" + user.name + "</div>"))
References
Mitigation
Ban using the Write
method of the HTTP response writer. Alternatively, use html/template
to render data to users.
Semgrep rule
go.lang.security.audit.xss.no-direct-write-to-responsewriter.no-direct-write-to-responsewriterNot finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.