Xml External Entities with Mutual Tls
How Xml External Entities Manifests in Mutual Tls
XML External Entity (XXE) vulnerabilities in Mutual TLS (mTLS) environments exploit the trust relationship established between client and server certificates. When an API endpoint secured with mTLS processes XML input, the mutual authentication layer doesn't prevent XML parsers from resolving external entities, creating a dangerous attack surface.
In mTLS-secured APIs, attackers can leverage XXE through several attack vectors:
- Internal network reconnaissance: An XXE payload can cause the server to resolve internal hostnames and IP addresses, mapping the internal network topology behind the mTLS gateway.
- Service account credential exposure: If the mTLS client certificate has elevated privileges, XXE can trigger requests to internal services that expose credentials or configuration files.
- Internal port scanning: XML parsers resolving external entities can perform blind port scanning of internal services accessible from the mTLS server.
Consider this vulnerable mTLS API endpoint in Go:
package main
import (
"crypto/tls"
"encoding/xml"
"net/http"
)
func main() {
// Mutual TLS configuration
tlsConfig := &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: loadClientCAs(),
}
// Vulnerable XML processing
http.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil || r.TLS.VerifiedChains == nil {
http.Error(w, "mTLS required", http.StatusUnauthorized)
return
}
var data Payload
xml.NewDecoder(r.Body).Decode(&data) // No entity expansion disabled
// Process data...
})
server := &http.Server{
Addr: ":443",
TLSConfig: tlsConfig,
}
http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
}
type Payload struct {
Data string `xml:"data"`
}The vulnerability exists because the XML decoder processes external entities by default, even though the connection is secured with mTLS. An attacker with a valid client certificate can send:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/" >
]>
<data>&xxe;</data>This payload would cause the server to make an HTTP request to the internal metadata service, potentially exposing cloud instance metadata. The mTLS layer only verifies the client certificate—it doesn't inspect XML content for malicious entities.
Mutual Tls-Specific Detection
Detecting XXE vulnerabilities in mTLS environments requires specialized scanning that can establish the mutual trust relationship while testing XML processing. Traditional scanners that don't support client certificates cannot reach these endpoints.
middleBrick's mTLS detection capabilities include:
- Client certificate authentication: The scanner presents valid client certificates to establish mTLS connections before testing XML endpoints.
- XML entity expansion testing: Active probing sends XXE payloads to detect whether external entities are processed.
- Network boundary testing: The scanner attempts to resolve internal resources to identify internal network exposure.
Using middleBrick's CLI for mTLS XXE scanning:
npx middlebrick scan \
--url https://api.example.com/v1/endpoint \
--client-cert client.crt \
--client-key client.key \
--ca-cert ca.crt \
--test xml-external-entitiesThe scanner automatically tests for XXE vulnerabilities by:
- Establishing an mTLS connection using the provided certificates
- Sending XML payloads with various entity definitions
- Monitoring for error responses, timeouts, or unexpected network requests
- Checking for SSRF indicators in the response
middleBrick's findings report includes severity ratings based on the potential impact:
| Severity | Risk Level | Typical Impact |
|---|---|---|
| Critical | 90-100 | Remote code execution, internal network compromise |
| High | 70-89 | Internal network reconnaissance, credential exposure |
| Medium | 40-69 | Limited information disclosure |
| Low | 0-39 | No XXE vulnerability detected |
The scanner also provides remediation guidance specific to mTLS environments, including secure XML parser configuration and network segmentation recommendations.
Mutual Tls-Specific Remediation
Securing XML processing in mTLS environments requires both XML parser hardening and network-level controls. The most effective approach combines secure XML parsing with mTLS-specific network restrictions.
Secure XML Parser Configuration
In Go, disable external entity processing:
package main
import (
"crypto/tls"
"encoding/xml"
"io"
"net/http"
"golang.org/x/net/html/charset"
)
func secureXMLHandler(w http.ResponseWriter, r *http.Request) {
if r.TLS == nil || r.TLS.VerifiedChains == nil {
http.Error(w, "mTLS required", http.StatusUnauthorized)
return
}
// Read body first
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
// Create decoder with entity expansion disabled
decoder := xml.NewDecoder(body)
decoder.Entity = xml.HTMLEntity
decoder.Strict = true
// Prevent external entity resolution
decoder.AutoClose = xml.HTMLAutoClose
decoder.CharsetReader = charset.NewReaderLabel
var data Payload
err = decoder.Decode(&data)
if err != nil {
http.Error(w, "XML parsing error", http.StatusBadRequest)
return
}
// Process data...
}
type Payload struct {
Data string `xml:"data"`
}Network-Level Controls
Implement network segmentation to limit the impact of potential XXE exploits:
// Network restrictions in mTLS configuration
tlsConfig := &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: loadClientCAs(),
// Additional security
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
PreferServerCipherSuites: true,
}
// Create a restricted network client for any internal requests
server := &http.Server{
Addr: ":443",
TLSConfig: tlsConfig,
// Custom transport with restrictions
Handler: &restrictedHandler{
next: http.DefaultServeMux,
// Block outbound requests from XML processing
blockedHosts: map[string]bool{
"169.254.169.254": true, // AWS metadata
"metadata.google.internal": true, // GCP metadata
"169.254.0.0/16": true, // Azure metadata range
},
},
}
// Custom handler that inspects requests
type restrictedHandler struct {
next http.Handler
blockedHosts map[string]bool
}
func (h *restrictedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Check if request is attempting to access blocked resources
if h.isBlockedRequest(r) {
http.Error(w, "Blocked", http.StatusForbidden)
return
}
h.next.ServeHTTP(w, r)
}
func (h *restrictedHandler) isBlockedRequest(r *http.Request) bool {
// Check host against blocked list
if h.blockedHosts[r.Host] {
return true
}
// Check for suspicious paths
if r.URL.Path == "/latest/meta-data/" {
return true
}
return false
}Java Spring Boot Implementation
For Java applications using Spring Boot with mTLS:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public X509AuthenticationFilter x509AuthenticationFilter() {
return new X509AuthenticationFilter();
}
@Bean
public X509AuthenticationProvider x509AuthenticationProvider() {
return new X509AuthenticationProvider();
}
@Bean
public X509AuthenticationEntryPoint x509AuthenticationEntryPoint() {
return new X509AuthenticationEntryPoint();
}
@Bean
public XMLReader xmlReader() throws SAXException {
XMLReader reader = XMLReaderFactory.createXMLReader();
// Disable external entities
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
return reader;
}
@Bean
public DocumentBuilderFactory documentBuilderFactory() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setExpandEntityReferences(false);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
return dbf;
}
}
@RestController
@RequestMapping("/api")
public class ApiController {
@PostMapping("/data")
public ResponseEntity<String> processData(@RequestBody String xmlData) {
// mTLS authentication handled by Spring Security
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof X509AuthenticationToken)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("mTLS required");
}
try {
// Secure XML processing
DocumentBuilderFactory dbf = documentBuilderFactory();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xmlData)));
// Process document...
return ResponseEntity.ok("Processed successfully");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("XML processing error");
}
}
}These remediation strategies ensure that even if an attacker obtains a valid mTLS client certificate, they cannot exploit XXE vulnerabilities to compromise internal systems or exfiltrate sensitive data.