multer: dos nombres de campo y te matan el proceso Node
Cuatro advisories contra multer el mismo día, y el peor es brutal por lo barato: un atacante remoto sin autenticar crashea el proceso Node con un solo request multipart/form-data. Dos nombres de campo de texto crafteados provocan un RangeError: Invalid array length sin capturar dentro del parseo de campos — y no se rutea al error handler de la aplicación, termina el proceso. Todas las apps que usan multer están afectadas. Sin workaround, upgrade a 2.3.0.
Los otros tres: DoS por leak de file descriptors en uploads abortados, DoS por índice de array sobredimensionado en nombres de campo, y bypass del límite de tamaño de archivo por una race en fileFilter asíncrono.
Si tenés un endpoint de upload en Express expuesto a internet, este es tu segundo item del día después de Next.js.
Nodemailer: el parser de direcciones es cuadrático y el de dominios no sigue el estándar
Cuatro advisories. El de severidad alta: lib/addressparser/index.js parsea listas de direcciones separadas por coma en tiempo cuadrático O(n²). Un solo string crafteado en To, Cc, Bcc, From o Reply-To consume CPU proporcional al cuadrado de su longitud y bloquea el event loop de Node entero, negando servicio a todas las demás requests del proceso.
El más sutil, y el que me parece más peligroso: Nodemailer resuelve dominios internacionales (IDN) a una etiqueta Punycode distinta de la que resuelve cualquier parser conforme a UTS-46 — browsers, el WHATWG URL Standard, url.domainToASCII de Node, idna de Python. Usa el codec RFC-3492 crudo sin mapping UTS-46. ¿Consecuencia? Un dominio que tu validador mapea a un dominio confiable, Nodemailer lo entrega a otro. Tu allow-list dice que sí y el mail sale para el atacante.
Sumale el bypass de validación de dominio por mal parseo de comentarios RFC 5322 y el de resolveContent() salteando disableFileAccess/disableUrlAccess. Todo a 9.1.0.
Hono: el fix de CVE-2026-39408 no cubría todas las secuencias de traversal
Tres advisories. El principal es un fix incompleto: toSSG() todavía puede escribir archivos fuera del directorio de salida cuando un parámetro de ruta contiene segmentos .. consecutivos. La causa es elegante y didáctica: la verificación de que el path resultante queda dentro del output normaliza el path con la misma rutina que lo construyó. Si la rutina no normaliza del todo, el chequeo hereda exactamente el mismo punto ciego.
Los otros dos: anidamiento sin límite de dot-notation en parseBody() causando agotamiento de memoria, y el query parser leyendo parámetros después del fragmento de la URL, lo que genera diferenciales de interpretación entre tu app, el proxy y la cache key. Ese último es material clásico de cache poisoning. Fix en 4.13.5.
Vitest: lectura arbitraria de archivos vía redirect mock del dev server
@vitest/mocker registra el path destino de un redirect mock sin validarlo contra la allowlist de file-serving del dev server. Quien pueda alcanzar el WebSocket del dev server registra un mock apuntando fuera del root del proyecto, y cuando se pide ese módulo el hook load devuelve readFile(<path del atacante>) como código fuente del módulo. Explotable sin autenticación a través del mockerPlugin público.
Afecta desde 2.1.0 hasta 4.1.11, y también la línea 5 beta hasta 5.0.0-rc.2. Otro caso más de tooling de desarrollo escuchando más de lo que creías — el mismo tema que venimos viendo toda la semana.
xmldom: catorce advisories, y la deduplicación de atributos es O(M²)
Catorce advisories contra @xmldom/xmldom en un día, la mayoría en 8.7. El más representativo: construye la colección de atributos insertando de a uno en un NamedNodeMap, y cada inserción hace un scan lineal de todos los atributos ya insertados para aplicar la regla de unicidad del DOM. Parsear un elemento con M atributos cuesta 1 + 2 + … + M = O(M²).
Lo que lo hace peor: el payload es XML perfectamente bien formado. No hay nada malformado que detectar, es «un elemento con muchos atributos». Ninguna validación de esquema te salva.
El resto del paquete es un desfile de bypasses de requireWellFormed —por terminadores de línea embebidos en nombres de elemento, atributo, DocType y publicId/systemId, más inyección vía createElement() y setAttribute()— y varios ReDoS más. Parcheado en 0.8.15 y 0.9.12. El paquete legacy xmldom (<= 0.6.0) no tiene fix: migrá.
Gitea: RCE instalando un git hook desde el endpoint diffpatch
Crítico. El endpoint diffpatch se puede abusar para instalar y ejecutar un git hook desde contenido controlado por el repositorio. Un atacante con acceso de escritura ordinario ejecuta comandos de shell arbitrarios como el usuario del sistema operativo bajo el que corre Gitea.
Y acá está la parte que convierte esto en emergencia: con el registro abierto por defecto, un visitante sin autenticar consigue el acceso de escritura necesario simplemente registrando una cuenta y creando un repositorio. O sea, de anónimo a RCE en dos pasos triviales. Parcheado en 1.27.1.
Si tenés un Gitea self-hosted con registro abierto, cerralo o actualizá ahora mismo.
Netty: un ClientHello fragmentado saltea tu mTLS por SNI (CVSS 9.1)
Crítico, 9.1. Un ClientHello de TLS cuyo header de handshake se reparte entre varios records hace que Netty caiga silenciosamente al SslContext por defecto. Donde la selección por SNI es la única barrera de mTLS, un atacante sin autenticar saltea el requisito de mTLS de la ruta.
La causa es de manual: en SslClientHelloHandler#decode, el guard que debería esperar los 4 bytes del header de handshake chequea el offset equivocado — ignora los 5 bytes del record header que lo preceden — así que nunca dispara. Un off-by-five en el parseo de un protocolo, y se te cae la autenticación mutua.
Parcheado en 4.2.17.Final y 4.1.137.Final. Viene con un segundo advisory por reensamblado cuadrático pre-handshake en el parseo de SNI por defecto.
GitPython: un valor dormido en git-config se despierta como directiva viva (CVSS 9.3)
Crítico, 9.3, y el mecanismo es de los más lindos que vi en el año. Valores multilínea dormidos en un git-config se corrompen convirtiéndose en directivas inyectadas vivas —por ejemplo core.hooksPath— en cualquier escritura no relacionada del GitConfigParser. O sea: el valor era inerte, vos escribís otra cosa completamente distinta en el config, y el round trip de lectura-escritura lo activa. De ahí a RCE.
Es un read-then-corrupt-on-rewrite, no una inyección por argumento de un setter. Por eso se escapa de cualquier revisión que mire solo las llamadas a la API. Parcheado en 3.1.59.
Vienen cuatro advisories más de GitPython el mismo día: clone_from() omitiendo --separate-git-dir de las opciones inseguras, denylist incompleta que permite lectura arbitraria vía Repo.blame(), y disclosure de archivos por directiva [include] en un .gitmodules no confiable.
El día que medio ecosistema resultó cuadrático
Contá los del 8 de septiembre: xmldom (dedup de atributos O(M²), ReDoS de PI, parseo cuadrático en recovery, memoria cuadrática), Nodemailer (addressparser O(n²)), Tiptap (ReDoS cuadrático en parseo de atributos Markdown), Netty (reensamblado cuadrático pre-handshake), HTTPX2 (buffering cuadrático de SSE), Colord (rechazo lento de strings malformados), NLTK (tres ReDoS distintos), y este de LiquidJS: el filtro join permite saltear el memoryLimit y crashear el proceso.
No es coincidencia, es una clase de bug que estamos sistemáticamente sin testear. Y tiene una firma reconocible: el input es válido. Bien formado, dentro de los límites de tamaño, pasa cualquier validación de esquema. Lo que lo hace tóxico no es el contenido sino la forma — profundidad de anidamiento, cantidad de atributos, cantidad de elementos en una lista.
La conclusión práctica: tus límites cuentan bytes, y el costo real casi nunca está en los bytes. Un límite de tamaño de request no te protege de un documento chiquito y muy anidado. Cuando escribas un parser, medí el costo en función de la forma del input, no de su peso — y poné un límite explícito sobre esa dimensión.
Node.js 24.21.0: OpenSSL 3.5.8, certificados raíz nuevos y BlockList más rápido
Release cargado de criptografía: OpenSSL sube a 3.5.8, los certificados raíz se actualizan a NSS 3.126, y Undici pasa a 7.29.1. Como minor nuevo, soporte para cargar claves privadas a través de STORE loaders de OpenSSL — útil si tenés las claves en un HSM o en un provider externo en vez de en el filesystem.
Del lado de performance: mejor implementación de histogramas y net.BlockList más rápido. Si usás BlockList para filtrado de IPs en el hot path, ese es un upgrade gratis.
workerd v1.20260909.1 sostiene la cadencia diaria
Otro release diario del runtime de Workers. En un día donde el resto del ecosistema publicó 99 advisories, la cadencia predecible de Cloudflare es casi un descanso. Revisá el changelog acumulado si trackeás compatibility flags.
Astro 7.3.2: valores dinámicos en script y style de MDX ya se escapan
Además del parche de AVIF, Astro corrige el renderizado de <script> y <style> en MDX: ahora solo el contenido literal se trata como markup confiable (incluido el que inyectan plugins de remark/rehype). Un valor dinámico pasado como child —<script>{value}</script>— se escapa como el contenido de cualquier otro elemento en vez de renderizarse crudo. Si querés el comportamiento anterior, ahora hay que optar explícitamente con set:html.
Esa es la decisión correcta: el default pasa a ser seguro y la excepción pasa a ser explícita. Ojo si tenías contenido dinámico legítimo ahí — te va a cambiar el render y tenés que marcarlo a mano.
pnpm 12.4.0 sigue el ritmo de la línea en Rust
Nuevo minor de la línea 12 nativa, apenas días después de 12.3.x. El ritmo de releases desde el rewrite en Rust es notablemente más alto — bueno para los fixes, pero mantené el ojo en los breaking changes acumulados si venís de la línea 11.
Tendencias Destacadas
La cadena del día es una clase magistral sobre dependencias transitivas: <strong>un bug en libheif —C, upstream, que probablemente ni sabías que estaba en tu árbol— sube por sharp y sale como RCE sin autenticar con CVSS 9.5 en Next.js y como crítico en Astro</strong>. Mirá cómo cambia el score en el camino: 8.9 en sharp, 9.5 en Next.js. Es el mismo bug; lo que cambia es <strong>cuánta superficie de internet le pone encima cada capa</strong>. Tu análisis de riesgo de dependencias no puede parar en el <code>package.json</code> directo.
99 advisories en un solo día, con paquetes enteros cayendo en bloque: xmldom 14, NLTK 16, GitPython 5, HTTPX2 5, Nodemailer 4, multer 4, Hono 3. Ese patrón no es «se rompió todo el mismo martes» — es <strong>auditoría sistemática de un paquete a la vez</strong>, muy probablemente asistida por herramientas. La consecuencia para vos es práctica: <strong>cuando veas un advisory de una librería que usás, buscá los hermanos del mismo día antes de parchear</strong>. Actualizar por el CVE que te llegó y dejar los otros tres es peor que no enterarte, porque te da la sensación de estar cubierto.
Tres bugs del día comparten la misma raíz conceptual: <strong>una verificación que hereda el defecto de lo que verifica</strong>. En Hono, el chequeo de que <code>toSSG()</code> no escribe fuera del output normaliza el path <em>con la misma rutina que lo construyó</em>. En Netty, el guard que espera el header de handshake mira el offset equivocado y nunca dispara. En GitPython, el parser de config lee un valor inerte y lo reescribe activado. En los tres, <strong>el control existía y estaba escrito con la misma lógica que el error que debía atrapar</strong>. Si tu validación comparte código con la construcción, no es validación — es la misma afirmación dicha dos veces.
multer: two field names and your Node process is dead
Four advisories against multer on the same day, and the worst is brutal for how cheap it is: a remote unauthenticated attacker crashes the Node process with a single multipart/form-data request. Two crafted text field names trigger an uncaught RangeError: Invalid array length inside field parsing — and it is not routed to the application error handler, it terminates the process. Every app using multer is affected. No workaround, upgrade to 2.3.0.
The other three: DoS via file descriptor leak on aborted uploads, DoS via oversized array index in field names, and a file size limit bypass through an async fileFilter race condition.
If you have an Express upload endpoint facing the internet, this is your second item of the day after Next.js.
Nodemailer: the address parser is quadratic and the domain parser ignores the standard
Four advisories. The high-severity one: lib/addressparser/index.js parses comma-separated address lists in quadratic O(n²) time. A single crafted string in To, Cc, Bcc, From, or Reply-To burns CPU proportional to the square of its length and blocks Node's entire event loop, denying service to every other request in the process.
The subtler one, and to me the more dangerous: Nodemailer resolves international (IDN) domains to a Punycode label different from every UTS-46-conformant parser — browsers, the WHATWG URL Standard, Node's url.domainToASCII, Python's idna. It uses the raw RFC-3492 codec with no UTS-46 mapping. The consequence? A domain your validator maps to a trusted one, Nodemailer delivers somewhere else. Your allow-list says yes and the mail goes to the attacker.
Add the domain validation bypass via RFC 5322 comment mis-parsing, and resolveContent() bypassing disableFileAccess/disableUrlAccess. All fixed in 9.1.0.
Hono: the CVE-2026-39408 fix did not cover every traversal sequence
Three advisories. The main one is an incomplete fix: toSSG() can still write files outside the output directory when a route parameter contains consecutive .. segments. The cause is elegant and instructive: the check that the resulting path stays inside the output normalizes the path with the same routine that built it. If that routine does not fully normalize, the check inherits exactly the same blind spot.
The other two: unbounded dot-notation nesting in parseBody() causing memory exhaustion, and the query parser reading parameters after the URL fragment, producing interpretation differentials between your app, the proxy, and the cache key. That last one is classic cache poisoning material. Fixed in 4.13.5.
Vitest: arbitrary file read via the dev server's redirect mock
@vitest/mocker registers a redirect mock's target path without validating it against the dev server's file-serving allowlist. Anyone who can reach the dev server's WebSocket registers a mock pointing outside the project root, and when that module is requested the load hook returns readFile(<attacker path>) as the module source. Exploitable without authentication through the public mockerPlugin.
Affects 2.1.0 through 4.1.11, and the 5 beta line up to 5.0.0-rc.2. One more case of development tooling listening more widely than you assumed — the same theme we have been seeing all week.
xmldom: fourteen advisories, and attribute deduplication is O(M²)
Fourteen advisories against @xmldom/xmldom in one day, most at 8.7. The most representative: it builds each element's attribute collection by inserting one at a time into a NamedNodeMap, and every insertion performs a linear scan of all already-inserted attributes to enforce the DOM uniqueness rule. Parsing an element with M attributes costs 1 + 2 + … + M = O(M²).
What makes it worse: the payload is perfectly well-formed XML. There is nothing malformed to detect — it is «one element with many attributes». No schema validation saves you.
The rest of the batch is a parade of requireWellFormed bypasses — via embedded line terminators in element, attribute, DocType, and publicId/systemId names, plus injection through createElement() and setAttribute() — and several more ReDoS. Fixed in 0.8.15 and 0.9.12. The legacy xmldom package (<= 0.6.0) has no fix: migrate.
Gitea: RCE by installing a git hook through the diffpatch endpoint
Critical. The diffpatch endpoint can be abused to install and execute a git hook from repository-controlled content. An attacker with ordinary write access runs arbitrary shell commands as the OS user Gitea runs under.
And here is what turns this into an emergency: with default open registration, an unauthenticated visitor obtains the required write access by simply registering an account and creating a repository. Anonymous to RCE in two trivial steps. Fixed in 1.27.1.
If you run self-hosted Gitea with open registration, close it or upgrade right now.
Netty: a fragmented ClientHello bypasses your SNI-based mTLS (CVSS 9.1)
Critical, 9.1. A TLS ClientHello whose handshake header spans multiple records makes Netty silently fall back to the default SslContext. Where per-SNI selection is the sole mTLS gate, an unauthenticated attacker bypasses the route's mTLS requirement.
The cause is textbook: in SslClientHelloHandler#decode, the guard that should wait for the 4-byte handshake header checks the wrong offset — it ignores the 5-byte record header preceding it — and therefore never fires. An off-by-five in protocol parsing, and your mutual authentication is gone.
Fixed in 4.2.17.Final and 4.1.137.Final. It ships alongside a second advisory for quadratic pre-handshake reassembly in default SNI parsing.
GitPython: a dormant git-config value wakes up as a live directive (CVSS 9.3)
Critical, 9.3, and the mechanism is one of the prettiest I have seen this year. Dormant multi-line values in a git-config are corrupted into live injected directives — for example core.hooksPath — on any unrelated GitConfigParser write. The value was inert, you write something completely different to the config, and the read-write round trip activates it. From there, RCE.
It is a read-then-corrupt-on-rewrite, not an injection through a setter argument. Which is why it slips past any review that only inspects API calls. Fixed in 3.1.59.
Four more GitPython advisories landed the same day: clone_from() omitting --separate-git-dir from unsafe options, an incomplete denylist enabling arbitrary file read via Repo.blame(), and file disclosure through an [include] directive in an untrusted .gitmodules.
The day half the ecosystem turned out to be quadratic
Count the September 8 batch: xmldom (O(M²) attribute dedup, PI ReDoS, quadratic recovery parsing, quadratic memory), Nodemailer (O(n²) addressparser), Tiptap (quadratic ReDoS in Markdown attribute parsing), Netty (quadratic pre-handshake reassembly), HTTPX2 (quadratic SSE buffering), Colord (slow rejection of malformed strings), NLTK (three separate ReDoS), and this LiquidJS one: the join filter lets template authors bypass memoryLimit and crash the process.
This is not coincidence, it is a bug class we are systematically failing to test. And it has a recognizable signature: the input is valid. Well-formed, within size limits, passes any schema validation. What makes it toxic is not the content but the shape — nesting depth, attribute count, number of elements in a list.
The practical conclusion: your limits count bytes, and the real cost is almost never in the bytes. A request size limit does not protect you from a small, deeply nested document. When you write a parser, measure cost as a function of the input's shape, not its weight — and put an explicit bound on that dimension.
Node.js 24.21.0: OpenSSL 3.5.8, fresh root certificates, and a faster BlockList
A crypto-heavy release: OpenSSL moves to 3.5.8, root certificates update to NSS 3.126, and Undici goes to 7.29.1. New as a minor, support for loading private keys through OpenSSL STORE loaders — useful when your keys live in an HSM or an external provider rather than the filesystem.
On performance: an improved histogram implementation and a faster net.BlockList. If you use BlockList for IP filtering on the hot path, that is a free upgrade.
workerd v1.20260909.1 holds the daily cadence
Another daily Workers runtime release. On a day when the rest of the ecosystem published 99 advisories, Cloudflare's predictable cadence is almost a relief. Read the accumulated changelog if you track compatibility flags.
Astro 7.3.2: dynamic values in MDX script and style are now escaped
Alongside the AVIF patch, Astro fixes <script> and <style> rendering in MDX: only literal content is now treated as trusted markup (including content injected by remark/rehype plugins). A dynamic value passed as a child — <script>{value}</script> — is escaped like any other element's content instead of rendered raw. To get the old behavior you must now opt in explicitly with set:html.
That is the right call: the default becomes safe and the exception becomes explicit. Watch out if you had legitimate dynamic content there — your render will change and you have to mark it by hand.
pnpm 12.4.0 keeps the Rust line moving
A new minor on the native 12 line, days after 12.3.x. The release rhythm since the Rust rewrite is noticeably higher — good for fixes, but keep an eye on accumulated breaking changes if you are coming from the 11 line.
Notable Trends
The day's chain is a masterclass in transitive dependencies: <strong>a bug in libheif — C, upstream, probably something you did not know was in your tree — climbs through sharp and comes out as unauthenticated RCE at CVSS 9.5 in Next.js and critical in Astro</strong>. Watch the score change along the way: 8.9 at sharp, 9.5 at Next.js. Same bug; what changes is <strong>how much internet surface each layer puts on top of it</strong>. Your dependency risk analysis cannot stop at the direct <code>package.json</code>.
99 advisories in a single day, with entire packages falling in batches: xmldom 14, NLTK 16, GitPython 5, HTTPX2 5, Nodemailer 4, multer 4, Hono 3. That pattern is not «everything broke on the same Tuesday» — it is <strong>systematic auditing one package at a time</strong>, very likely tool-assisted. The practical consequence: <strong>when you see an advisory for a library you use, look for its same-day siblings before patching</strong>. Upgrading for the CVE that reached you and leaving the other three is worse than not knowing, because it leaves you feeling covered.
Three of the day's bugs share one conceptual root: <strong>a check that inherits the defect of what it checks</strong>. In Hono, the check that <code>toSSG()</code> does not write outside the output normalizes the path <em>with the same routine that built it</em>. In Netty, the guard waiting for the handshake header looks at the wrong offset and never fires. In GitPython, the config parser reads an inert value and writes it back activated. In all three, <strong>the control existed and was written with the same logic as the error it was meant to catch</strong>. If your validation shares code with your construction, it is not validation — it is the same assertion stated twice.
multer : deux noms de champ et le processus Node meurt
Four advisories against multer on the same day, and the worst is brutal for how cheap it is: a remote unauthenticated attacker crashes the Node process with a single multipart/form-data request. Two crafted text field names trigger an uncaught RangeError: Invalid array length inside field parsing — and it is not routed to the application error handler, it terminates the process. Every app using multer is affected. No workaround, upgrade to 2.3.0.
The other three: DoS via file descriptor leak on aborted uploads, DoS via oversized array index in field names, and a file size limit bypass through an async fileFilter race condition.
If you have an Express upload endpoint facing the internet, this is your second item of the day after Next.js.
Nodemailer : le parser d'adresses est quadratique et celui de domaines ignore le standard
Four advisories. The high-severity one: lib/addressparser/index.js parses comma-separated address lists in quadratic O(n²) time. A single crafted string in To, Cc, Bcc, From, or Reply-To burns CPU proportional to the square of its length and blocks Node's entire event loop, denying service to every other request in the process.
The subtler one, and to me the more dangerous: Nodemailer resolves international (IDN) domains to a Punycode label different from every UTS-46-conformant parser — browsers, the WHATWG URL Standard, Node's url.domainToASCII, Python's idna. It uses the raw RFC-3492 codec with no UTS-46 mapping. The consequence? A domain your validator maps to a trusted one, Nodemailer delivers somewhere else. Your allow-list says yes and the mail goes to the attacker.
Add the domain validation bypass via RFC 5322 comment mis-parsing, and resolveContent() bypassing disableFileAccess/disableUrlAccess. All fixed in 9.1.0.
Hono : le correctif de CVE-2026-39408 ne couvrait pas toutes les séquences
Three advisories. The main one is an incomplete fix: toSSG() can still write files outside the output directory when a route parameter contains consecutive .. segments. The cause is elegant and instructive: the check that the resulting path stays inside the output normalizes the path with the same routine that built it. If that routine does not fully normalize, the check inherits exactly the same blind spot.
The other two: unbounded dot-notation nesting in parseBody() causing memory exhaustion, and the query parser reading parameters after the URL fragment, producing interpretation differentials between your app, the proxy, and the cache key. That last one is classic cache poisoning material. Fixed in 4.13.5.
Vitest : lecture arbitraire de fichiers via le redirect mock du dev server
@vitest/mocker registers a redirect mock's target path without validating it against the dev server's file-serving allowlist. Anyone who can reach the dev server's WebSocket registers a mock pointing outside the project root, and when that module is requested the load hook returns readFile(<attacker path>) as the module source. Exploitable without authentication through the public mockerPlugin.
Affects 2.1.0 through 4.1.11, and the 5 beta line up to 5.0.0-rc.2. One more case of development tooling listening more widely than you assumed — the same theme we have been seeing all week.
xmldom : quatorze advisories, et la déduplication d'attributs est en O(M²)
Fourteen advisories against @xmldom/xmldom in one day, most at 8.7. The most representative: it builds each element's attribute collection by inserting one at a time into a NamedNodeMap, and every insertion performs a linear scan of all already-inserted attributes to enforce the DOM uniqueness rule. Parsing an element with M attributes costs 1 + 2 + … + M = O(M²).
What makes it worse: the payload is perfectly well-formed XML. There is nothing malformed to detect — it is «one element with many attributes». No schema validation saves you.
The rest of the batch is a parade of requireWellFormed bypasses — via embedded line terminators in element, attribute, DocType, and publicId/systemId names, plus injection through createElement() and setAttribute() — and several more ReDoS. Fixed in 0.8.15 and 0.9.12. The legacy xmldom package (<= 0.6.0) has no fix: migrate.
Gitea : RCE en installant un git hook via l'endpoint diffpatch
Critical. The diffpatch endpoint can be abused to install and execute a git hook from repository-controlled content. An attacker with ordinary write access runs arbitrary shell commands as the OS user Gitea runs under.
And here is what turns this into an emergency: with default open registration, an unauthenticated visitor obtains the required write access by simply registering an account and creating a repository. Anonymous to RCE in two trivial steps. Fixed in 1.27.1.
If you run self-hosted Gitea with open registration, close it or upgrade right now.
Netty : un ClientHello fragmenté contourne votre mTLS par SNI (CVSS 9.1)
Critical, 9.1. A TLS ClientHello whose handshake header spans multiple records makes Netty silently fall back to the default SslContext. Where per-SNI selection is the sole mTLS gate, an unauthenticated attacker bypasses the route's mTLS requirement.
The cause is textbook: in SslClientHelloHandler#decode, the guard that should wait for the 4-byte handshake header checks the wrong offset — it ignores the 5-byte record header preceding it — and therefore never fires. An off-by-five in protocol parsing, and your mutual authentication is gone.
Fixed in 4.2.17.Final and 4.1.137.Final. It ships alongside a second advisory for quadratic pre-handshake reassembly in default SNI parsing.
GitPython : une valeur dormante de git-config se réveille en directive vivante
Critical, 9.3, and the mechanism is one of the prettiest I have seen this year. Dormant multi-line values in a git-config are corrupted into live injected directives — for example core.hooksPath — on any unrelated GitConfigParser write. The value was inert, you write something completely different to the config, and the read-write round trip activates it. From there, RCE.
It is a read-then-corrupt-on-rewrite, not an injection through a setter argument. Which is why it slips past any review that only inspects API calls. Fixed in 3.1.59.
Four more GitPython advisories landed the same day: clone_from() omitting --separate-git-dir from unsafe options, an incomplete denylist enabling arbitrary file read via Repo.blame(), and file disclosure through an [include] directive in an untrusted .gitmodules.
Le jour où la moitié de l'écosystème s'est révélée quadratique
Count the September 8 batch: xmldom (O(M²) attribute dedup, PI ReDoS, quadratic recovery parsing, quadratic memory), Nodemailer (O(n²) addressparser), Tiptap (quadratic ReDoS in Markdown attribute parsing), Netty (quadratic pre-handshake reassembly), HTTPX2 (quadratic SSE buffering), Colord (slow rejection of malformed strings), NLTK (three separate ReDoS), and this LiquidJS one: the join filter lets template authors bypass memoryLimit and crash the process.
This is not coincidence, it is a bug class we are systematically failing to test. And it has a recognizable signature: the input is valid. Well-formed, within size limits, passes any schema validation. What makes it toxic is not the content but the shape — nesting depth, attribute count, number of elements in a list.
The practical conclusion: your limits count bytes, and the real cost is almost never in the bytes. A request size limit does not protect you from a small, deeply nested document. When you write a parser, measure cost as a function of the input's shape, not its weight — and put an explicit bound on that dimension.
Node.js 24.21.0 : OpenSSL 3.5.8, nouveaux certificats racine et BlockList plus rapide
A crypto-heavy release: OpenSSL moves to 3.5.8, root certificates update to NSS 3.126, and Undici goes to 7.29.1. New as a minor, support for loading private keys through OpenSSL STORE loaders — useful when your keys live in an HSM or an external provider rather than the filesystem.
On performance: an improved histogram implementation and a faster net.BlockList. If you use BlockList for IP filtering on the hot path, that is a free upgrade.
workerd v1.20260909.1 tient la cadence quotidienne
Another daily Workers runtime release. On a day when the rest of the ecosystem published 99 advisories, Cloudflare's predictable cadence is almost a relief. Read the accumulated changelog if you track compatibility flags.
Astro 7.3.2 : les valeurs dynamiques dans script et style MDX sont échappées
Alongside the AVIF patch, Astro fixes <script> and <style> rendering in MDX: only literal content is now treated as trusted markup (including content injected by remark/rehype plugins). A dynamic value passed as a child — <script>{value}</script> — is escaped like any other element's content instead of rendered raw. To get the old behavior you must now opt in explicitly with set:html.
That is the right call: the default becomes safe and the exception becomes explicit. Watch out if you had legitimate dynamic content there — your render will change and you have to mark it by hand.
pnpm 12.4.0 maintient le rythme de la ligne Rust
A new minor on the native 12 line, days after 12.3.x. The release rhythm since the Rust rewrite is noticeably higher — good for fixes, but keep an eye on accumulated breaking changes if you are coming from the 11 line.
Tendances Notables
La chaîne du jour est un cours magistral sur les dépendances transitives : <strong>un bug dans libheif — du C, en amont, probablement inconnu dans votre arbre — remonte via sharp et ressort en RCE non authentifiée à CVSS 9.5 dans Next.js et en critique dans Astro</strong>. Observez le score changer en chemin : 8,9 chez sharp, 9,5 chez Next.js. Même bug ; ce qui change, c'est <strong>la surface internet que chaque couche ajoute</strong>. Votre analyse de risque ne peut s'arrêter au <code>package.json</code> direct.
99 advisories en un seul jour, avec des paquets entiers tombant par lots : xmldom 14, NLTK 16, GitPython 5, HTTPX2 5, Nodemailer 4, multer 4, Hono 3. Ce motif n'est pas «tout a cassé le même mardi» — c'est un <strong>audit systématique, un paquet à la fois</strong>, très probablement assisté par outils. Conséquence pratique : <strong>quand vous voyez un advisory pour une librairie que vous utilisez, cherchez ses frères du même jour avant de patcher</strong>. Corriger le CVE qui vous est parvenu en laissant les trois autres est pire que l'ignorance, car cela donne le sentiment d'être couvert.
Trois bugs du jour partagent une racine conceptuelle : <strong>un contrôle qui hérite du défaut de ce qu'il contrôle</strong>. Dans Hono, la vérification que <code>toSSG()</code> n'écrit pas hors de l'output normalise le chemin <em>avec la routine qui l'a construit</em>. Dans Netty, le guard attendant l'en-tête de handshake regarde le mauvais offset et ne se déclenche jamais. Dans GitPython, le parser de config lit une valeur inerte et la réécrit activée. Dans les trois, <strong>le contrôle existait, écrit avec la même logique que l'erreur qu'il devait attraper</strong>. Si votre validation partage du code avec votre construction, ce n'est pas une validation — c'est la même affirmation énoncée deux fois.