Le fil de l’actualité

Écrit par l’IASécurité

Traiter des PDF non fiables sans risque : isoler Ghostscript et les convertisseurs de documents

Le CVE-2026-39919 de Ghostscript sert de déclencheur. La vraie question : ce que SAFER, les conteneurs, les limites de ressources et le correctif arrêtent, et ce qu’ils ratent.

Une page PDF lumineuse entrant dans un coffre de verre scellé au cœur d’un centre de données sombre

Rédigé par une IA. Cette analyse a été rédigée par une IA et publiée sans relecture ligne par ligne.

Dans l’actualité

Un téléversement de PDF, c’est un fichier que vous avez demandé à un programme qui ne vous appartient pas d’ouvrir. Le plus souvent, ce programme est un générateur de vignettes, une chaîne d’impression ou une file de conversion, et il tourne avec plus d’accès que personne ne se souvient avoir accordé. La question n’est pas de savoir si le bogue de Ghostscript est grave. Elle est de savoir quelles couches, entre le fichier téléversé et votre serveur, l’arrêtent vraiment, et lesquelles rendent seulement l’incident plus difficile à expliquer.

Avant de lire : Notre texte sur comment isoler des agents IA défend les sorties réseau refusées par défaut et les frontières placées hors du processus attaqué. Cet article applique la même logique à un convertisseur que vous n’avez pas écrit et que vous ne pouvez pas corriger ligne par ligne.

Pourquoi maintenant : Le 13 octobre 2026, BleepingComputer a signalé un dépassement de tampon critique dans le tas de l’interpréteur et du moteur de rendu de Ghostscript, suivi sous le nom CVE-2026-39919, qui peut mener à l’exécution de code à distance par un PDF malveillant. Wordfence l’a découvert le 23 août, et Artifex a livré le correctif dans Ghostscript 10.08.0 le 8 septembre. L’actualité sert de déclencheur. Le problème, lui, était déjà dans votre chaîne de traitement de PDF.

Table des matières

La faible fiabilité n’est pas la sécurité

Les deux preuves de concept de Wordfence écrivaient 1 024 octets dans un tampon de 256 octets, soit un dépassement quatre fois supérieur à la taille prévue. En laboratoire, sur des paquets Linux, elles ont été exécutées 10 240 fois sans obtenir d’exécution de code à distance. Elles ont réussi sur un serveur de test conçu à cette fin. Changer les polices, les réglages de langue, la configuration des polices et une bibliothèque centrale aidait, sans garantir le résultat.

Lisez ce chiffre comme un résultat de laboratoire, pas comme une garantie. 10 240 échecs rassurent un mainteneur. Un attaquant patient n’a besoin que d’un environnement qui s’aligne par hasard. Wordfence a testé dix environnements Linux, dont un instantané de l’image Docker officielle de WordPress, et a trouvé le code vulnérable dans tous. Être dans la liste de paquets par défaut est la situation courante, pas l’exception.

La plage touchée selon Wordfence va de 9.21 à 10.07.1. Des correctifs ont aussi été rétroportés vers des branches plus anciennes. Vérifiez donc les détails de révision dans l’avis de votre distribution plutôt que de comparer seulement les numéros de version.

Le dépassement se produit sous les couches que vous configurez

Le PDF malveillant de ce cas contient une image JPEG 2000, et le dépassement se situe dans le décodage d’image pendant le rendu. Ce n’est pas un opérateur PostScript. Cette distinction détermine ce que chaque contrôle peut voir.

Selon ma lecture de la documentation de Ghostscript, SAFER agit au niveau PostScript : il contrôle l’accès aux fichiers, le choix des périphériques et certains paramètres de périphérique. La même page indique que ses contrôles de fichiers s’appliquent à tout ce qui passe par l’interface fichier C de Ghostscript, puis ajoute qu’Artifex n’a aucun contrôle sur le code tiers. Une erreur de bornes dans un décodeur n’est pas un accès au fichier. SAFER n’a jamais son mot à dire.

Cela ne rend pas SAFER inutile. Cela en fait un outil différent, visant une autre partie de l’attaque. Le tableau ci-dessous est ma lecture des sources, pas un résultat de test.

ContrôleCe qu’il toucheArrête le dépassement lui-mêmeLimite les dégâts après l’exécution de code
Correctif vers 10.08.0 ou rétroportationLe bogueOui, pour ce bogueNon
-dSAFER (par défaut depuis la 9.50)Accès PostScript aux fichiers, périphériques et paramètresNonEn partie, pour les accès fichier et périphérique faits par l’interpréteur
Listes d’autorisations (—permit-file-read et compagnons)Chemins lisibles ou inscriptiblesNonEn partie, pour les chemins hors liste
Conteneur sans réseau et racine en lecture seuleRéseau, vue du système de fichiers, processusNonOui, si bien configuré
Limites de mémoire, de processus et de tempsRessources et exécutions emballéesNonPlafonne l’usage des ressources et arrête les exécutions folles
Désactiver PDF dans la politique ImageMagickL’expositionRetire cette voieRetire cette voie

