Link Search Menu Expand Document

XML Entity Expansion in NodeJS

Vulnerable example

The following Express.js route parses XML data coming from a POST request and returns the parsed content in the HTTP response. In the example below, libxmljs is configured with external entity processing enabled:

app.post('/load_xml', upload.single('xml'), async function (req, res) {
    if (!req.file) {
        res.sendStatus(500);
        return;
    }

    try {
        const xml = req.file.buffer;
        const doc = libxmljs.parseXml(xml, {noent: true});
        res.send(doc.text());
    } catch (err) {
        res.send(err.toString());
        res.sendStatus(500);
    }
});

When the function libxmljs.parseXml is invoked, its logic parses and expands the external entities. For example, when uploading the XML document below:

<!DOCTYPE d [<!ENTITY e SYSTEM "file:///etc/passwd">]><t>&e;</t>

The entity &e; is expanded with the content of the local /etc/passwd system file, resulting in the disclosure of the file.

Prevention

Node.js does not provide a native XML parser. Third-party libraries that provide libxml bindings can be used, for example libxmljs.

Parsing of external entities is disabled by default; care must be taken to avoid processing untrusted XML data when this option is enabled. Parsing of external entities can be enabled as follows:

const doc = libxmljs.parseXml(xml, {noent: true});

References

OWASP - XML External Entity (XXE) Processing OWASP - XML External Entity Prevention Cheat Sheet