Vulnerability GHSA-qfx6-q44v-9qqw
Summary
ag-psd can exhaust memory when parsing crafted PSD dimensions
Details
Summary
readPsd() commits the image/layer buffers from the declared header geometry (width x height x channels x depth, and per-layer rectangles) before validating those values against the actual data. A tiny crafted PSD declaring huge geometry forces a multi-gigabyte allocation.
Impact
On ag-psd 30.2.0, Node 24, a 52-byte PSD makes readPsd(buf) commit ~3.17 GB (measured peak RSS) in ~0.45 s before throwing a catchable RangeError ("Offset is outside the bounds of the DataView") — about 61,000,000x amplification. Because the buffer is committed before validation, the allocation OOM-kills the process before the error on essentially any host (uncatchable), and concurrent requests exhaust memory. Any service reading untrusted PSDs with ag-psd is exposed to a remote DoS.
This is distinct from #39 and #206, which involve genuinely large PSDs (memory proportional to real data). Here the input is 52 bytes: the file declares enormous geometry that is never present, so the allocation is driven by an unvalidated header field, not by actual content, an uncontrolled-allocation denial-of-service vulnerability, not proportional memory use.
Steps to reproduce
The PoC is a 52-byte PSD (sha256 a1146a6fabdfef289472f99a56851249e7a46e8d19d4d8bf85fe833e2f0158b6). Reconstruct with:
base64 -d > poc.psd <<'EOF'
OEJQUwABAAAAAAAAAA0AADcuAAA58wAgAAMAAAAAAAAAAAAAAAAAAdEgNZv+i9bc9ygd2A==
EOF
Then (commits ~3.17 GB before throwing a catchable RangeError):
const { readPsd } = require('ag-psd');
const buf = require('fs').readFileSync('poc.psd');
readPsd(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
Root cause
psdReader.js sizes the off-heap typed-array buffers from the declared header dimensions (and per-layer rectangles, a second independent lever) before validating against the available bytes.
Suggested fix
Validate the declared dimensions, channel count, depth, and per-layer rectangles against the actual input length (and a sane maximum) before allocating.
Related Vulnerabilities
Other vulnerabilities affecting the same packages