{"record":{"id":"c7774251cae14447","repo":"dompdf/dompdf","slug":"permission-denied-on-file-the-communication-prot","errorCode":null,"errorMessage":"Permission denied on $file. The communication protocol is not supported.","messagePattern":"Permission denied on \\$file\\. The communication protocol is not supported\\.","errorType":"exception","errorClass":"Dompdf\\Exception","httpStatus":null,"severity":"error","filePath":"src/Dompdf.php","lineNumber":357,"sourceCode":"     *\n     * Parse errors are stored in the global array `$_dompdf_warnings`.\n     *\n     * @param string      $file     A filename or URL to load.\n     * @param string|null $encoding Encoding of the file.\n     */\n    public function loadHtmlFile($file, $encoding = null)\n    {\n        $this->setPhpConfig();\n\n        if (!$this->protocol && !$this->baseHost && !$this->basePath) {\n            [$this->protocol, $this->baseHost, $this->basePath] = Helpers::explode_url($file);\n        }\n        $protocol = strtolower($this->protocol);\n        $uri = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $file, $this->options->getChroot());\n\n        $allowed_protocols = $this->options->getAllowedProtocols();\n        if (!array_key_exists($protocol, $allowed_protocols)) {\n            throw new Exception(\"Permission denied on $file. The communication protocol is not supported.\");\n        }\n\n        if ($protocol === \"file://\") {\n            $ext = strtolower(pathinfo($uri, PATHINFO_EXTENSION));\n            if (!in_array($ext, $this->allowedLocalFileExtensions)) {\n                throw new Exception(\"Permission denied on $file: The file extension is forbidden.\");\n            }\n        }\n\n        foreach ($allowed_protocols[$protocol][\"rules\"] as $rule) {\n            [$result, $message] = $rule($uri);\n            if (!$result) {\n                throw new Exception(\"Error loading $file: $message\");\n            }\n        }\n\n        [$contents, $http_response_header] = Helpers::getFileContent($uri, $this->options->getHttpContext());\n        if ($contents === null) {","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/dompdf/dompdf/blob/b14267808b811db092f53830f81f4706f4917c79/src/Dompdf.php#L339-L375","documentation":"loadHtmlFile() enforces a protocol whitelist before any I/O: the URI's scheme must be a key of Options::allowedProtocols (defaults: data://, file://, http://, https://). Any other scheme — or a scheme an administrator removed while hardening dompdf against SSRF/LFI — throws this permission error immediately. It is a security control, not an incidental failure.","triggerScenarios":"$dompdf->loadHtmlFile('ftp://server/doc.html') or any wrapper outside the whitelist; a deployment calls setAllowedProtocols() with only file:// (anti-SSRF hardening) while application code still loads http(s):// URLs; custom stream wrappers used as the document source.","commonSituations":"Hardening dompdf after security guidance (removing remote protocols), then legacy features that render remote pages break; passing wrapper-prefixed paths like phar:// or php://temp; inconsistent configuration between staging and production.","solutions":["Extend the whitelist deliberately: $options->setAllowedProtocols([...]) — note it REPLACES the map, so include every protocol you need with their rules.","Or fetch the document yourself (curl/Guzzle) and pass the body to $dompdf->loadHtml($html) — this respects app-level network controls instead of dompdf's.","If remote loading is not required, keep it disabled and generate/load local HTML."],"exampleFix":"// before\n$dompdf->loadHtmlFile('ftp://example.com/report.html'); // throws: ftp not allowed\n\n// after: either whitelist the protocol\n$dompdf->getOptions()->setAllowedProtocols([\n    'data://' => ['rules' => []],\n    'file://' => ['rules' => []],\n    'http://' => ['rules' => []],\n    'https://' => ['rules' => []],\n    'ftp://' => ['rules' => []],\n]);\n\n// or bypass with explicit fetching\n$dompdf->loadHtml(file_get_contents_curl('ftp://example.com/report.html'));","handlingStrategy":"validation","validationCode":"$scheme = strtolower(parse_url($file, PHP_URL_SCHEME) . '://');\n$allowed = $dompdf->getOptions()->getAllowedProtocols();\nif (!array_key_exists($scheme, $allowed)) {\n    throw new InvalidArgumentException(\"Protocol not allowed by dompdf config: $file\");\n}\n$dompdf->loadHtmlFile($file);","typeGuard":null,"tryCatchPattern":"try {\n    $dompdf->loadHtmlFile($file);\n} catch (\\Dompdf\\Exception $e) {\n    if (strpos($e->getMessage(), 'communication protocol is not supported') !== false) {\n        $dompdf->loadHtml(file_get_contents_via_app_client($file)); // app-controlled fetch\n    }\n}","preventionTips":["Derive the allowed-protocol configuration from one place in your app so code and config cannot drift.","Default to fetching remote documents with your HTTP client and passing strings to loadHtml().","Document the SSRF rationale for any protocol you keep enabled."],"tags":["security","protocol","url","ssrf","configuration"],"backgroundTag":"url-protocol-not-allowed","analyzedSha":"b14267808b811db092f53830f81f4706f4917c79","analyzedAt":"2026-08-21T03:01:11.111Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}