HIGH server side template injectionginbasic auth

Server Side Template Injection in Gin with Basic Auth

Server Side Template Injection in Gin with Basic Auth — how this specific combination creates or exposes the vulnerability

Server Side Template Injection (SSTI) in the Gin web framework occurs when user-controlled data is passed into a template and executed as code. Gin uses the html/template package (or third-party engines like gin-contrib/html) which provide automatic escaping for HTML contexts by default. However, if a developer uses the .SafeHTML method, disables escaping, or calls functions like template.HTML on attacker-influenced input, the template engine can evaluate malicious content. When Basic Auth is used without additional authorization checks, unauthenticated or low-privilege users can still reach the vulnerable endpoint, which broadens the attack surface.

In a typical Gin route, a developer might pass query parameters or JSON fields into a template rendering function. For example, a debug or status endpoint that includes a user-supplied name parameter in the template can become exploitable:

// Vulnerable example: user input is directly injected into the template
type PageData struct {
    Name string
}

g.GET("/profile", func(c *gin.Context) {
    name := c.Query("name")
    c.HTML(http.StatusOK, "profile", gin.H{
        "Name": name,
    })
})

If the template profile.tmpl uses {{ .Name | safe }} or {{ .Name | printf "

%s
" | safeHTML }}, an attacker can inject template directives. In combination with Basic Auth, where credentials are only checked at the handler level and do not restrict template rendering, an authenticated session can be abused to execute arbitrary template logic. This may lead to reading local files via {{ (index . "$nil").Files "/" }} or invoking functions mapped into the template’s function map, enabling further exploitation. The risk is elevated when Basic Auth is used for coarse-grained access control while template-level controls are missing.

Gin does not automatically protect against SSTI simply because Basic Auth validates credentials. Attack patterns like CVE-2021-26121 (Atlassian Confluence SSTI) illustrate how template injection can lead to remote code execution or sensitive data exposure. middleBrick checks for these issues by correlating OpenAPI/Swagger spec definitions with runtime behavior, identifying unsafe template usage and overly permissive auth configurations.

Basic Auth-Specific Remediation in Gin — concrete code fixes

Remediation focuses on preventing untrusted data from reaching the template layer and tightening access controls. Avoid marking user input as safe, and use context-aware escaping. Prefer structured data output (e.g., JSON) for APIs, or ensure templates escape by default.

1. Use strict escaping and avoid SafeHTML

Never apply template.HTML or custom safe functions to user input. Instead, let the template engine handle escaping:

// Safe approach: rely on default escaping
g.GET("/profile-safe", func(c *gin.Context) {
    name := c.Query("name")
    c.HTML(http.StatusOK, "profile", gin.H{
        "Name": name, // auto-escaped in html/template
    })
})

2. Validate and sanitize input before use

Allowlist acceptable values and reject unexpected patterns. If you must include input in templates, sanitize it to a safe subset:

import "regexp"

var safeName = regexp.MustCompile(`^[a-zA-Z0-9_\-\s]+$`)

g.GET("/profile-validated", func(c *gin.Context) {
    name := c.Query("name")
    if !safeName.MatchString(name) {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid name"})
        return
    }
    c.HTML(http.StatusOK, "profile", gin.H{
        "Name": name,
    })
})

3. Combine Basic Auth with role-based authorization at the route or handler level

Basic Auth provides authentication but not fine-grained authorization. Use middleware to enforce scopes or roles before rendering sensitive templates:

func BasicAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        user, pass, ok := c.Request.BasicAuth()
        if !ok || !checkCredentials(user, pass) {
            c.Header("WWW-Authenticate", `Basic realm="restricted"`)
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "auth required"})
            return
        }
        // Attach user identity for downstream handlers
        c.Set("user", user)
        c.Next()
    }
}

func RequireRole(role string) gin.HandlerFunc {
    return func(c *gin.Context) {
        user, _ := c.Get("user")
        if !hasRole(user.(string), role) {
            c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
            return
        }
        c.Next()
    }
}

// Usage
 g.GET("/admin", BasicAuth(), RequireRole("admin"), func(c *gin.Context) {
    // Only authenticated users with role "admin" reach here
    c.JSON(http.StatusOK, gin.H{"status": "admin area"})
})

4. Use JSON APIs instead of server-side templates for public endpoints

For endpoints consumed by web or mobile clients, prefer JSON responses. This removes template injection risk entirely and aligns with modern API practices:

g.GET("/api/status", BasicAuth(), func(c *gin.Context) {
    name := c.Query("name")
    // Validate input as needed
    c.JSON(http.StatusOK, gin.H{
        "message": "Hello, " + name,
    })
})

By default, encoding/json escapes HTML characters, preventing injection into downstream consumers. Combine this with middleware that enforces Basic Auth and scope checks to maintain a secure, minimal attack surface.

Frequently Asked Questions

Does Basic Auth alone prevent Server Side Template Injection in Gin?
No. Basic Auth handles credential verification but does not protect against untrusted data being interpreted as template code. SSTI requires input validation, strict escaping, and template hygiene regardless of authentication.
Can middleBrick detect SSTI in Gin endpoints protected by Basic Auth?
Yes. middleBrick tests the unauthenticated attack surface and can identify unsafe template usage. It correlates findings with auth configurations to highlight exposures where authenticated access does not mitigate template injection risks.