Anneaux de sécurité concentriques autour d’une page PDF, un anneau par contrôle

Couche 1 : corriger, puis vérifier le correctif

Passez à la version 10.08.0 ou plus récente, ou à une rétroportation de votre distribution qui contient le correctif. Ensuite, vérifiez ce qui tourne réellement : dpkg -l ghostscript sur Debian et Ubuntu, et gs --version sur le binaire lui-même.

Faites la même vérification dans l’image que vous déployez. L’hôte et le conteneur livrent souvent des paquets différents, et une image de base périmée est un moyen facile de se croire corrigé alors qu’on ne l’est pas.

Couche 2 : SAFER est une clôture, pas un mur

SAFER est le réglage par défaut depuis la 9.50, et la documentation précise que save et restore ne l’annulent pas, contrairement à l’ancienne implémentation. Une fois .activatepathcontrol exécuté, un appel ultérieur à .addcontrolpath est une erreur fatale. C’est un bon signe : le design est fait pour se verrouiller, pas pour négocier.

Le travail réel se fait avec les options de liste d’autorisations : --permit-file-read, --permit-file-write, --permit-file-control, --permit-file-all et --permit-devices. Il y a un piège subtil. Les chemins passés sur la ligne de commande, comme -I ou -sFONTPATH, sont ajoutés automatiquement à la liste de lecture. Le répertoire de polices indiqué pour le rendu devient donc lisible par tout ce qui tourne dans ce processus, y compris ce qu’un attaquant aurait réussi à exécuter. Auditez ces chemins comme vous auditez le chemin de téléversement.

Une commande de conversion qui rend les réglages par défaut visibles :

gs -dSAFER -dBATCH -dNOPAUSE -dQUIET -dPDFSTOPONERROR -dFirstPage=1 -dLastPage=1 -dPDFFitPage -sDEVICE=png16m -r72 -sOutputFile=/work/out/vignette.png /work/in/upload.pdf

-dSAFER est déjà la valeur par défaut; l’écrire sert le lecteur. -dPDFSTOPONERROR arrête l’exécution sur une entrée brisée au lieu de laisser l’analyse tolérante continuer. Les limites de pages et -dPDFFitPage gardent le travail à la seule page dont une vignette a besoin.

Couche 3 : ne donner au convertisseur rien à atteindre

Ghostscript écrit ses fichiers temporaires dans /tmp, sauf si TMPDIR ou TEMP le redéfinit. C’est le seul endroit inscriptible dont un convertisseur a normalement besoin, à part sa sortie. Construisez le conteneur autour de ce fait :

docker run --rm --network none --read-only --tmpfs /tmp:rw,size=64m --memory 256m --pids-limit 32 --cap-drop ALL --security-opt no-new-privileges --user 65534:65534 -v $PWD/in:/work/in:ro -v $PWD/out:/work/out gs-converter:patched gs -dSAFER -dBATCH -dNOPAUSE -dQUIET -dPDFSTOPONERROR -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -sOutputFile=/work/out/vignette.png /work/in/upload.pdf

gs-converter:patched est un nom fictif à remplacer par votre image. Chaque option retire quelque chose. --network none supprime la sortie vers le réseau, donc un rappel d’exploit n’a nulle part où aller. --read-only et un petit tmpfs laissent un seul espace de travail. --cap-drop ALL et no-new-privileges retirent les capacités Linux et bloquent la prise de privilèges par les binaires setuid. --memory et --pids-limit plafonnent les dégâts d’un processus qui déraille. Le montage d’entrée est en lecture seule, donc le convertisseur ne peut pas réécrire le fichier qu’on lui a remis.

Un PDF scellé dans un conteneur transparent, sans câble réseau branché

Le point critique : les conteneurs partagent le noyau de l’hôte. Cette configuration réduit ce qu’un attaquant ayant obtenu l’exécution de code peut atteindre. Elle ne fait pas du noyau un mur, et un bogue noyau est un autre problème. Pour de grands volumes d’entrées non fiables, l’étape suivante est une frontière plus forte, comme gVisor ou une microVM, qui place un noyau distinct entre le convertisseur et l’hôte. Je n’ai pas mesuré ce que cette commande bloque, et je ne ferais pas d’affirmation à ce sujet tant que quelqu’un ne l’a pas fait.

Couche 4 : mettre une horloge et un nombre de pages à chaque travail

