Server Side Template Injection in Gorilla Mux with Firestore
Server Side Template Injection in Gorilla Mux with Firestore — how this specific combination creates or exposes the vulnerability
Server Side Template Injection (SSTI) occurs when an attacker can control template input that is later rendered by a server-side templating engine. In a Go API using Gorilla Mux as the router and Firestore as the backend datastore, the risk arises when user-supplied data is passed into a response template without proper escaping or validation, and that template is processed by a server-side engine such as html/template or text/template.
Gorilla Mux does not render templates itself; it only matches routes and passes request context to handlers. If a handler extracts path or query parameters via mux.Vars(request) or request.URL.Query() and forwards them directly to a Firestore document field that is later injected into a template, an attacker can supply template syntax that executes during rendering. For example, a user profile stored in Firestore with a display name field could contain injected Go template actions, and if the handler uses {{ template "profile" . }} to render user data, those actions execute on the server.
Consider an endpoint /user/{username} where the handler fetches a document from a Firestore collection users and passes the document data to a template. If the Firestore document contains a field like bio: "{{ 3 | multiply }} </script>", and the handler uses the same template context for rendering, the server evaluates the Go template expression, potentially leading to code execution, information disclosure, or DOM-based side effects in the client.
The combination is dangerous because Firestore documents can store arbitrary user input, and Go’s html/template package, while auto-escaping by default, can be bypassed when using the . | safeHTML filter or when template actions are constructed dynamically. If a handler trusts Firestore data and reuses shared templates across users, a single malicious document can compromise all visitors who request that route. Attack patterns include credential theft via injected JavaScript, server-side request forgery to internal metadata endpoints, or probing internal services through SSRF facilitated by injected template HTTP calls.
Because middleBrick scans test the unauthenticated attack surface and include checks for SSRF and unsafe consumption, such a misconfiguration would be surfaced as a high-severity finding. Developers should treat all Firestore fields as untrusted and apply context-aware escaping at the point of template rendering, not at storage time.
Firestore-Specific Remediation in Gorilla Mux — concrete code fixes
Remediation centers on strict input validation, context-aware escaping, and avoiding the direct injection of Firestore document fields into executable template actions. The following patterns assume you use Go’s standard html/template package with Gorilla Mux.
1. Use context-aware escaping in templates
Always let html/template handle escaping. Do not use the triple-strip or safe filters on user data. Define your structs so that Firestore data is placed into fields that are escaped by default.
// Firestore document fields mapped to a Go struct
type UserProfile struct {
Username string
Bio string // treated as plain text, not template code
}
// Template using {{ .Bio }} ensures HTML escaping
const profileTmpl = `
<div>
<h2>{{ .Username }}</h2>
<p>Bio: {{ .Bio }}</p>
</div>
`
template, err := template.New("profile").Parse(profileTmpl)
if err != nil {
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
docSnap, err := client.Collection("users").Doc(username).Get(ctx)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
}
var profile UserProfile
if err := docSnap.DataTo(&profile); err != nil {
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
profile.Execute(w, profile)
2. Validate and sanitize Firestore string fields before use
For fields that must contain limited HTML (e.g., a rich text bio), use a sanitizer that understands HTML structure, and do not rely on the template engine alone. Avoid using template.JS or template.HTML unless you have a strict allow-list and understand the risks.
import "github.com/microcosm-cc/bluemonday"
var policy = bluemonday.UGCPolicy()
func getSanitizedBio(docMap map[string]interface{}) string {
if raw, ok := docMap["bio"].(string); ok {
return policy.Sanitize(raw)
}
return ""
}
3. Avoid dynamic template construction from Firestore data
Never parse or execute templates whose definitions come from Firestore. If you must store template-like snippets, treat them as data and render them through a restricted renderer or by generating plain text only.
// Anti-pattern to avoid:
// docData["template"] = "{{ .UserInput | customFunc }}"
// t := template.Must(template.New("dynamic").Parse(docData["template"].(string)))
// Safe alternative: store only data, not executable instructions.
4. Enforce strict schema validation on Firestore writes
Use Firestore validation rules or server-side checks to reject unexpected keys or malformed values that could later be used in template contexts.
// Example Firestore rule concept (not Go code):
// allow create: if request.resource.data.keys().hasAll(['username', 'bio'])
// && request.resource.data.bio is string
// && request.resource.data.bio.size() < 500;
By treating Firestore data as untrusted input, applying escaping at render time, and avoiding dynamic template parsing, you mitigate SSTI risks while still leveraging Firestore’s flexibility with Gorilla Mux handlers.
Frequently Asked Questions
Can Firestore document fields be safely used in Go templates if they are validated on write?
html/template defaults, because data can be modified after validation or accessed through other collections.