Server Side Template Injection in Fiber with Hmac Signatures
Server Side Template Injection in Fiber with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Server Side Template Injection (SSTI) in the Fiber web framework becomes particularly concerning when Hmac Signatures are used to guard route handling but are implemented inconsistently. SSTI occurs when an attacker can control a template expression that is evaluated on the server, leading to arbitrary code execution or information disclosure. In Fiber, routes often render HTML templates using third-party engines such as html/template or embedded templates, and if user-supplied data is injected into template actions or filters without proper escaping, injection is possible.
When Hmac Signatures are used to validate the integrity of requests (e.g., to confirm a webhook or a token originated from a trusted source), a common mistake is to include user-controlled values inside the signed payload and then later use those values in template rendering. If the signature verification passes but the downstream template execution does not enforce output escaping, an attacker who can influence the signed data might be able to inject template expressions. For example, if a route builds a signed payload that includes a user-controlled display name and then passes that name into a template that evaluates actions (such as with custom delimiters or functions), malicious input like {{ (index . "0").Execute }} could be stored, signed, and later rendered as executable template code.
The risk is exacerbated when developers assume Hmac Signatures alone prevent tampering. A valid Hmac confirms the payload has not been altered after signing, but it does not neutralize malicious content within the payload. If the application trusts the signature and directly interpolates signed data into templates without sanitization or contextual escaping, the attack surface mirrors classic SSTI vectors described in the OWASP API Top 10. Real-world patterns seen with other systems, such as CVE-2020-28472 in related Go template engines, illustrate how injection can bypass integrity checks when escaping is applied too late or inconsistently.
In Fiber, this typically manifests in handlers that parse form values or JSON bodies, compute an Hmac over selected fields, and then forward those fields to template rendering. If the template engine supports functions or method calls, an attacker-supplied key in the signed data could map to a function that executes arbitrary logic. Because the scan checks include Input Validation and Unsafe Consumption, middleBrick flags scenarios where untrusted data reaches templates even when protected by Hmac Signatures, emphasizing that signature verification is not a substitute for output encoding and strict allowlists.
Hmac Signatures-Specific Remediation in Fiber — concrete code fixes
To remediate SSTI risks when using Hmac Signatures in Fiber, ensure that data covered by the signature is treated as untrusted for rendering purposes and that templates enforce strict contextual escaping. Do not rely on the signature to sanitize content; instead, validate, encode, and restrict what is passed to the template engine.
Below are concrete, working examples for Fiber that demonstrate secure handling of Hmac Signatures alongside template rendering. The examples use Go’s standard library crypto/hmac and html/template to ensure output is properly escaped.
Example 1: Verifying Hmac and rendering with escaped HTML
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"strings"
"github.com/gofiber/fiber/v2"
"html/template"
)
func verifyAndRender(c *fiber.Ctx) error {
// Expected signature from a trusted source, e.g., header or query param
expectedSig := c.Get("X-Signature")
// Secret known only to server
secret := []byte("super-secret-key")
// Build the signed payload from non-sensitive, canonical data
payload := "v1:data"
mac := hmac.New(sha256.New, secret)
mac.Write([]byte(payload))
computedSig := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(computedSig), []byte(expectedSig)) {
return c.Status(fiber.StatusUnauthorized).SendString("invalid signature")
}
// Safe: use only verified, canonical data for template; treat user input separately
tmpl, err := template.New("page").Parse(`<h1>Welcome</h1><p>{{.Message}}</p>`)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString("template error")
}
data := struct {
Message template.HTML
}{
Message: template.HTML("Hello, authenticated user"), // explicitly trusted HTML
}
return c.Render(fiber.StatusOK, template.H{"page": tmpl}, data)
}
Example 2: Rejecting user input in signed payloads before template use
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/valyala/fasthttp"
)
func handleWebhook(c *fiber.Ctx) error {
body := c.Body()
expectedSig := c.Get("X-Hub-Signature-256")
secret := []byte("webhook-secret")
mac := hmac.New(sha256.New, secret)
mac.Write(body)
computedSig := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(computedSig), []byte(expectedSig)) {
return c.Status(fiber.StatusBadRequest).SendString("invalid signature")
}
// Parse only after signature verification
var payload map[string]interface{}
if err := json.Unmarshal(body, &payload); err != nil {
return c.Status(fiber.StatusBadRequest).SendString("invalid json")
}
// Do NOT inject payload fields directly into templates
// Instead, extract only safe, validated fields
safeTitle, ok := payload["title"].(string)
if !ok {
return c.Status(fiber.StatusBadRequest).SendString("missing title")
}
// Use a strict allowlist and escape user data
tmpl, _ := template.New("notify").Parse(`<div>{{.Title}}</div>`)
tmpl.Execute(c.Context().Response.BodyWriter(), struct{ Title template.HTMLEscapedString }{
Title: template.HTMLEscapedString(safeTitle),
})
return nil
}
Key remediation practices
- Verify Hmac signatures before using any data from the payload.
- Never pass raw user-controlled values into templates; use allowlists and type assertions.
- Use framework-aware escaping types (e.g.,
template.HTML,template.HTMLEscapedString) when you must render trusted HTML. - Keep template logic minimal and avoid custom functions or actions that can execute code.
- Treat signature integrity as authenticity, not sanitization; apply output encoding per context (HTML, JS, CSS, URL).