Xml External Entities in Adonisjs with Api Keys
Xml External Entities in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability
XML External Entity (XXE) injection occurs when an application processes untrusted XML input that references external entities. In AdonisJS, this risk can intersect with API key authentication in two primary ways: (1) API keys passed in HTTP headers may be inadvertently reflected into XML processing logic, and (2) API keys used to gate XML-based endpoints may not prevent an attacker from sending malicious XML payloads to those same endpoints.
Consider an AdonisJS route that accepts XML uploads (e.g., SOAP or legacy data formats) and uses an API key header to identify the consumer. If the route parses the XML using an XML parser configured to resolve external entities, an attacker who knows or guesses a valid API key can submit crafted XML that references internal file paths, internal service URLs, or parameter entities. A malicious payload might look like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>&xxe;</root>
If the parser resolves the entity, the file contents may be returned in error messages, logs, or responses. Even when API keys enforce access control, the route handler might still deserialize the attacker-controlled XML, enabling information disclosure or server-side request forgery (SSRF) against internal services. In AdonisJS, common causes include using libraries that enable external entity resolution by default, failing to disable DTDs, or constructing XML documents by concatenating strings rather than using safe serializers.
Another scenario involves OpenAPI/Swagger specs loaded or generated by the application. If an AdonisJS service exposes an endpoint that returns an OpenAPI spec and accepts an API key, an attacker could attempt XXE via spec references if the server processes untrusted XML without proper safeguards. Because the scan categories include Input Validation and Data Exposure, middleBrick can detect whether endpoints that accept or return XML are vulnerable to XXE indirectly by analyzing responses for unexpected data exposure when entity references are injected.
Additionally, API keys used for authentication should not be assumed to prevent injection; authentication and input validation are separate controls. An authenticated request with a valid API key that carries malicious XML may still lead to XXE if the server-side parser is misconfigured. This underscores the need to treat XML input as untrusted regardless of authentication or authorization mechanisms.
Api Keys-Specific Remediation in Adonisjs — concrete code fixes
To mitigate XXE in AdonisJS when API keys are used, focus on secure XML parsing and strict input validation. Below are concrete remediation patterns with code examples.
1. Disable external entities for XML parsers
If you use a library like libxmljs or a SOAP client, ensure DTDs and external entities are disabled. For example, with fast-xml-parser, configure strict parsing:
const { XMLParser } = require("fast-xml-parser");
const parser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "@_",
textNodeName: "#text",
// Ensure no external entity resolution
allowBooleanAttributes: true,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
// Reject DOCTYPE and external entities
validation: false,
});
const xml = `<?xml version="1.0"?>
<root>safe</root>`;
if (!parser.validate(xml)) {
throw new Error("Invalid XML");
}
const jsonObj = parser.parse(xml);
console.log(jsonObj);
2. Use a secure XML parser with DTD and entity expansion disabled
For Node.js, prefer parsers that disable external resolution by default. With xmldom, avoid the default entity loader:
const { DOMParser } = require("xmldom");
const xml = `<?xml version="1.0"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" >]&
lt;root>&xxe;</root>`;
const doc = new DOMParser().parseFromString(xml, "text/xml");
// Ensure implementation does not resolve external entities; consider using a hardened fork or sanitizer
const serializer = new XMLSerializer();
const serialized = serializer.serializeToString(doc);
console.log(serialized);
Note: Some DOMParser implementations may still attempt to resolve entities; test behavior in your runtime and consider additional sanitization.
3. Validate and sanitize inputs before processing
Regardless of parser settings, validate incoming XML against a strict schema. In AdonisJS, you can use Joi or validator libraries to ensure payloads conform to expected structure and reject unexpected entities or references:
const { schema, rules } = use("Validator");
const xmlSchema = schema.create({
xml_body: schema.string.optional({}, [
rules.regex(/^<\?xml[^>]*>?<root>[\s\S]*<\/root>$/),
// Reject DOCTYPE if present
rules.regex(/<!DOCTYPE/i).negate(),
]),
});
const { fails } = await xmlSchema.validate({ xml_body: request.input("xml_body") });
if (fails) {
return response.badRequest({ error: "Invalid XML payload" });
}
// Proceed with parsing using a safe parser
4. Separate authentication from parsing logic
Ensure API key verification occurs before any XML deserialization. This reduces the attack surface by failing fast on malformed or malicious payloads. Example middleware in AdonisJS:
const ApiKey = use("App/Models/ApiKey");
async function verifyApiKey({ request, response, next }) {
const apiKey = request.header("x-api-key");
if (!apiKey) {
return response.unauthorized({ error: "API key missing" });
}
const key = await ApiKey.query().where("key", apiKey).first();
if (!key) {
return response.unauthorized({ error: "Invalid API key" });
}
await next();
}
// Apply to routes that handle XML
Route.post("/xml-endpoint", ["ApiKey.verify"], async ({ request }) => {
const safeParser = new XMLParser({ /* hardened config */ });
const payload = safeParser.parse(request.post());
// process payload
});