Mille dollars. C'est la prime que Google a versée à Salvatore Gulizia, le chercheur connu sous le pseudo Serotav, pour avoir signalé ce qui est devenu la CVE-2026-85046, un bug de type confusion dans V8 que des criminels exploitaient déjà avant que le correctif n'atteigne la plupart des machines. La build corrigée, Chrome 152.0.7977.82, est sortie le 3 septembre 2026. La CISA a ajouté la faille à son catalogue Known Exploited Vulnerabilities dès le lendemain et a donné aux agences fédérales américaines jusqu'au 18 septembre. CVSS 8.8, sixième zero-day Chrome de l'année confirmé comme activement exploité. Tu pourrais légitimement te demander pourquoi un journal PHP consacre sa chronique à un bug de navigateur. Parce qu'il y a de bonnes chances que ton application PHP embarque un navigateur, et que personne dans ton équipe ne soit chargé de le patcher.

Fais un rapide grep mental sur ta propre stack. spatie/browsershot qui génère factures et étiquettes d'expédition via Puppeteer. Laravel Dusk ou Symfony Panther qui pilotent un vrai Chromium dans ta suite de tests. Un conteneur Playwright dans la pipeline CI. Peut-être un scraper qui récupère des pages fournisseurs et les transforme en données structurées pour le backend de la boutique. Chacun de ces outils embarque une build Chromium complète, et ce binaire écrase à lui seul tout ton répertoire vendor réuni. Pourtant composer audit affiche du vert, Dependabot reste muet, et l'image construite en mars tourne toujours avec le Chromium de sa naissance. On a passé une décennie à professionnaliser l'hygiène des dépendances PHP, et le plus gros exécutable du conteneur passe tranquillement à côté de tout ça.

L'advisory offre une consolation: ce bug seul donne une exécution de code dans le processus de rendu sandboxé, et pour transformer ça en compromission complète de l'hôte, il faut le chaîner avec une évasion séparée. Très bien pour un Chrome de bureau. Maintenant, ouvre ton Dockerfile. Tu vois ce flag --no-sandbox que tu as ajouté parce que Chromium refuse de démarrer son sandbox dans un conteneur sans privilèges supplémentaires, et que tous les tutoriels Browsershot du web te disaient de le mettre ? Félicitations, la consolation ne s'applique plus à toi. Dans cette configuration, une exécution de code dans le renderer, c'est une exécution de code dans ton worker, avec l'environnement de ton worker: le DSN de la base, les clés S3, les tokens d'API internes posés dans $_ENV comme des fruits dans une corbeille.

L'objection la plus solide mérite une réponse franche: mon worker de rendu ne surfe pas sur des sites d'attaquants, je contrôle le HTML qu'il voit. Vraiment ? Le déclencheur de la CWE-843, c'est du JavaScript dans une page piégée, qui exploite une confusion du compilateur où un tableau d'objets ordinaires se retrouve étiqueté avec une map prévue pour des petits entiers, ce qui dégénère en lectures et écritures arbitraires sur le tas JS. Ton template de facture interpole des noms de clients, des adresses, des notes de commande en texte libre. Ton scraper récupère des pages tierces dont le métier même est d'échapper à ton contrôle. À moins de désactiver explicitement JavaScript pendant le rendu, et presque personne ne le fait parce que les feuilles de style print et les bibliothèques de graphiques en ont besoin, une entrée non fiable se trouve à un rendu de template du JIT de V8.

Et ce ne sera pas la dernière fois. Deux des cinq zero-days Chrome exploités plus tôt en 2026 logeaient aussi dans V8. Ce moteur spécule agressivement sur la forme des objets pour rendre JavaScript rapide, et chaque spéculation est une hypothèse qui peut être brisée. Google le fuzze, le durcit, paie des primes pour ses bugs, et ils continuent d'arriver quand même, parce que le design sacrifie des marges de sécurité au profit de la vitesse sur les chemins chauds. Chrome desktop absorbe ça grâce à la mise à jour automatique, en général avant que les utilisateurs ne s'en aperçoivent. Ta version de Puppeteer épinglée dans le package.json voisin du composer.json n'absorbe rien du tout. Elle attend, patiemment vulnérable, qu'un humain la bumpe, reconstruise l'image et redéploie les workers de queue.

Voici donc ce que je changerais concrètement. D'abord, promeus le navigateur au rang de dépendance de production nommée, versionnée, avec un responsable, exactement comme tu traites le runtime PHP lui-même: quand Chrome stable bouge pour une raison de sécurité, un job CI doit échouer bruyamment tant que ton Chromium embarqué n'a pas bougé aussi. Ensuite, mets-le en quarantaine. Une étape de rendu devrait être un petit service ennuyeux qui accepte du HTML d'un côté et émet des octets de PDF de l'autre, sans identifiants qui vaillent la peine d'être volés ni route vers internet qui vaille la peine d'être abusée. Enfin, et c'est le point inconfortable, demande-toi si le navigateur a sa place dans la pipeline tout court. Une facture à deux colonnes avec un logo n'a pas besoin d'un compilateur JIT. dompdf ou mpdf la dessineront sans jamais exécuter une ligne de JavaScript, et oui, tu maudiras leur support CSS, et oui, ce compromis peut quand même être le bon.

C'est sur ce dernier compromis que j'attends vraiment tes objections. J'ai livré les deux: des documents rendus par Chromium au pixel près qui ont fait le bonheur de la compta, et des PDF en PHP natif qui ont raccourci la revue de sécurité. Après avoir vu V8 produire son sixième zero-day exploité en neuf mois, je penche pour réserver le navigateur aux rares documents qui le méritent vraiment. Et toi, tu te situes où ? Un CSS print fidèle vaut-il la peine de materner un moteur de navigateur avec cette cadence de patchs, ou es-tu revenu à une bibliothèque PDF native en PHP en faisant la paix avec ses caprices ? Dis-moi sur quoi tourne ta pipeline de documents, et pourquoi.