RSTR-XSS-005 — Go HTTP response writes with request input

Summary

A Go HTTP handler writes request-derived data into the response with fmt.Fprintf, io.WriteString, or w.Write([]byte(...)) — no HTML escaping in between. The browser receives the attacker's input as part of an HTML page rendered in the application's origin.

Severity

High.

Languages

Go.

What rastray flags

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hi %s</h1>",
        r.URL.Query().Get("name"))                  // ← flagged
}
io.WriteString(w, "<p>"+r.FormValue("msg")+"</p>") // ← flagged

What rastray deliberately does not flag

  • Writes that go through html/template (auto-escaping).
  • json.NewEncoder(w).Encode(...) — JSON, not HTML.
  • Writes of literal strings.

How to fix it

Use html/template — Go's stdlib renderer is context-aware and escapes correctly per HTML/JS/URL context:

import "html/template"

var helloTmpl = template.Must(template.New("hi").Parse(
    `<h1>Hi {{ .Name }}</h1>`))

func hello(w http.ResponseWriter, r *http.Request) {
    helloTmpl.Execute(w, struct{ Name string }{r.URL.Query().Get("name")})
}

For one-off writes, escape explicitly:

import "html"

fmt.Fprintf(w, "<p>%s</p>", html.EscapeString(r.FormValue("msg")))

text/template does not escape — use it only for non-HTML output.

References