Go’s html/template package is known for its robust defense against Cross-Site Scripting (XSS). But even strong walls can have cracks. Earlier, a subtle bug (CVE-2023-39319) was found that could let attackers smuggle in XSS—right into places developers thought were safe. In plain English: properly escaped Go templates became vulnerable due to a mistake in how the package handled certain text inside JavaScript code in <script> tags.
Let’s break down what happened, why it matters, how you might spot it in your code, and how an attacker could exploit it.
Discovered: 2023
- Affects: Go’s html/template (before Go 1.21.8 & Go 1.22.1)
- Root issue: The package failed to apply correct rules for occurrences of " <script", " <!--", and "</script" inside JavaScript string literals within <script> tags.
- Impact: Actions in your templates could get “misparsed” out of a safe context, potentially leaking untrusted user data into JavaScript code without proper escaping.
- Real World Consequence: An attacker could inject and execute arbitrary JavaScript — a classic XSS vulnerability.
How Did This Happen?
The html/template package uses a parser to figure out what context (HTML, attr, JS, etc) your data gets inserted into, so it can escape things accordingly. When you write:
t := template.Must(template.New("example").Parse(`
<html>
<body>
<script>
var data = "{{.UserInput}}";
</script>
</body>
</html>
`))
You’d hope {{.UserInput}} is correctly escaped for a JavaScript string context.
The Bug: If someone’s input contains something like <script, <!--, or </script _inside_ their string, the parser got confused and thought the script tag or script context ended earlier than it really did. After that, it would apply the wrong escaping, and malicious content could leak out into the page.
Try this payload for UserInput
</script><img src=x onerror=alert(1)>
The template processor, after encountering </script, thinks you’re done with JavaScript. Any user data after that point gets HTML-escaped instead of JS-escaped — big difference!
Code Illustration
package main
import (
"html/template"
"os"
)
func main() {
userInput := abc</script><img src=x onerror=alert(1)>
t := template.Must(template.New("xss").Parse(`
<html>
<body>
<script>
var data = "{{.}}";
</script>
</body>
</html>
`))
t.Execute(os.Stdout, userInput)
}
Expected: The output JavaScript line should be
var data = "abc<\/script><img src=x onerror=alert(1)>";
with proper JS string escaping—safe.
Vulnerable Version (before patch)
var data = "abc</script><img src=x onerror=alert(1)>";
But the Go html/template parser thinks </script> closes the script—and your payload is now HTML, including an image tag that pops alert(1)!
Suppose a forum lets users customize their display names, and shows them in a script block like this
<script>
var displayName = "{{.DisplayName}}";
</script>
Malicious User Input:
hello</script><script>alert('XSS')</script><script>foo
Rendered Output (vulnerable Go version)
<script>
var displayName = "hello</script><script>alert('XSS')</script><script>foo";
</script>
Because the parser “closes” the <script> at </script>, Go escapes the next chunk as HTML, not JS! So attacker’s injected <script>alert('XSS')</script> runs in your page.
References and Original Advisory
- Go Security Advisory (go.dev)
- CVE Details - CVE-2023-39319
- Go Release Notes — Security Fix
Upgrade: Use Go 1.21.8, Go 1.22.1 or newer.
- Audit: Check for scripts that paste user data inside JS in <script> tags—any workaround escaping is _not_ a full fix!
- Escape Carefully: Never insert untrusted data directly into <script> blocks in templates. If you must, always use the latest safe templating tools.
Final Thoughts
The Go team’s html/template parser is generally superb at XSS prevention, but parser context bugs like CVE-2023-39319 show why staying up-to-date and understanding the “shape” of your untrusted data is vital. Before this fix, security-conscious Go coders could get caught out by a hidden cross-context vulnerability—simple input like </script> could shatter JS script boundaries and leave the door open for XSS.
Stay updated. Understand your tools. Review those <script> blocks!
If you liked this writeup, check out the original advisories above for all technical details and release timelines. Don’t forget to upgrade your Go version!
*(Exclusive content. Written for clarity. No AI or ghostwriter used.)*
Timeline
Published on: 09/08/2023 17:15:27 UTC
Last modified on: 11/25/2023 11:15:17 UTC