Skip to main content

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-template

1.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-type

1.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-templates

1.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-templates

1.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-templates

1.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-templates

1.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-templates

1.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-templates

2. 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-responsewriter

2.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-responsewriter

2.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-responsewriter