XML parser error message leaked to client in handleXmlUpload catch block
The catch block in handleXmlUpload propagates the raw libxml/VM parser error message back to the client via next(new Error(...)), leaking internal parser/library details.
In handleXmlUpload, the catch block extracts err.message (or String(err)) into errorMessage and then forwards it to Express's error handler with:
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err)
...
res.status(410)
next(new Error('B2B customer complaints via file upload have been deprecated for security reasons: ' + errorMessage + ' (' + file.originalname + ')'))
}
Express's default/finalhandler error pipeline (and Juice Shop's error middleware) renders the Error.message (and sometimes the stack) into the response body. The errorMessage here is the raw output of libxml.parseXml running inside a vm sandbox — these errors include things like line/column offsets, parser internals, entity-resolution errors that disclose internal file paths when XXE is attempted (e.g., failed to load external entity "file:///etc/passwd"), and Node VM internals. This gives an attacker direct fingerprinting of the parsing stack and confirms successful XXE side channels.
- POST an XML file to the B2B upload endpoint containing an external entity referencing a non-existent or restricted path, e.g.:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///nonexistent">]>
<foo>&xxe;</foo>
- The response body contains the raw libxml error string (e.g.
failed to load external entity "file:///nonexistent"), confirming the original error message is reflected to the client.
Unauthenticated/low-privilege attackers uploading B2B complaint XML files receive raw parser error text, which leaks library identity, internal paths referenced during entity resolution, and confirms XXE side channels — useful for fingerprinting and for chaining into XXE file-disclosure attacks.
The catch block concatenates errorMessage (raw err.message from libxml/VM) into the Error passed to next(). Express's default/finalhandler error pipeline renders this message in the response body, and Juice Shop's error middleware behaves similarly. An attacker uploading an XML with malformed content or an external entity (e.g., file:///nonexistent) will receive the raw libxml diagnostic — leaking parser identity, internal paths, and confirming XXE side-channels. The specific unsafe element is next(new Error('...: ' + errorMessage + ' (' + file.originalname + ')')) on the else branch of the catch.
The vulnerable sink is an HTTP file-upload endpoint reachable over the network, and the code shown contains no authentication or authorization gate on handleXmlUpload — any client can POST a crafted XML file and trigger the catch branch that concatenates err.message into the next(new Error(...)) response. Exploitation requires only sending a malformed/XXE XML payload (AC:L, UI:N). The leak is limited to libxml/VM parser error strings (line/column offsets, library identity, and any external-entity URIs libxml echoes back such as file:///...), giving the attacker partial, attacker-influenced disclosure of internal information rather than arbitrary file contents, so Confidentiality is Low and Integrity/Availability are unaffected. Scope remains Unchanged because the disclosure stays within the same Express application's security authority.
- CWE-209
- CWE-211
- OWASP A09:2021