Un convertisseur qui tourne indéfiniment est un déni de service avec un beau logo. Enveloppez l’appel dans un timeout, et fixez la valeur d’après votre document légitime le plus lent plutôt qu’après une supposition : timeout 20s gs ....

Ne traitez que ce qu’il faut. Ghostscript ne rend que les pages demandées quand vous donnez -dFirstPage, -dLastPage ou -sPageList. Un travail de vignette ne devrait jamais toucher à la page 400 d’un manuel numérisé. Plafonnez aussi la taille du téléversement avant que Ghostscript démarre. Cette vérification ne coûte rien et se fait hors du processus qui vous inquiète.

La politique actuelle de Ghostscript consiste à tenter de rendre les PDF brisés en affichant un avertissement. C’est utile pour une personne qui a une facture endommagée. Sur un point de téléversement public, cela signifie que l’analyseur continue sur des entrées qu’un outil plus strict refuserait. -dPDFSTOPONERROR est l’interrupteur qui le fait plutôt s’arrêter.

Couche 5 : retirer les fonctions que vous n’utilisez pas

-dDOPS active les flux PostScript à l’intérieur des PDF. La documentation le déconseille pour les applications soucieuses de sécurité, et il est désactivé par défaut. Le piège, c’est l’enveloppe : tout script ou toute bibliothèque qui lance Ghostscript peut ajouter des options que vous n’avez jamais tapées. Cherchez donc DOPS dans l’enveloppe et dans la politique ImageMagick, ainsi que les codecs PDF.

Le PDF a été conçu pour s’afficher pareil sur chaque écran. Il peut aussi transporter des flux PostScript, c’est-à-dire un langage de programmation, et l’interrupteur qui les fait tourner est désactivé par défaut. Parmi tous les réglages rassurants de cet article, celui-là est le plus rassurant.

Si votre site n’a besoin de vignettes PDF que pour une médiathèque, le contrôle le moins coûteux est de désactiver PDF dans la politique ImageMagick. BleepingComputer le cite comme mesure d’atténuation. Cela retire la voie, pas le bogue, et cela ne change rien aux appels directs à Ghostscript.

Un plan de test que vous pouvez exécuter sans l’exploit

Je ne publie pas de banc d’essai pour la preuve de concept publique, et vous n’en avez pas besoin. Testez les frontières avec des fichiers bénins. Construisez deux images en laboratoire : une corrigée, une figée sur une version dont vous voulez sortir. Lancez ensuite des sondes qui demandent ce qu’un convertisseur ne devrait jamais faire :

  1. Un fichier PostScript qui tente de lire /etc/passwd avec l’opérateur de fichier, par exemple (/etc/passwd) (r) file. Sous SAFER, il doit être refusé. Notez le message d’erreur exact.
  2. La même sonde en écriture, d’abord vers /tmp, puis vers un chemin hors de la liste d’écriture.
  3. Un PDF au nombre de pages excessif, pour vérifier que -dLastPage et le timeout se comportent comme prévu.
  4. Un PDF volontairement malformé, pour comparer la sortie avec et sans -dPDFSTOPONERROR.

Mesurez la mémoire maximale avec /usr/bin/time -v et vérifiez le code de sortie quand le timeout se déclenche. Puis faites ce que le bac à sable est censé rendre difficile : comparez ce que le processus peut atteindre depuis le conteneur avec ce qu’il peut atteindre depuis un shell hôte nu.

Ces résultats, et non les options listées ici, doivent décider de votre configuration. Je n’ai exécuté aucun de ces tests pour cet article. Traitez donc chaque ligne du tableau comme une hypothèse, jusqu’à ce que vos chiffres la remplacent.

Ce que chaque couche vous achète

Le correctif ferme le trou. Tout le reste détermine combien de la maison part avec le cambrioleur. SAFER empêche le convertisseur d’ouvrir les mauvais fichiers, le conteneur l’empêche de téléphoner à la maison, et les limites empêchent un mauvais document de tenir un travailleur en otage. Aucune de ces couches n’arrête le dépassement. Si vous ne pouvez pas garder un décodeur corrigé à temps, l’option honnête est de cesser de lui donner les fichiers d’inconnus.

Faits amusants

  • Quatre fois plus : 1 024 octets dans un tampon de 256 octets, soit un dépassement quatre fois supérieur. Cela a quand même échoué 10 240 fois en laboratoire.
  • Une valeur par défaut, pas une frontière : SAFER est activé par défaut depuis la 9.50, mais la documentation dit qu’Artifex n’a aucun contrôle sur le code tiers. Les valeurs par défaut protègent le code écrit par leurs auteurs.
  • Le répertoire temporaire est un choix : Ghostscript écrit ses fichiers temporaires dans /tmp si rien ne dit le contraire. Un convertisseur non configuré choisit donc discrètement l’emplacement de ses fichiers de travail.

Sources