esbuild v0.28.1, publiée le 11 juin 2026, est la première release du bundler depuis v0.28.0 le 2 avril. Un tel écart de deux mois est inhabituel pour un projet qui sort normalement une release toutes les quelques semaines, et la 0.28.1 dépense son budget sur trois choses qui méritent chacune une mise à jour : une exécution de code à distance de haute gravité dans l'API Deno, un path traversal limité à Windows dans le dev server, et un bug de justesse du minifier qui cassait silencieusement la syntaxe de disposal using et await using.
Comme esbuild est le substrat de l'optimiseur de dépendances et du pipeline TS/JSX de Vite, beaucoup de projets héritent de ces correctifs transitivement. Voici ce qui a changé et qui doit agir.
Une RCE de haute gravité dans l'API Deno
L'élément le plus sérieux est GHSA-gv7w-rqvm-qjhr, notée High avec CVSS 8.1. La distribution Deno d'esbuild (lib/deno/mod.ts) télécharge le binaire natif d'esbuild depuis un registre npm et l'écrit sur disque avec les permissions exécutables (0o755) sans en vérifier le contenu. L'installeur Node avait déjà un binaryIntegrityCheck() qui compare un hash SHA-256 de l'exécutable téléchargé aux valeurs attendues figées dans package.json ; le chemin Deno n'a jamais eu l'équivalent.
Le vecteur d'exploitation est la variable d'environnement NPM_CONFIG_REGISTRY. Le module Deno construit son URL de téléchargement à partir de cette variable, donc quiconque peut la positionner, dans un pipeline CI, une machine de dev partagée ou un réseau d'entreprise qui proxie npm via un registre custom, peut servir un binaire piégé qu'esbuild exécutera sans sourciller. C'est la même classe de défaut de confiance supply-chain qui a produit le récent incident de prise de contrôle du compte npm shai-hulud : le registre est considéré comme sûr par défaut et le consommateur n'a pas de second contrôle.
La 0.28.1 porte le contrôle d'intégrité SHA-256 sur l'installeur Deno. Un binaire dont le hash ne correspond pas à la valeur attendue échoue désormais avec une erreur au lieu de s'exécuter. Notez que l'API Deno d'esbuild installe toujours depuis registry.npmjs.org par défaut et honore toujours NPM_CONFIG_REGISTRY ; le correctif porte sur la vérification, pas sur un changement de source.
Un path traversal Windows dans le dev server
La seconde advisory, GHSA-g7r4-m6w7-qqqr, est notée Low (CVSS 2.5) mais illustre parfaitement un bug classique. Le serveur de développement local d'esbuild nettoyait les chemins de requêtes entrantes avec path.Clean() de Go. Cette fonction est purement POSIX : elle comprend les slashs mais traite un antislash comme un caractère ordinaire. Sous Windows, où \ est un séparateur de chemin valide, une requête forgée pouvait donc sortir du répertoire serve configuré et lire des fichiers arbitraires.
La cause racine tient en une ligne :
queryPath := path.Clean(req.URL.Path)[1:]
La 0.28.1 interdit purement et simplement les antislashs dans les chemins de requêtes du dev server. L'exposition est étroite : elle nécessite le dev server (esbuild.context().serve() ou le flag --serve) sous Windows, joignable par un attaquant. Le bundling de production et les builds one-shot ne sont pas affectés, pas plus que les hôtes macOS et Linux.
Le bug du minifier sur using et await using
Le troisième correctif est celui pour lequel la plupart des développeurs d'application devraient vraiment auditer leur output. Issue #4482 : le minifier d'esbuild inlinait parfois une déclaration using ou await using dans son usage ultérieur, ce qui supprime le binding et signifie que Symbol.dispose / Symbol.asyncDispose ne s'exécute jamais. L'échec ressemble à ça :
// Code original
{
using x = new Resource()
x.activate()
}
// Ancien output esbuild (avec --minify)
new Resource().activate();
// Output corrigé (0.28.1)
{using e=new Resource;e.activate()}
L'ancien output fait fuiter la ressource à chaque fois, parce qu'il ne reste plus de using pour déclencher le disposal en fin de bloc. Le bug existe parce que la passe d'inlining du minifier avait été écrite pour let et const, exclue ensuite pour var, et jamais mise à jour quand la syntaxe d'explicit resource management a ajouté deux nouveaux types de déclaration. Si vous livrez des builds de production minifiés et que vous utilisez using pour des handles de fichiers, des connexions de base de données, des verrous ou n'importe quel AsyncDisposable, c'est une régression de justesse silencieuse qu'il vaut la peine de grep dans votre output de build.
Correctifs de justesse plus petits
Le reste de la 0.28.1 est un cluster de correctifs qui touchent surtout des cas limites de bundling :
- Erreurs de module relancées (#4461, #4467). Si un module lève une erreur pendant l'évaluation, la spec exige que chaque
import()ourequire()ultérieur de ce module relance la même erreur. esbuild ne préservait l'erreur que pour le premier appel. Ça compte pour la logique de retry et la gestion d'erreurs en import dynamique. - Wrapping de l'opérateur
new(#4477). Les cibles complexes denew, en particulier les template literals taggés et les optional chains, n'étaient pas toujours wrappées de parenthèses. L'ancien output était parfois une erreur de syntaxe et parfois modifiait la sémantique, par exemplenew (foo()bar)()etnew (foo()?.bar)(). - Renommage de
varhoisté (#4471). Unvardéclaré dans un scope imbriqué et hoisté vers le scope module n'était pas traité comme un symbole de niveau module lors de la passe de collision de noms, ce qui pouvait faire collider des noms quand la minification était désactivée. constversvaren ES5 (#4448). Pour les constructs TypeScript-onlyimport x = require('y')ciblant ES5, esbuild émet désormaisvarau lieu deconst, qu'il ne pouvait pas downgrader correctement.
Qui doit mettre à jour
La RCE Deno est le seul élément qui justifie une mise à jour immédiate du type « tout le monde, maintenant », et uniquement pour les projets qui consomment esbuild via Deno dans un environnement où NPM_CONFIG_REGISTRY est positionné. Tout le monde devrait quand même passer à la 0.28.1 au prochain bump d'outils de build : le path traversal Windows ferme une exposition réelle, même si étroite, et le correctif de disposal using est un bug de justesse que vous ne voulez pas dans votre output de production minifié.
La release est aussi un rappel utile qu'esbuild n'est pas qu'un détail d'implémentation de Vite. C'est le substrat de transpilation et de minification sous une grande part de la toolchain JavaScript en Rust, et son écart de release de deux mois vaut la peine d'être noté face au rythme hebdomadaire d'Oxc et Rolldown. Pour l'instant, les correctifs atterrissent proprement et la mise à jour est un bun install esbuild@latest ou équivalent. Si vous faites tourner le dev server d'esbuild sous Windows, ou si vous utilisez esbuild depuis Deno derrière un registre custom, faites-le aujourd'hui.



