Xml External Entities in Gorilla Mux
How XML External Entities Manifests in Gorilla Mux Applications
XML External Entity (XXE) vulnerabilities arise when an XML parser processes external entity references within a document. In Gorilla Mux applications, the router itself is not vulnerable; instead, the risk lies in HTTP handlers that decode XML request bodies using Go's standard encoding/xml package without proper security controls.
Consider a common pattern where a Gorilla Mux route handles XML payloads:
r := mux.NewRouter()
r.HandleFunc("/api/xml", vulnerableXMLHandler).Methods("POST")
func vulnerableXMLHandler(w http.ResponseWriter, r *http.Request) {
var req MyRequest
decoder := xml.NewDecoder(r.Body)
if err := decoder.Decode(&req); err != nil {
http.Error(w, "Invalid XML", http.StatusBadRequest)
return
}
// Process request...
}
This handler uses xml.NewDecoder with default settings, which allows external entity expansion. An attacker can exploit this by submitting a malicious XML document:
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>
If the server processes this, the &xxe; entity expands to the contents of /etc/passwd, which may be included in the application's response or logged, leading to sensitive data disclosure. Similarly, SSRF can occur if the entity references an internal network resource like http://169.254.169.254/latest/meta-data/ (AWS metadata).
Gorilla Mux routes do not modify the request body, so the vulnerability is entirely within the handler's XML processing logic. Any endpoint that accepts XML and uses xml.Unmarshal or xml.NewDecoder without disabling entities is potentially exploitable. This is particularly risky for APIs that integrate with legacy systems or third-party services requiring XML, as the attack surface is any unauthenticated endpoint accepting XML content.
Detecting XXE Vulnerabilities in Gorilla Mux APIs
Detecting XXE vulnerabilities requires testing XML endpoints with payloads that trigger external entity expansion. Manual testing involves sending crafted XML requests and observing responses for file contents, error messages, or behavioral changes. For example, using curl:
curl -X POST http://api.example.com/api/xml \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><foo>&xxe;</foo>'
If the response contains root:x:0:0 (from /etc/passwd), the endpoint is vulnerable.
Automated scanning with middleBrick streamlines this process. When you submit a URL to middleBrick, it performs a black-box scan that includes XXE testing as part of its Input Validation check. middleBrick sends multiple XML payloads designed to:
- Trigger entity expansion and detect file content in responses
- Probe for SSRF via external network calls (e.g., to
http://127.0.0.1:22) - Identify error messages that leak file paths or system details
middleBrick analyzes responses for patterns indicating successful exploitation, such as common file signatures or internal IP addresses. The scan takes 5–15 seconds and produces a risk score (0–100, A–F) with per-category breakdowns. If XXE is found, it appears under Input Validation with severity (Critical/High/Medium/Low) and specific remediation guidance, like disabling entity expansions in the XML decoder.
Because middleBrick requires no credentials or configuration, you can quickly assess any Gorilla Mux API's exposure to XXE, even in staging or production environments. The CLI tool and GitHub Action enable integration into development workflows, ensuring XXE risks are caught early.
Securing Gorilla Mux Handlers Against XXE
Remediating XXE in Gorilla Mux handlers involves configuring Go's XML parser to disable external entity processing. The key is to use xml.NewDecoder and set DisallowEntityExpansions = true, which prevents any &entity; reference from being expanded. Optionally, enable Strict = true for additional constraints like requiring explicit closing tags.
Update vulnerable handlers as follows:
func secureXMLHandler(w http.ResponseWriter, r *http.Request) {
var req MyRequest
decoder := xml.NewDecoder(r.Body)
decoder.DisallowEntityExpansions = true // Critical: prevent XXE
decoder.Strict = true // Optional: reject invalid XML
if err := decoder.Decode(&req); err != nil {
http.Error(w, "Invalid XML", http.StatusBadRequest)
return
}
// Process request...
}
DisallowEntityExpansions = true ensures that any entity reference causes an error, neutralizing XXE attacks. This setting is available since Go 1.8 and should be considered a baseline requirement for any XML processing. Strict = true adds defense-in-depth by rejecting malformed XML, though it may break compatibility with some legacy clients.
If you use xml.Unmarshal directly, note that it does not expose the decoder's settings. Switch to xml.NewDecoder as shown, or wrap the request body with a custom io.Reader that limits entity expansion—though the decoder setting is simpler and recommended.
Where possible, replace XML with safer data formats like JSON, which does not support external entities. Gorilla Mux handles JSON natively via json.NewDecoder, eliminating XXE risk entirely. If XML is required (e.g., for SOAP integrations), combine the decoder settings with input validation against an XSD schema to ensure structural integrity.
Finally, conduct regular scans with middleBrick to verify that all XML endpoints remain secure, especially after code changes. The Web Dashboard tracks scores over time, while the GitHub Action can fail builds if XXE risks are introduced.