Link Search Menu Expand Document

XML Entity Expansion in NodeJS

Play SecureFlag Play NodeJS Labs on this vulnerability with SecureFlag!

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: false});

References

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