If your application turns user input into PDFs, you may have an outbound request engine sitting inside your stack that you never deployed on purpose. A flaw disclosed this week in php-weasyprint, a PHP library with more than 1.2 million installs, lets an attacker who can influence one option make your server fetch internal endpoints, cloud metadata, or local files, then hands those bytes straight back inside the generated PDF. It is tracked as CVE-2026-49359, rated 6.5 out of 10, and already fixed. The score undersells it, because the prize here is your secrets, not a crash.
What the flaw actually is
php-weasyprint is a wrapper around Kozea's WeasyPrint, the document engine that turns HTML into a PDF. It exposes an attachment option so an application can embed a file into the PDF it builds. The problem is what happens when the value of that option looks like a web address. The library fetches it server-side with PHP's file_get_contents() and never restricts the scheme. It decides whether something is a URL with FILTER_VALIDATE_URL, which happily accepts file://, php:// stream wrappers, and ftp:// alongside http and https. So whoever controls the attachment value controls what the server reaches.
Two distinct attacker primitives fall out of that. The first is server-side request forgery, the trick of making a server send requests on the attacker's behalf: an internal admin panel, a database's HTTP interface, or the cloud metadata endpoint at the link-local address that hands out temporary credentials. The second is local file disclosure: a file:// or php:// value reads a file off the server's own disk. Either way the fetched content leaves the same door, embedded as an attachment in the PDF the victim application dutifully returns.
The CVE record, assigned by GitHub, classes the issue as both CWE-918 (server-side request forgery) and CWE-22 (improper path handling), with a CVSS vector that marks confidentiality as high and integrity and availability as none. That vector is the whole story. This bug reads. It does not write, corrupt, or take a service down. Versions 2.5.1 and earlier are affected, and version 2.6.0 carries the fix.
A PDF generator is an outbound-request engine in disguise
This is the same class of bug KnpLabs/snappy patched in its own URL-fetching option, and php-weasyprint was built as a drop-in replacement for snappy, copying its structure closely enough that it inherited the weakness. That overlap is not a coincidence. It is the pattern. Any feature that renders user-influenced HTML or options into a document has to fetch resources to do its job: images, stylesheets, fonts, attachments. The renderer becomes an HTTP and file client running with your server's network position and your server's filesystem access. wkhtmltopdf had this shape, snappy had it, and now the WeasyPrint-based wrapper has it too.
The defender takeaway is to stop treating document and image renderers as inert formatting code. Treat every server-side renderer you run, whether it builds PDFs, thumbnails, screenshots, or office files, as an outbound fetch engine. Then ask it the two questions you would ask of any HTTP client you wrote on purpose: which schemes can it use, and which hosts can it reach. If the answer is anything and anywhere, you have found your next hardening task. We have written before about how easily a server whose whole job is fetching URLs turns into a liability, and how one request can make a server read its own local files.
Are you actually exposed?
Using php-weasyprint does not automatically mean you are vulnerable. The flaw needs a caller who can influence the attachment value. The real test is whether any user-controllable data reaches the PDF options, through a request parameter or a per-tenant configuration row, rather than a fixed server-side constant.
The classic high-risk shape is multi-tenant software where a tenant's setting flows into Pdf::generate(), Pdf::getOutput(), or setOption('attachment', ...). If your attachment value is always a hard-coded string set in code, your exposure is lower. The safe move is still to upgrade, because the next refactor could quietly route user input into that sink without anyone noticing the security boundary it crossed.
What to do now
- Upgrade to 2.6.0 or later. The fix fetches an option URL only when its scheme is on an allow-list, defaulting to
httpandhttpsand configurable through a new$allowedSchemesconstructor argument. The same release also closed an arbitrary file deletion bug and a PHAR deserialization bypass, so it is worth taking regardless of how you use the attachment option. - Keep the attachment value out of user control until you patch. Source it only from trusted server-side configuration. If it has to be dynamic, validate it against an allow-list of permitted hosts and reject any scheme that is not
httporhttps. - Put egress controls around the rendering worker. The library fix closes the scheme, but defense in depth means the host that renders documents should not be able to reach your cloud metadata endpoint or internal ranges in the first place. On AWS, enforce IMDSv2. Block the link-local metadata address from any process that builds documents.
- Audit your call sites. Find every place the attachment option is set and confirm none of it traces back to request input or tenant-supplied data. If you also run KnpLabs/snappy, check its URL-fetching options the same way, because it carries the same design.
For detection, the signal is anomalous outbound traffic from the rendering service. A PDF worker connecting to the metadata address, to link-local space, or to internal hosts it has no reason to touch is the tell, as is a file:// or php:// string surfacing in the inputs that feed PDF options. The confidentiality-only impact means there is no crash to alert on. You have to watch for the quiet read.
The patch has been available since late May, a month before the CVE made it official. The danger now is teams pinned to 2.5.1 who saw 2.6.0 as a routine release and skipped it. The CVE assignment is the prompt to go back and pull it in. A PDF feature is the kind of thing that ships once and never gets a second look, which is exactly why it deserves one this week.