{"id":"GHSA-8q6g-vjhf-jp8m","summary":"psd-tools composite/numpy has uncontrolled memory allocation via crafted PSD geometry","details":"### Summary\n`PSDImage.composite()` (and `.numpy()`) allocate the output image buffer from the PSD's header geometry (width × height × channels × depth, and per-layer rectangles) before validating those values against the actual file contents. A tiny crafted PSD declaring huge dimensions causes a multi-gigabyte allocation. Critically, `composite()` then returns a (black) image with only a warning, no exception is raised, so a caller cannot detect or guard against it.\n\n### Impact\nOn psd-tools 1.17.2 (latest), default usage, a 49-byte PSD makes `composite()` commit ~3 GB and return successfully (warning only); `.numpy()` reaches ~7.5 GB, and the per-layer rectangle is a second lever (up to ~32 GB), all from an input under 100 bytes (input-to-commit amplification over 1000×). Because the buffer is committed before validation and no exception is thrown, any service that composites untrusted PSDs is exposed to denial of service: on a host with less RAM than the attacker-declared geometry the allocation is an unrecoverable OOM-kill. \n\n### Steps to reproduce\n```python\n# pip install psd-tools==1.17.2\nfrom psd_tools import PSDImage\npsd = PSDImage.open(\"psd-psdtools-grammar-d23.psd\")\npsd.composite()   # commits ~3 GB from a 49-byte file and returns (warning only)\n```\n\nPoC (49 bytes), reconstruct with:\n```sh\nbase64 -d \u003e psd-psdtools-grammar-d23.psd \u003c\u003c'EOF'\nOEJQUwABAAAAAAAAAAYAACg4AAAXTAAIAAMAAAAAAAAAAAAAAAAAAUNIUIFU+yQtDw==\nEOF\n```\nVerify:\n```\n7d8ebf03a54393cb0359ecf4b676d1b08c9a8c6afdd06671ef406d6893cce826  psd-psdtools-grammar-d23.psd\n```\n\n### Root cause\nThe composite/numpy buffer is sized from the declared image (and per-layer) dimensions and channel/depth without checking them against the available data length or a sane maximum.\n\n### Suggested fix\nValidate the declared dimensions, channel count, and per-layer rectangles against the actual file length (and a configurable maximum pixel/byte budget) before allocating; raise an error on overflow instead of committing the buffer and returning a black image.","aliases":["CVE-2026-59991","PYSEC-2026-4139"],"modified":"2026-10-01T17:56:13.306457211Z","published":"2026-09-22T19:45:51Z","database_specific":{"cwe_ids":["CWE-789"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-09-22T19:45:51Z","nvd_published_at":null},"references":[{"type":"WEB","url":"https://github.com/psd-tools/psd-tools/security/advisories/GHSA-8q6g-vjhf-jp8m"},{"type":"WEB","url":"https://github.com/psd-tools/psd-tools/commit/a3d9a53ad51e667b5772a4f636ca6f2e16f4b271"},{"type":"PACKAGE","url":"https://github.com/psd-tools/psd-tools"},{"type":"WEB","url":"https://github.com/psd-tools/psd-tools/releases/tag/v1.17.4"}],"affected":[{"package":{"name":"psd-tools","ecosystem":"PyPI","purl":"pkg:pypi/psd-tools"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.17.4"}]}],"versions":["0.1.1","0.1.2","0.1.3","0.1.4","0.10","0.2","0.5","0.6","0.7","0.7.1","0.8","0.8.1","0.8.2","0.8.3","0.8.4","0.9","0.9.1","1.0","1.1","1.10.0","1.10.1","1.10.10","1.10.11","1.10.12","1.10.13","1.10.2","1.10.3","1.10.4","1.10.5","1.10.6","1.10.7","1.10.8","1.10.9","1.11.0","1.11.1","1.12.0","1.12.1","1.12.2","1.13.0","1.13.1","1.14.0","1.14.1","1.14.2","1.14.3","1.15.0.post1","1.16.0","1.17.0","1.17.1","1.17.2","1.17.3","1.2","1.3","1.4","1.8.10","1.8.11","1.8.12","1.8.13","1.8.14","1.8.15","1.8.16","1.8.17","1.8.18","1.8.19","1.8.20","1.8.21","1.8.22","1.8.23","1.8.24","1.8.25","1.8.26","1.8.27","1.8.28","1.8.29","1.8.30","1.8.31","1.8.32","1.8.33","1.8.34","1.8.35","1.8.36","1.8.37","1.8.38","1.8.8","1.8.9","1.9.0","1.9.1","1.9.10","1.9.11","1.9.12","1.9.13","1.9.14","1.9.15","1.9.16","1.9.17","1.9.18","1.9.19","1.9.2","1.9.20","1.9.21","1.9.22","1.9.23","1.9.24","1.9.26","1.9.27","1.9.28","1.9.29","1.9.3","1.9.30","1.9.31","1.9.32","1.9.33","1.9.34","1.9.4","1.9.5","1.9.6","1.9.7","1.9.8","1.9.9"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-8q6g-vjhf-jp8m/GHSA-8q6g-vjhf-jp8m.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]}