dompdf aceita uma imagem BMP e gera um PNG compatível com PDF baseado apenas nas suas dimensões de cabeçalho *declaradas* e nunca limita a largura × altura antes de a imagem ser convertida através do GD. A 58 -byte BMP cujo cabeçalho declara p. ex. ` 6000 × 6000 ` é aceito e, posteriormente, uni `imagecreatetruecolor($width, $height)` (e decodificador BMP nativo do PHP) para alocar a tela de pixels completa. Uma carga útil pode caber em um único pedido HTTP: o BMP pode ser inlineado como um `data: image/ bmp;base 64,...` URI dentro do HTML controlado pelo atacante, por isso não é necessário carregar, não é necessário buscar remotamente e não é necessário nenhum arquivo acessível ao chroot. Foi demonstrado que um ** 169 -byte** pedido conduziu dompdf para renderizar para **~ 412 MB pico RSS e ~ 4.8 s** do tempo CPU/parede, versus ~ 34 MB para um pedido benigno de tamanho idêntico — aproximadamente um 12 × amplificação de memória por pedido, repetible e não autêntica. ### Detalhes ## Causa raíz. A imagem é processada com base em dimensões declaradas e apenas no tipo — nenhum orçamento de pixels:.
```php // src/ Image/Cache.php: 131 - 134 list($width, $height, $type) = Helpers::dompdf_getimagesize($resolved_url, $options->getHttpContext()); se (($width && $height && in_array($type, ["gif","png","jpeg","bmp","svg","webp"], true)) === false) { lançar novo ImageException("Tipo de imagem desconhecido", E_WARNING); } ``` Para os BMPs que `getimagesize()` não analisam completamente, o dompdf confia nos campos de cabeçalho bruto: ```php // src/ Helpers.php: 833 - 837 if (substr( $data, 0, 2 ) === "BM") { $meta = desempacote("vtype/Vfilesize/Vreserved/Voffset/Vheadersize/Vwidth/Vheight", $data); $width = (int) $meta["width"]; $height = (int) $meta["height"]; $type = "bmp"; } ````.
No tempo de conversão a tela é alocada a partir das dimensões declaradas, antes de qualquer verificação de que existem dados de pixels suficientes: ```php // src/ Helpers.php: 868 - 869 — o decodificador nativo é tentado PRIMEIRO no PHP >= 7.2 if (function_ exists("imagecreatefrombmp") & & ($im = imagecreatefrombmp($filename))!== false) { retorna $im; } // src/ Helpers.php: 940 — retalho laminado manualmente $im = imagecreatetruecolor($meta['width'], $meta['hight']); `` Não há proteção máxima de largura/altura ou máximo total de pixels em qualquer lugar neste caminho.
1. O HTML do atacante atinge `Dompdf::loadHtml()` com ` ` (ou qualquer BMP ` src`). 2. `Dompdf::render()` decora quadros; ` Frame\Factory` marca ` ` como uma imagem; ` FrameDecorator\ Image` chama ` Image\Cache::resolve_url()`. 3. `Image\Cache::resolve_url()` aceita o BMP em dimensões/tipo declarado (`src/Image/Cache.php: 131 - 134 `). 4. Durante o renderização, o `Adapter\CPDF::image()` identifica o BMP e chama `_convert_to_png()` (`src/Adapter/CPDF.php: 593 `). 5. `_convert_to_png()` invoca `Helpers::imagecreatefrombmp()`, que aloca a tela completa — através da `imagecreatefrombmp()` nativa no PHP ≥ 7.2, ou o retalho manual `imagecreatetruecolor() ', de outra forma. ### PoC erificou contra dompdf @ `a 6 ddc 4 f` no PHP 8.3.6 com GD ativado. O BMP criado é 58 bytes: a 14 -byte cabeçalho do arquivo + 40 -byte `BITMAPINFOHEADER` declarando a largura/altura do alvo no 24 bpp + 4 bytes de acolchoamento. Inlineado como URI de dados, a carga útil completa do atacante é 169 bytes:.
(A base 64 acima decodifica para um 58 -byte BMP declarando ` 6000 × 6000 `. O `largura' do CSS: 1 px; height: 1 px` não ajuda o defensor — o decodificado intrínseco acontece independentemente do que seja.) ### 1 — Conversão direta. ```` native imagecreatefrombmp exist: sim dompdf_getimagessize => 6000 x 6000 tipo=bmp imagecreatefrombmp => GdImage 6000 x 6000 (alocado a partir de um 58 -byte arquivo) Tamanho máximo do conjunto de residentes: 160 MB ( 10 x 10 controle: 24 MB) php_ up (gestão de PHP): 0.8 MB <-- A memória GD é nativa; o limite_de memória PHP NÃO a captura ``` O pico gerenciado pelo PHP está abaixo 1 MB enquanto RSS é 160 MB: a tela vive no allocador nativo da GD, assim `memory_limit` não a liga.
### 2 — Completo `Dompdf::render()`. ``` declarou 6000 x 6000 carga útil 169 octets render 5.8 RSS ~ 417 Saída de MB 106 KB declarado 10 x 10 carga útil 169 octets render 0.01 RSS ~ 30 Saída de MB 1.4 KB ``` ### 3 — Reprodução HTTP (curl / Burp). Reproduzida contra um endpoint PDF mínimo (`server.php`, incluído) que simplesmente renderiza HTML publicado — a forma de qualquer serviço de fatura/report/HTML- para- PDF. O objetivo define ` isRemoteEnabled= False`; o ataque ainda funciona porque `data:` URIs são um protocolo permitido por padrão e não precisam de remote fetch. Enrolação: ````bash curl -s -X POST " \ --data-binary ' ' \ -o /dev/null -w 'http=% {http_code} tempo=% {time_total} s\n' ```.
Repetir o Burp (ativando "Atualizar a Lungura do Conteúdo"): ``` POST / render HTTP/ 1.1 Host: TARGET User- Agent: Mozilla/ 5.0 (Windows NT) 10.0; Ganhar 64; x 64 ) AppleWebKit/ 537.36 (KHTML, como Gecko) Chrome/ 120.0.0.0 Safari/ 537.36 Aceita: texto/html, aplicação/xhtml+xml, aplicação/xml;q= 0.9,*/*;q= 0.8 Aceitar- Idioma: pt- US, pt;q= 0.5 Aceitar- Codificação: gzip, deflate, br Tipo de Conteúdo: texto/html Conexão: fechar Observado (pico RSS lido a partir do `/proc/ / estatus` `VmHWM` do trabalhador, cada um em um trabalhador fresco para que a marca de alta água seja por- petição): ``` [ATTACK ] declarado 6000 x 6000 solicitação= 169 B -> 200 aplicativo/pdf saída= 106397 Apagnância do servidor B RSS ~ 412 Muro MB 4.8 s [CONTROL] declarado 10 x 10 solicitação= 169 B -> 200 aplicativo/pdf saída= 1407 Apagnância do servidor B RSS ~ 34 Muro MB < 0.1 s ```.
Dois tamanhos idênticos 169 -byte solicita; a única diferença são as dimensões declaradas dentro do 58 - BMP byte. O pedido de ataque custa ~ 378 MB memória nativa extra e ~ 5 CPU s. As escalas de custo com a declaração `largura × altura`, limitadas apenas pelo 32 - bit campos de cabeçalho e a memória disponível do hospedeiro (o processo é morto pela OOM antes do máximo teórico). Um único sem autenticação 169 -byte forças de solicitação ~ 400 MB de alocação nativa e vários segundos de CPU no trabalho de renderização. A renderização em PDF é normalmente feita por um pequeno grupo de trabalhadores PHP-FPM ou de fila; um punhado de pedidos concorrentes exausce a memória e a barraca do grupo ou os trabalhadores OOM- mata, negando o serviço aos usuários legítimos. Como a alocação pesada está no allocador nativo do GD, uma solicitação `memory_limit` contém **não**. **Caveat:** este é um primitivo exaustão de recursos (DoS), não a divulgação de dados ou a execução de código. Algumas implantações já sandbox dompdf por trás de tempos de renderização, tampas de memória do trabalhador (cgroups) ou isolamento de trabalho — aquelas reduzem o impacto do mundo real. No entanto, a implementação específica do GD em um sistema pode não ser limitada pelos limites do PHP, permitindo o consumo de recursos a nível do sistema além daqueles alocados ao PHP.
Registro de aconselhamento: GHSA- 8 hg 6 - c 449 - 896 m. Identificadores relacionados: CVE- 2026 - 59941. Tempo: GitHub Advisory Database publicou este registro em 2026 - 07 - 22 T 22: 50: 34.000 Z e lista a sua última modificação como 2026 - 07 - 22 T 22: 50: 34.000 Z. Gravidade: MODERAR. Dados de pontuação publicados: CVSS_V 4: CVSS: 4.0 /AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/África do Sul:N.
Software afetado e informações de versão: Packagist dompdf/dompdf — ECOSISTEM: introduzido 0, corrigido 3.1.6. Classificação e evidência: identificadores de fraqueza CWE- 400. O registro contém 4 suporte de referências nestes tipos: WEB, PACKAGE.