Xml External Entities in Hapi with Mutual Tls
Xml External Entities in Hapi with Mutual Tls — how this specific combination creates or exposes the vulnerability
XML External Entity (XXE) injection is a web application security issue that occurs when an application processes untrusted XML data containing references to external entities. In Hapi, if XML parsing is enabled—such as when using payload parsers that accept XML input—and the parser is configured to resolve external entities, an attacker can supply a malicious XML document that references internal files, hosts, or services. This can lead to sensitive data exposure, server-side request forgery (SSRF), denial of service, or credential leakage.
Mutual Transport Layer Security (mTLS) adds client certificate authentication to the TLS handshake, ensuring that both the client and the server authenticate each other. While mTLS strengthens channel-level authentication and helps verify that requests originate from trusted clients, it does not inherently protect against application-layer attacks such as XXE. In fact, the combination of XXE in Hapi with mTLS can create a misleading sense of security: operators may assume that strong client authentication prevents abuse, but if the server parses untrusted XML with external entity resolution enabled, an authenticated client can still inject malicious payloads.
The risk scenario typically unfolds as follows: an API endpoint in Hapi accepts XML input, perhaps for configuration or structured data uploads. If the underlying XML parser resolves DOCTYPE declarations and external entity references, an attacker who possesses a valid client certificate (obtained through proper or compromised mTLS credentials) can send an XML body that reads local files via file:// URLs, triggers SSRF to internal services, or consumes excessive resources through billion laughs attacks. Because mTLS ensures the request is authenticated, logging and monitoring may treat the request as legitimate, delaying detection. The server’s response might disclose file contents or internal hostnames, directly violating data exposure controls.
Compounding the issue, Hapi applications that rely on community XML parsing plugins or custom payload processing may not explicitly disable external entity resolution. Default configurations in some parsers are permissive, and developers might overlook hardening settings. Even with mTLS enforcing strict client identity, the server-side XML processing remains vulnerable if entities are not explicitly forbidden. This underscores that transport-layer controls like mTLS complement but do not replace input validation and secure parsing practices.
An illustrative request from an authenticated client might include a Content-Type of application/xml and a body such as <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><root>&xxe;</root>. If Hapi forwards this to an XML parser that resolves the external entity, the server may read /etc/passwd and include it in the response or error logs. Security checks that include XML input validation and entity expansion limits are essential, regardless of mTLS status.
Mutual Tls-Specific Remediation in Hapi — concrete code fixes
To mitigate XXE in Hapi while using mTLS, focus on disabling external entity resolution in XML parsing and validating incoming payloads. Below are concrete code examples for a Hapi server with mTLS configured and hardened XML handling.
Hapi server with mTLS and secure XML parsing
The following example demonstrates a Hapi server with mTLS enabled and XML input processed safely by disabling external entities and limiting parser behavior.
const Hapi = require('@hapi/hapi');
const fs = require('fs';
const path = require('path');
const XmlParser = require('fast-xml-parser');
const init = async () => {
const server = Hapi.server({
port: 443,
host: '0.0.0.0',
tls: {
key: fs.readFileSync(path.join(__dirname, 'certs/server.key')),
cert: fs.readFileSync(path.join(__dirname, 'certs/server.crt')),
ca: [fs.readFileSync(path.join(__dirname, 'certs/ca.crt'))],
requestCert: true,
rejectUnauthorized: true,
},
});
// Secure XML parsing options: disable external entities and DTD
const xmlOptions = {
ignoreAttributes: true,
attributeNamePrefix: '_',
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
// Disable DOCTYPE and external entity resolution
validate: false,
isArray: false,
allowBooleanAttributes: false,
// Prevent entity expansion
ignoreDeclaration: true,
// Reject dangerous features
parserLimit: 10000,
};
server.route({
method: 'POST',
path: '/upload',
handler: (request, h) => {
const xml = request.payload;
if (!XmlParser.validate(xml)) {
return h.response({ error: 'Invalid XML' }).code(400);
}
const json = XmlParser.parse(xml, xmlOptions);
// Process json safely
return h.response({ received: true });
},
options: {
payload: {
output: 'data',
parse: true,
allow: 'application/xml',
},
},
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.error(err);
process.exit(1);
});
Key points in the configuration:
requestCert: trueandrejectUnauthorized: trueenforce mTLS so only clients with trusted certificates can connect.- XML parsing options explicitly disable DTD and external entity resolution. The
ignoreDeclarationand restricted parser limits reduce the risk of entity expansion attacks. - Input validation with
fast-xml-parserensures well-formed XML before processing, reducing parsing errors that could expose sensitive data.
In addition to code fixes, operational practices matter: rotate mTLS certificates regularly, monitor authentication logs for anomalies even though mTLS authenticates clients, and apply the principle of least privilege to server-side file and network access. Remember that middleBrick scans can help identify XXE indicators and other XML-related misconfigurations in your deployed endpoints, providing prioritized findings and remediation guidance.
For teams using CI/CD, the middleBrick GitHub Action can add API security checks to your pipelines, failing builds if risk scores drop below your chosen threshold. The middleBrick CLI allows on-demand scans from the terminal with middlebrick scan <url>, and the MCP Server enables scanning APIs directly from AI coding assistants.