agentggagentgg
Back to all findings
HIGHconfirmedfile-upload-validationunsafe-yaml-parse-on-uploadf2ab09972b00

YAML upload deserialised without size or content validation

handleYamlUpload invokes yaml.load on the raw uploaded buffer with no size cap, no MIME/extension allowlist, and no schema, exposing the server to YAML-bomb DoS amplification.

Fileroutes/fileUpload.ts
Lines105130
Confidence
80%
File statusvalidated
Details
const data = file.buffer.toString()
...
const yamlString = vm.runInContext('JSON.stringify(yaml.load(data))', sandbox, { timeout: 2000 })

The entire upload buffer is converted to a string and parsed. Because checkUploadSize (see separate finding) is a no-op and there is no multer limits.fileSize, the input can be arbitrarily large. The explicit yamlBombChallenge recovery path in this same function confirms a billion-laughs-style alias expansion attack is reachable. While js-yaml v4's default load no longer instantiates arbitrary JS objects, the lack of a size limit and the use of String.prototype.toString on a possibly huge Buffer is itself a memory-exhaustion vector before parsing even starts.

Proof of concept

POST a 5 MB YAML bomb (a small file with nested anchor aliases that expands to gigabytes in memory) as bomb.yml to the upload endpoint. The handler buffers it, calls yaml.load, and either OOMs the worker or trips the 2 s vm timeout — the existing code admits as much by solving yamlBombChallenge in that branch.

Impact

Unauthenticated denial of service via memory/CPU exhaustion against any node serving this endpoint.

Validation
confirmed

The handler calls file.buffer.toString() then yaml.load(data) on arbitrary uploaded content with no size cap — checkUploadSize only flags a challenge instead of rejecting, and no multer limits.fileSize is configured. While the 2s vm timeout mitigates pure CPU exhaustion, memory-amplification YAML bombs are explicitly reachable, as proven by the in-code yamlBombChallenge branch that catches 'Invalid string length' / 'Script execution timed out'. Per scope, Juice Shop must be evaluated as a real production app, so this unauthenticated DoS vector is a legitimate bug.

CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Base score: 7.5 · HIGH

The endpoint accepts file uploads over HTTP with no authentication middleware visible in this route, so an anonymous remote attacker can hit handleYamlUpload directly (AV:N, PR:N, UI:N). The handler performs file.buffer.toString() followed by yaml.load(data) inside a vm with only a 2 s timeout and no size cap (since checkUploadSize is a no-op and no multer.limits.fileSize is configured), so a single YAML-bomb POST reliably exhausts memory/CPU — the existence of yamlBombChallenge in the catch branch confirms the path is exploitable with low complexity (AC:L). The impact is purely DoS on the affected worker (A:H); js-yaml v4's default schema does not instantiate arbitrary JS objects and the parsing happens inside a vm sandbox, so there is no disclosure or tampering primitive (C:N/I:N) and the impact stays within the Node process's authority (S:U).

References