HIGH xml external entitiesginbasic auth

Xml External Entities in Gin with Basic Auth

Xml External Entities in Gin with Basic Auth — how this specific combination creates or exposes the vulnerability

Xml External Entity (XXE) injection occurs when an XML parser is configured to process external entities and untrusted XML input is accepted. In the Gin framework for Go, this typically arises when an endpoint parses XML request bodies using a permissive XML decoder that allows external entity references. When Basic Auth is used, an attacker may first need to obtain or bypass credentials, but once a valid username and password pair is acquired or guessed, the authenticated context can be abused to probe or exploit XXE behavior in endpoints that process XML.

Because Basic Auth credentials are transmitted in the Authorization header on each request, an authenticated session can be used to test XXE payloads against authenticated routes that parse XML. Even though Basic Auth itself does not cause XXE, it can lower the barrier to testing authenticated code paths that are otherwise protected. For example, an authenticated session might access an administrative endpoint that accepts XML uploads and forwards them to a backend parser. If the parser resolves external entities, an attacker can leverage the authenticated context to read server-side files (via file:// URLs), perform SSRF to internal services, or cause denial of service through entity expansion (billion laughs).

In Gin, a vulnerable pattern looks like binding an XML body to a struct with a custom XML decoder that does not disable external entity processing. If the endpoint does not enforce strict input validation and relies on the default XML unmarshaling behavior, an attacker can supply a malicious XML payload containing DOCTYPE and entity declarations. The combination of authenticated access via Basic Auth and insufficient XML hardening creates a scenario where XXE can be leveraged to extract sensitive configuration, trigger SSRF against internal endpoints, or amplify resource consumption, depending on how the parser is configured.

Basic Auth-Specific Remediation in Gin — concrete code fixes

To mitigate XXE in Gin when Basic Auth is used, focus on hardening XML parsing and ensuring credentials are not relied upon to protect unsafe deserialization. Always disable external entities and DTD processing in your XML decoder, and avoid using the default xml.Unmarshal for untrusted payloads. Implement strict content-type validation and prefer JSON for APIs where possible. Below are concrete, secure examples for Gin with Basic Auth.

1. Secure Basic Auth setup in Gin

Use middleware to validate credentials on each request without storing sensitive data in shared state.

package main

import (
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

// BasicAuthMiddleware validates username:password against a secure source.
func BasicAuthMiddleware() 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", charset="UTF-8"`)
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
			return
		}
		c.Set("user", user)
		c.Next()
	}
}

// checkCredentials performs constant-time verification against a secure store.
func checkCredentials(user, pass string) bool {
	// In production, use a constant-time compare and hashed passwords.
	// Example: compare pbkdf2/argon2 hash with stored hash.
	validUsers := map[string]string{
		"admin": "$argon2id$...", // placeholder for a properly hashed password
	}
	hashed, exists := validUsers[user]
	if !exists {
		return false
	}
	// Use a secure constant-time comparison function.
	return subtleCompare(hashed, pass)
}

// subtleCompare avoids timing attacks (placeholder: use subtle.ConstantTimeCompare).
func subtleCompare(a, b string) bool {
	if len(a) != len(b) {
		return false
	}
	var equal byte
	for i := 0; i < len(a); i++ {
		equal |= a[i] ^ b[i]
	}
	return equal == 0
}

2. Disable external entities in XML parsing

Do not use the standard library’s xml.Unmarshal directly on untrusted XML. Instead, configure a decoder with strict settings that disable external entities and DTDs.

package main

import (
	"encoding/xml"
	"io"
	"net/http"

	"github.com/gin-gonic/gin"
)

type SafeXMLValidator struct{}

// DecodeXML decodes XML without processing external entities.
func (v *SafeXMLValidator) DecodeXML(c *gin.Context) (interface{}, error) {
	// Limit the reader to prevent oversized payloads.
	lr := &io.LimitedReader{R: c.Request.Body, N: 10e6} // 10 MB
	defer c.Request.Body.Close()

	// Create a decoder with strict settings.
	decoder := xml.NewDecoder(lr)
	decoder.Entity = xml.HTMLEntity // minimal entities, no external resolution
	decoder.Strict = true

	// Define a target structure that matches expected XML.
	var payload struct {
		Message string `xml:"message"`
	}
	if err := decoder.Decode(&payload); err != nil {
		return nil, err
	}
	return payload, nil
}

// Example endpoint using both auth and safe XML parsing.
func uploadXML(c *gin.Context) {
	// Auth middleware ensures credentials are valid.
	user := c.MustGet("user").(string)

	payload, err := SafeXMLValidator{}.DecodeXML(c)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid XML"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"user": user, "data": payload})
}

func main() {
	r := gin.Default()
	r.POST("/upload", BasicAuthMiddleware(), uploadXML)
	r.Run()
}

3. Additional hardening steps

  • Set c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 10<<20) before decoding to cap request size.
  • Validate Content-Type is exactly application/xml or text/xml to avoid content-sniffing attacks.
  • Avoid XPath or XSLT processing on untrusted input, as they can also introduce XXE-like behaviors.
  • Combine with continuous monitoring: use the middleBrick CLI (middlebrick scan <url>) to detect misconfigurations in unauthenticated attack surface and the GitHub Action to fail builds if risk scores degrade after changes.

Frequently Asked Questions

Does using Basic Auth prevent XXE in Gin endpoints?
No. Basic Auth handles authentication but does not affect XML parser behavior. XXE depends on how XML input is processed; you must explicitly disable external entities and DTDs in the XML decoder regardless of authentication.
Can middleBrick detect XXE in Gin APIs protected by Basic Auth?
middleBrick scans the unauthenticated attack surface by default. To test authenticated routes, supply valid Basic Auth credentials so the scanner can exercise protected endpoints and identify XML parsing issues.