{"id":"CVE-2026-59991","aliases":["DEBIAN-CVE-2026-59991","EUVD-2026-84808","GHSA-8q6g-vjhf-jp8m","PYSEC-2026-4139","UBUNTU-CVE-2026-59991"],"status":"published","title":"psd-tools: Uncontrolled memory allocation in psd-tools composite/numpy via crafted PSD geometry","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00517,"percentile":0.44339,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-789"],"published":"2026-09-22T19:11:38Z","modified":"2026-10-28T02:30:21Z","fixes":[{"ecosystem":"PyPI","package":"psd-tools","fixed_in":["1.17.4"],"sources":["ghsa","osv"]},{"ecosystem":"Debian:14","package":"psd-tools","fixed_in":["1.17.4+dfsg.1-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.17.4"}]}]},{"source":"osv","ecosystem":"Debian:12","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.10.7+dfsg.1-1","1.10.9+dfsg.1-1","1.12.0+dfsg.1-1","1.12.1+dfsg.1-1","1.14.2+dfsg.1-1","1.14.3+dfsg.1-1","1.15.0+dfsg.1-1","1.16.0+dfsg.1-1","1.17.0+dfsg.1-1","1.17.4+dfsg.1-1","1.9.24+dfsg.1-1","1.9.28+dfsg.1-1","1.9.30+dfsg.1-1","1.9.31+dfsg.1-1","1.9.32+dfsg.1-1","1.9.34+dfsg.1-1"]},{"source":"osv","ecosystem":"Debian:13","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.10.7+dfsg.1-1","1.10.7+dfsg.1-1+deb13u1","1.10.9+dfsg.1-1","1.12.0+dfsg.1-1","1.12.1+dfsg.1-1","1.14.2+dfsg.1-1","1.14.3+dfsg.1-1","1.15.0+dfsg.1-1","1.16.0+dfsg.1-1","1.17.0+dfsg.1-1","1.17.4+dfsg.1-1"]},{"source":"osv","ecosystem":"Debian:14","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.17.4+dfsg.1-1"}]}],"versions":["1.10.7+dfsg.1-1","1.10.9+dfsg.1-1","1.12.0+dfsg.1-1","1.12.1+dfsg.1-1","1.14.2+dfsg.1-1","1.14.3+dfsg.1-1","1.15.0+dfsg.1-1","1.16.0+dfsg.1-1","1.17.0+dfsg.1-1"]},{"source":"osv","ecosystem":"PyPI","package":"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"]},{"source":"osv","ecosystem":"PyPI","package":"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"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.9.28+dfsg.1-1","1.9.28+dfsg.1-1build1","1.9.30+dfsg.1-1","1.9.30+dfsg.1-1build1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.12.1+dfsg.1-1","1.17.0+dfsg.1-1","1.17.4+dfsg.1-1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"psd-tools","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.10.7+dfsg.1-1","1.10.7+dfsg.1-1build1","1.10.9+dfsg.1-1","1.12.0+dfsg.1-1","1.12.1+dfsg.1-1"]}],"products":[{"vendor":"psd-tools","product":"psd-tools"}],"references":[{"url":"https://github.com/psd-tools/psd-tools/security/advisories/GHSA-8q6g-vjhf-jp8m","tags":["x_refsource_CONFIRM","exploit","advisory","web","report"]},{"url":"https://github.com/psd-tools/psd-tools/commit/a3d9a53ad51e667b5772a4f636ca6f2e16f4b271","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/psd-tools/psd-tools/releases/tag/v1.17.4","tags":["x_refsource_MISC","web","report"]},{"url":"https://github.com/advisories/GHSA-8q6g-vjhf-jp8m","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/59xxx/CVE-2026-59991.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-59991","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-59991","tags":["advisory"]},{"url":"https://github.com/psd-tools/psd-tools","tags":["package"]},{"url":"https://pypi.org/project/psd-tools","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-59991","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-59991","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-59991","title":"psd-tools: Uncontrolled memory allocation in psd-tools composite/numpy via crafted PSD geometry","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T19:11:38.661Z","modified":"2026-09-22T19:37:39.755Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-789"],"updated_at":"2026-11-02T14:19:58.944663Z"}],"euvd":[{"id":"EUVD-2026-84808","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T19:11:38Z","modified":"2026-09-22T19:37:39Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T17:28:01.71506Z"}],"ghsa":[{"id":"GHSA-8q6g-vjhf-jp8m","title":"psd-tools composite/numpy has uncontrolled memory allocation via crafted PSD geometry","description":"### 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.","status":"published","published":"2026-09-22T19:45:51Z","modified":"2026-09-22T19:45:53Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-789"],"updated_at":"2026-11-02T14:41:19.455935Z"}],"nvd":[{"id":"CVE-2026-59991","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T20:17:04.123Z","modified":"2026-09-23T18:12:04.247Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-789"],"updated_at":"2026-11-02T14:12:50.703874Z"}],"osv":[{"id":"CVE-2026-59991","title":"psd-tools: Uncontrolled memory allocation in psd-tools composite/numpy via crafted PSD geometry","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T19:11:38.661Z","modified":"2026-10-28T02:30:21.830256796Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-789"],"updated_at":"2026-11-02T15:45:12.933503Z"},{"id":"DEBIAN-CVE-2026-59991","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T20:17:04.123Z","modified":"2026-09-24T08:47:34.021966209Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T15:45:57.932517Z"},{"id":"GHSA-8q6g-vjhf-jp8m","title":"psd-tools composite/numpy has uncontrolled memory allocation via crafted PSD geometry","description":"### 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.","status":"published","published":"2026-09-22T19:45:51Z","modified":"2026-10-01T17:56:13.306457211Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-789"],"updated_at":"2026-11-02T15:46:42.78452Z"},{"id":"PYSEC-2026-4139","title":"psd-tools composite/numpy has uncontrolled memory allocation via crafted PSD geometry","description":"### 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.","status":"published","published":"2026-10-01T16:38:34.060897Z","modified":"2026-10-01T17:45:16.013433116Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T15:52:57.255153Z"},{"id":"UBUNTU-CVE-2026-59991","description":"psd-tools is a Python package for working with Adobe Photoshop PSD files. Prior to 1.17.4, PSDImage.composite() and PSDImage.numpy() allocated output buffers from attacker-controlled PSD header geometry, including width, height, channels, depth, and per-layer rectangles, before validating those values against the available file data. A tiny crafted PSD could therefore cause multi-gigabyte memory allocation, and PSDImage.composite() could return a black image with only a warning instead of raising an exception. Services that composite untrusted PSD files could be terminated by out-of-memory handling. This issue is fixed in version 1.17.4.","status":"published","published":"2026-09-22T20:17:00Z","modified":"2026-10-17T12:56:00.429909106Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T16:56:41.911783Z"}]}}
