Newsletter #017: Rest, Bologna, and the Week Everyone Patched Everything ๐Ÿงฏ

Written by Ulises Gascรณn

Oct 25, 2026 โ€” 31 min read

This post was originally shared with my GitHub Sponsors. If you'd like to get early access to updates like this and support my open source work, consider becoming a sponsor here. ๐Ÿ™Œ


Hola everyone! ๐ŸŽ‰

Hope you've all been doing awesome since our last catch-up. This issue starts quietly, with the OpenJS CNA taking a coordinated break and three days in Bologna without a pager, and ends with a rough week for the whole web: a certificate authority with recoverable keys, two nicknamed RCEs, and a lot of people patching everything at once. In between, 78 CVEs, 17 releases, and the humans behind them.

This one is long. Grab a coffee, jump to whatever interests you, and skip the CVE and release lists with a clear conscience, they are collapsed for a reason ๐Ÿค“

Let's dive in! โœจ

๐Ÿ๏ธ We Took a Break. The CVE Flood Did Not.

From 17 September to 6 October the OpenJS Foundation CNA paused all security operations, following the example curl set with its Summer of Bliss, and we invited other projects to do the same. Express joined publicly. We kept an eye on the channels in case of an emergency. None came. Reports were slightly below the usual volume, and we did not reserve or publish a single CVE in those three weeks.

That matters more than it sounds. Most of the security triage and patching in the JavaScript ecosystem is done by unpaid volunteers, and we wanted to send a clear signal: taking a break is fine, and maintainers owe you nothing. This first break was the exercise that lets us sustain the effort long term, and we will most likely coordinate another one around the end of the year.

The numbers did not take a break. Since January the CNA has been hitting records on published CVEs, and September was no exception: 34 CVEs published, our highest month so far, and that was with the CNA closed from the 17th.

Monthly CVEs published by the OpenJS Foundation CNA

The pressure is everywhere, not just on us. According to CVE.ICU, 86,430 CVEs were published through 25 October, up 123.3% on the same date last year, and on pace for about 106,000: the first time the program crosses 100,000 in a single year.

CVEs published in 2026 per CVE.ICU

The same site also ranks CNAs by volume: the OpenJS CNA has published 146 CVEs this year, against three in all of 2025, more than the CNAs run by Intel, Siemens, AMD or Google Cloud. Counts say nothing about severity or quality, but they do show where vulnerability management work is happening.

CVE.ICU leaderboard of CNAs by CVEs published in 2026, with the OpenJS Foundation above Intel, Siemens and AMD

That 146 is also an undercount. Every Foundation project is in scope for the OpenJS CNA, but not all of them issue their CVEs through it yet, Node.js and Electron among them. What is new is who else is on that list. The first CNAs were large vendors such as Microsoft and Red Hat, and for almost two decades the ranking was theirs. Community-run CNAs now sit among them, which says less about the ranking than about how much of every digital product rests on open source today.

๐Ÿ‡ฎ๐Ÿ‡น Bologna, Without the Pager

The best thing the CNA break gave me was three days in a room full of people without a triage queue in my pocket. NodeConf EU 2026 ran on 29 and 30 September in Bologna, with the Node.js Collaborator Summit on 1 October in the same hotel. Somewhere in this photo there is a very rested maintainer ๐Ÿ˜

NodeConf EU 2026 group photo in Bologna Photo by Nico Kaiser for NodeConf EU

I actually sat through talks this time, start to finish, and the playlist is already up if you missed it. The conversations in between were about the future of Node.js and Express, and yes, security came up, but mostly in the form of Rafael Gonzaga's summit session on improving security report triage: persistent case history and read-only HackerOne access so triagers stop rebuilding context on every report, with humans keeping every decision.

I was there with Rafael and Adriรกn Estrada, which for a NodeSource team spread across continents is an event in itself.

Rafael Gonzaga, Ulises Gascรณn and Adriรกn Estrada at NodeConf EU 2026

And Wes Todd, who besides everything he does for Express is a master potter, brought me two handmade mugs with the Express logo pressed into the clay. In daily use, with extra care ๐Ÿ˜Š It is not every day you get pieces of art like these.

Ulises Gascรณn and Wes Todd holding handmade Express mugs

I even met the Fastify team in person and we did not talk about a single CVE. It was the best event I have been to in years. Thank you to the OpenJS friends and supporters, the organizers, the sponsors and everyone who came. I came home recharged, and with a to-do list that reaches the moon, most of it born in those conversations in between.

๐Ÿ”ฅ Upgrade, and Keep Upgrading

The week of 20 October was a rough one for the whole web. Two critical unauthenticated RCEs in PHP, nicknamed php2shell. A certificate authority, eMudhra, whose eight intermediate keys anyone could recover from the certificates themselves. A Brotli decoder bug in Node.js that the industry promptly named node2shell. A CVSS 10 in GitLab reaching back to 2014, a poisoned LiteLLM release. Everyone was patching everything at the same time. Here is what two of those fixes looked like from inside Node.js.

eMudhra. The three Node.js releases of 21 October, 26.12.1, 24.22.1 and 22.23.4, carry an updated CA bundle with two emSign roots removed (emSign is eMudhra's CA brand), and for many deployments that is the end of it. Not for all: Node.js can also be told to trust the operating system's certificate store, or extra certificates of your own, and those may still contain the roots. So I wrote the patch that makes Node.js reject any TLS chain containing one of the eight compromised public keys, whatever trust store is in use, ported from Electron and matching what Go, Chrome and Firefox already ship. Blocking by public key also stops reissued certificates. If you want to know whether your own store still trusts them, I published a script that answers in a minute, in a throwaway container, with public data only. Seth Larson documented the same problem for Python in Documenting certificate distribution pain points, and most of it applies to Node.js too.

node2shell. The Brotli RCE, CVE-2026-111497, was reported by OpenAI Codex Security and fixed in Node.js by Matteo Collina and Antoine du Hamel. It shipped in those same releases, together with nine more Node.js CVEs, two of them TLS hostname bypasses fixed by James Snell, and the undici 8.12.2 bump, which closes eight more CVEs that the undici team and I had patched in the weeks before. Patch the Planet named the people who coordinated the response across Node.js, Bun, Envoy and Istio, and I am honored to be on that list, mostly for backstage work: the initial risk assessment and coordination from the OpenJS side. If you run Node.js, those three versions are where you want to be, and check where else you pin undici.

Why there was capacity to respond. The Alpha-Omega grant, run as a partnership between the OpenJS Foundation and NodeSource, funds my time as Node.js Security Engineer in Residence, and companies like Orbitant and the individuals who sponsor me directly cover the rest of my open source work. That is what makes it possible to drop everything the day a certificate authority breaks.

PHP is in the same boat. The PHP team shipped fixes for two critical RCEs across four release lines in a single coordinated release, and went further than they had to with source backports for three end-of-life versions. They did it while the CVE IDs were circulating a day early, which forced the release forward, and while a researcher's proof-of-concept video and leaked mitigation notes were making the rounds. Then, six hours before the coordinated release, one distributor unilaterally published built images containing the fix, effectively breaking the embargo. Every distributor had the patch in advance under that embargo, and publishing it early gave attackers the fix to study while everyone else was still waiting, throwing away weeks of coordination by many parties. The PHP Foundation's write-up is worth your time for its honesty: the root cause had been known for a while, the fix stalled on hard trade-offs with too few engineers who know the engine, and they say so, together with what they changed. If you run PHP, that ask is for you.

๐Ÿ“ฆ Release Backlog Updates

I cut 17 releases across eight packages this period, 14 of them with security fixes. Four of them ship new features, so here they are first. The full list follows.

Express 5.3.0 closes five CVEs and adds QUERY revalidation

Beyond bumping qs, body-parser and proxy-addr to close five CVEs, this release (notes) adds three things: QUERY requests support conditional revalidation through req.fresh, content-type@2 makes Content-Type parsing in res.send() about 1.5x faster, and the default error handler logs the full error object, Error.cause included. Almost every change started as a community PR, some of them open for a long time. Thank you to everyone who kept pushing them.

// QUERY /reports with If-None-Match: "12345"
app.query('/reports', (req, res) => {
  res.set('ETag', '"12345"')
  res.send(results) // now responds 304 Not Modified
})

Multer 2.4.0 finally works on Google Cloud Functions and Firebase

Those platforms pre-read the request body, so the classic req.pipe(busboy) never saw it. The new streamHandler option (notes) lets you hand Multer the body they already read. The release also accepts a function for limits, exposes the busboy defCharset, highWaterMark and fileHwm options, allows diskStorage() without options, adds an fsync flush option for disk storage, and includes the filename in file errors.

const multer = require('multer')

const upload = multer({
  storage: multer.memoryStorage(),
  streamHandler: (req, busboy) => {
    // Cloud Functions / Firebase expose the pre-read body here
    if (req.rawBody) busboy.end(req.rawBody)
    else req.pipe(busboy)
  }
})

app.post('/upload', upload.single('file'), (req, res) => {
  res.json({ name: req.file.originalname, size: req.file.size })
})

hbs 4.4.0 lets you lock down Handlebars per instance

compileOptions and runtimeOptions (notes) forward options to handlebars.compile() and to the compiled template for every view and layout. With runtimeOptions you can disable prototype method and property access in templates, the safer setting for untrusted data. The release also bumps the bundled handlebars to 4.7.10 for CVE-2026-106445, fails with a clear error when a settings key in render data shadows the Express one, and documents layouts, template inheritance and the security defaults.

const hbs = require('hbs').create(null, {
  compileOptions: { strict: true },
  runtimeOptions: {
    allowProtoMethodsByDefault: false,
    allowProtoPropertiesByDefault: false
  }
})

app.engine('hbs', hbs.__express)

on-finished 2.4.2, the first release since 2022

A small package with a huge footprint, released for the first time in four years (notes). isFinished(res) now reads writableEnded instead of the deprecated finished property (DEP0136), with a fallback for older Node.js versions. Nothing changes for consumers.

๐Ÿ“ฆ Expand the full release list๐Ÿ“ฆ Collapse the release list

๐Ÿ” Security Updates

I was involved in 78 CVEs across the JavaScript ecosystem this period, in different capacities, from triage and patches to advisory operations. undici accounts for 20 of them and fast-uri for 12, and the standout is a critical Lambda event-spoofing bypass in @fastify/aws-lambda. Rather than walk through all 78, here are the ones that sit where your app decides whom to trust, grouped by what they undermine. If you depend on any of these packages, patch them first. The full list is further down.

  • Trusted client IP: CVE-2026-90711 in proxy-addr and its twin CVE-2026-92395 in @fastify/proxy-addr are both critical. A trust subnet written as an IPv4-mapped IPv6 address, like ::ffff:10.0.0.0/8, ends up trusting every client, so req.ip and req.ips become attacker-controlled and any IP-based access control, rate limiting or audit logging built on them goes with it. In the same family, CVE-2026-16732 in fastify lets X-Forwarded-* headers be spoofed under a numeric trustProxy hop count.
  • Composed auth rules: CVE-2026-92087 in @fastify/auth makes an AND group inside an OR relation order-dependent, so a check like (isApp && hasValidToken) OR (isUser && hasValidToken) can pass when it should not.
  • Middleware scoping: CVE-2026-85184 and CVE-2026-112712 in @fastify/middie, both critical, let a request skip path-scoped middleware, which is where authentication usually lives.
  • Serverless: CVE-2026-18248 in @fastify/aws-lambda lets a client forge the whole Lambda proxy event through a header, authorizer claims included.
  • Token verification: CVE-2026-18500 in @fastify/jwt lets the global secret silently override a per-request verification key, so a token signed for one key is accepted under another.
  • Route guards: CVE-2026-76169 in fastify itself sends a malformed URL to a sibling plugin's not-found handler without running its preHandler hooks, which is where auth checks usually sit.
  • TLS on the client side: CVE-2026-84961 and CVE-2026-109383 in undici drop a function-valued checkServerIdentity during an options deep-clone, so a custom hostname check never runs. And CVE-2026-107318 in @fastify/reply-from ships HTTPS transports with rejectUnauthorized set to false, so an on-path attacker can impersonate the upstream.
๐Ÿ” Expand the full list of 78 CVEs๐Ÿ” Collapse the CVE list

undici

  • CVE-2026-85152 โ€” High-severity. Cross-origin cache poisoning and authentication bypass when the cache or dedupe interceptor is composed directly on a Client or Pool, because the origin is dropped from the cache key (GHSA-vp8m-p9jh-q5pm)
  • CVE-2026-84961 โ€” High-severity. TLS certificate validation bypass in BalancedPool, which JSON-clones its options and silently drops a function-valued checkServerIdentity or custom connector (GHSA-w293-vg96-wgc3)
  • CVE-2026-109383 โ€” High-severity. TLS certificate validation bypass in Agent, whose JSON deep-clone drops a caller-supplied checkServerIdentity before it reaches the TLS layer (GHSA-2m5v-pch6-74hx)
  • CVE-2026-109829 โ€” High-severity. Cache poisoning and cross-user disclosure when a cross-origin redirect response is cached under the original request URL (GHSA-4w7w-5xrc-9h26)
  • CVE-2026-19534 โ€” High-severity. Process crash during the WebSocket handshake when a server returns a Sec-WebSocket-Protocol the client never requested (GHSA-rfgv-xxqx-mfg5)
  • CVE-2026-109855 โ€” High-severity. WebSocket client crash on a failed HTTP/2 handshake, which leaves an orphaned stream that throws when the server disconnects (GHSA-qq8j-7v2v-3rwp)
  • CVE-2026-109869 โ€” High-severity. Process crash when a server returns more than five Content-Encoding layers and closes early, surfacing an unhandled error on an orphaned stream (GHSA-xjj6-f33q-929c)
  • CVE-2026-87018 โ€” High-severity. Process crash via a TLS 1.2 renegotiation that presents a different CA-trusted certificate whose hostname does not match (GHSA-qrxm-fqhp-jwvm)
  • CVE-2026-18149 โ€” Medium-severity. The retry handler can leave an already-exposed response body pending forever, accumulating hung promises and streams (GHSA-pmjh-fq2x-6v4x)
  • CVE-2026-84890 โ€” Medium-severity. The decompress interceptor imposes no output-size bound, so a small compression bomb can expand to exhaust client memory (GHSA-3xpg-4rpp-hhhm)
  • CVE-2026-84933 โ€” Medium-severity. A shared cache stores Set-Cookie responses and re-serves one caller's cookie to another (GHSA-2jfj-6hjv-fm6j)
  • CVE-2026-85014 โ€” Medium-severity. WebSocketStream crash when a peer closes the TCP connection without a WebSocket close handshake (GHSA-rx4f-c7p8-82vq)
  • CVE-2026-85024 โ€” Medium-severity. WebSocket permessage-deflate crash on a malformed DEFLATE byte past the 128 MiB limit, after the error listener was removed (GHSA-3wwx-pv8p-q78v)
  • CVE-2026-109841 โ€” Medium-severity. Subresource Integrity bypass when a pinned digest uses a non-lowercase algorithm token, which fetch() skips as unknown (GHSA-f72v-6w45-q472)
  • CVE-2026-109924 โ€” Medium-severity. EventSource parser memory exhaustion from many tiny fields or an unfinished line, unbounded by the byte-size limits (GHSA-4qv8-2p9j-2685)
  • CVE-2026-109932 โ€” Medium-severity. Unbounded automatic PONG buffering lets a server flooding small PING frames grow the outbound queue until memory runs out (GHSA-9fm3-97px-rjf6)
  • CVE-2026-87029 โ€” Medium-severity. decompress interceptor crash when a downstream handler throws asynchronously from a zlib callback (GHSA-55wc-3pg8-jfw6)
  • CVE-2026-18540 โ€” Low-severity. The retry interceptor can append a resumed range body past the forwarded Content-Length, enabling downstream response splitting (GHSA-r53p-7pc4-xj5r)
  • CVE-2026-84947 โ€” Low-severity. The dump interceptor truncates oversized chunked responses and tears down the connection while reporting success (GHSA-2gqq-gqf2-x968)
  • CVE-2026-85008 โ€” Low-severity. The cache interceptor caches and replays responses to unsafe HTTP methods such as POST, PUT, and DELETE (GHSA-8436-99hf-9mmv)

fast-uri

  • CVE-2026-75899 โ€” High-severity. Server-side request forgery via double percent-decoding of the hostname, which can resolve to a loopback target (GHSA-fph4-wmhf-6fwf)
  • CVE-2026-75931 โ€” High-severity. Host confusion because IDN canonicalization is skipped on scheme-relative references, so parse and resolve disagree on the host (GHSA-5jgf-p345-68v8)
  • CVE-2026-75975 โ€” High-severity. Server-side request forgery via malformed IPv6 normalization that collapses a bad literal to a loopback or private address (GHSA-f65p-4m7j-42xc)
  • CVE-2026-76172 โ€” High-severity. Host confusion via percent-encoded scheme normalization that emits an attacker-chosen authority (GHSA-jqff-g426-hqxp)
  • CVE-2026-84292 โ€” High-severity. Authority injection via an unvalidated port in serialize, which demotes the intended host to userinfo (GHSA-qw65-cvwx-89v3)
  • CVE-2026-84394 โ€” High-severity. Host confusion via an unclosed authority bracket, returned as the host with no error while HTTP clients resolve a different host (GHSA-58mr-gqgx-xq4g)
  • CVE-2026-86472 โ€” Medium-severity. Inconsistent host case normalization via a percent-encoded uppercase octet on a scheme-relative reference (GHSA-hrr3-gc8f-f4qj)
  • CVE-2026-86818 โ€” Medium-severity. mailto header injection via percent-encoded field names that desynchronize parse and serialize (GHSA-jvvf-x445-j334)
  • CVE-2026-110180 โ€” Medium-severity. Host confusion via unchecked WHATWG host canonicalization that silently rewrites the authority (GHSA-wjr9-j795-jxcr)
  • CVE-2026-110306 โ€” Medium-severity. Scheme spoofing via percent-encoded scheme decoding, turning an inert string into a live javascript: or data: URL (GHSA-w74x-v6f9-j3xg)
  • CVE-2026-110095 โ€” Low-severity. Improper path equivalence when dot-segment removal is applied to a relative reference, dropping a leading parent segment (GHSA-xhq7-xmqj-769h)
  • CVE-2026-110725 โ€” Low-severity. Scheme injection via an unescaped first-segment colon under the non-default suffix reference option (GHSA-333x-w4r6-6crp)

fastify

  • CVE-2026-76169 โ€” High-severity. Authentication bypass when a malformed URL reaches a sibling plugin's not-found handler without its preHandler hook (GHSA-p68q-wchp-6fh7)
  • CVE-2026-84428 โ€” High-severity. Header validation bypass because schema case-normalization skips the JSON Schema dependencies keyword (GHSA-9q9j-q6p8-xq58)
  • CVE-2026-84469 โ€” High-severity. Request validation bypass because a boolean false deny-all schema is treated as missing and never compiled (GHSA-hwr6-493r-vm6h)
  • CVE-2026-84504 โ€” High-severity. Request body replacement when a validated body carries a root value property that collides with the async-validation result protocol (GHSA-667r-xxjv-c9mm)
  • CVE-2026-16732 โ€” Medium-severity. X-Forwarded-* spoofing under a numeric trustProxy hop count, a form the CVE-2026-3635 guard did not cover (GHSA-3m5p-2c4r-xxw2)
  • CVE-2026-18504 โ€” Medium-severity. Schema validation bypass when a root primitive is coerced by Ajv but the request body is not replaced with the coerced value (GHSA-w2qp-rph6-63g4)
  • CVE-2026-92081 โ€” Medium-severity. HTTP/2 trailer responses crash the server because Transfer-Encoding: chunked is set unconditionally (GHSA-4mh8-r7rc-xpvc)
  • CVE-2026-107832 โ€” Low-severity. Header validation bypass because case-sensitive propertyNames enum or const header names are not lowercased (GHSA-389g-gv7q-r4x8)

multer

@fastify/busboy

@fastify/jwt

@fastify/middie

  • CVE-2026-85184 โ€” Critical-severity. Path-scoped middleware (authentication, authorization) is bypassed via an absolute-form request target that the router resolves differently (GHSA-hx87-8wv7-pjv8)
  • CVE-2026-112712 โ€” Critical-severity. Path-scoped middleware is bypassed via a scope-prefix mismatch, most often a trailing slash (GHSA-5p92-8765-9fv8)

@fastify/multipart

@fastify/oauth2

@fastify/static

webpack-dev-server

  • CVE-2026-112085 โ€” High-severity. Cross-origin WebSocket access through proxied upgrades that skip the Host and Origin validation allowedHosts applies to the HMR socket (GHSA-cfqc-fj3v-j925)
  • CVE-2026-114348 โ€” Medium-severity. Information disclosure via a Host validation bypass in the open-editor endpoint that leaks a full stack trace (GHSA-wqhc-fvfg-56q6)

morgan

  • CVE-2026-15603 โ€” Medium-severity. Log forging via unescaped Unicode line separators, a follow-up to CVE-2026-5078 which covered only ASCII controls (GHSA-jxfw-x594-9x9m)
  • CVE-2026-87859 โ€” Medium-severity. Log injection via an unescaped double quote that closes a quoted field of the Apache combined log format early (GHSA-9f6g-j8ch-79g4)

hbs

  • CVE-2026-16231 โ€” High-severity. Cross-site scripting because registerAsyncHelper output is substituted into the page without HTML escaping (GHSA-rg36-rxv9-2m9q)
  • CVE-2026-87123 โ€” Medium-severity. Process crash when an async helper resolves to an object with a truthy but non-callable toHTML, introduced by the escaping fix above (GHSA-3c55-w9jx-p5jr)

@fastify/aws-lambda

  • CVE-2026-18248 โ€” Critical-severity. Full authentication bypass and privilege escalation because the client-controlled x-apigateway-event header forges the Lambda proxy event, including authorizer claims (GHSA-m93c-jj3f-68ph)

@fastify/proxy-addr

  • CVE-2026-92395 โ€” Critical-severity. IP spoofing via an IPv4-mapped IPv6 trust subnet with an IPv4-sized prefix, inherited from proxy-addr (GHSA-8cmm-mhw6-v7xq)

proxy-addr

  • CVE-2026-90711 โ€” Critical-severity. IP spoofing via an IPv4-mapped IPv6 trust subnet with an IPv4-sized prefix (for example ::ffff:10.0.0.0/8), which trusts every IPv4 address and defeats req.ip-based access control (GHSA-jqcg-44mw-7w3h)

@fastify/auth

  • CVE-2026-92087 โ€” High-severity. Authorization bypass via order-dependent evaluation of a composed AND group under the relation: 'or' and run: 'all' options (GHSA-7h52-2rwr-m76r)

@fastify/http-proxy

  • CVE-2026-85124 โ€” High-severity. Prefix escape via backslash dot-segments on the plain HTTP path, which skips the destination validation the WebSocket path performs (GHSA-qv33-689p-2xq5)

@fastify/reply-from

  • CVE-2026-107318 โ€” High-severity. Improper certificate validation because the built-in HTTPS transports set rejectUnauthorized to false, so an on-path attacker can impersonate the upstream (GHSA-j425-jw94-m29r)

fastify-cli

  • CVE-2026-75021 โ€” High-severity. Remote code execution because an explicit Inspector bind address is ignored and the debugger is bound to a broadly reachable address (GHSA-88v4-3ph7-r88m)

compression

  • CVE-2026-87776 โ€” High-severity. A client that aborts mid-response leaks the zlib stream, which is never destroyed, so repeated early disconnects exhaust memory (GHSA-vc2v-76pw-4v95)

multiparty

body-parser

  • CVE-2026-111181 โ€” High-severity. A request whose compressed body carries trailing bytes after one valid frame crashes the process when the error is re-thrown on an already-finished decoder. Because body parsing runs before routing, any endpoint is affected (GHSA-27r3-jxmh-p828)

cookies

moment

  • CVE-2026-17495 โ€” Medium-severity. Path traversal via a crafted non-string locale object that bypasses the string guard in moment.locale(), an incomplete fix of CVE-2022-24785 (GHSA-4p3w-j4w9-5jqw)

I wrote up the details on the Express blog for August and September, and everything the OpenJS Foundation CNA publishes is listed on the security advisories page.

When a CVE for your project arrives from the outside. On 24 August the webpack-dev-middleware maintainers found out that CVE-2026-76844 had been assigned and published for a path traversal in their package by a third-party CNA, with no notice to them and no fix available. They worked with the OpenJS CNA on the coordinated advisory and shipped 8.3.0 and 7.4.6. Then that same CNA overwrote the record with a zlib vulnerability by mistake, and as of today it still describes zlib. Only the CNA that owns a record can edit it, and getting one corrected or transferred now takes weeks. The volume is hitting the CVE program as hard as it hits maintainers. It is also the story we kept hearing at NodeConf EU and the Collaborator Summit from maintainers whose projects go through other CNAs: delays getting CVEs reserved and published, and learning about your own CVEs after someone else published them. Running your own CNA is a big effort for a community, but it means your maintainers are never alone when a CVE lands on them, and the records about your projects stay in hands that know them. That was the main driver when we decided to create the OpenJS CNA.

๐Ÿ“š What Else?

Legacy does not mean dormant. Moment announced its sunset in 2020, and weekly downloads have more than tripled since. The August status update confirms that coding agents learned on Moment and keep picking it, and a 3.0 is no longer ruled out. I started helping on the security side with a threat model to triage reports against the library's boundaries. [email protected] followed, the first release in almost three years. It patches CVE-2026-17495, so moment.locale() now guards against non-string locale objects and extends the original fix for CVE-2022-24785, and it ships a dozen bug fixes: prototype properties no longer work as format tokens or locale names, time zone offsets are range-checked, and two new locales land.

Express is getting tracing channels, and it took a question from the stage. At NodeConf EU, Abdelrahman Awad asked during Tracing Without the Tax whether any Express maintainer in the room could merge his tracing channel PR, open since April. Wes Todd answered: we want this, we lack hands.

Wes Todd answering from the audience at NodeConf EU 2026, with Express listed as "on the way" on the slide behind him Photo by Nico Kaiser for NodeConf EU

So we gave the work owners. Awad and Sebastiรกn Beltrรกn are now router committers, the PR is merged, and [email protected] is being consolidated with one tracing channel covering every middleware, route and error handler, plus TypeScript types and a listRoutes method.

2027 is almost here, and the Node.js release model changes with it. I shared the change with you when it was proposed and when it became official. One of the key talks at NodeConf EU was Rafael Gonzaga and Antoine du Hamel walking through it in The New Node.js Release Model, with Rafael's blog post for the details. One major per year in April, every major becomes LTS, and a six-month Alpha phase replaces the odd lines, starting with Node.js 27 in 2027, when the version number begins to match the year. If your upgrade policy says "LTS only", it will soon mean every release, and library authors should get Alpha into CI now. For the Spanish version, Estefany Aguilar gives the day 2 keynote at JSConf Mรฉxico on 30 October on exactly this.

Not every vulnerability needs an embargo. Keeping every report private until a coordinated release is a heavy workload for small teams, often unpaid volunteers, and it treats a low-risk bug the same as a critical one. With AI tools rediscovering the same issues within days, the OpenJS Foundation announced a โ‚ฌ115,000 investment from the Sovereign Tech Agency to find out which vulnerabilities can be fixed in the open. Node.js is the research environment and Rafael Gonzaga the research lead. The plan is to classify reports by risk, run a controlled pilot that fixes the eligible ones through normal development, and measure time from report to fix against the private process, with maintainers keeping the final call. curl has already moved: from 26 October, low and medium reports go to public GitHub issues and only high and critical stay private.

GitHub shipped the advisory changes maintainers asked for. The report flood did not only hit our inboxes, it hit the tooling. Over the past year, from the OpenJS Security Working Group and the Alpha-Omega Security Engineers in Residence, together with Seth Larson, Matteo Collina and Mirko Swillus, we kept sharing with GitHub what we needed: fewer low-effort reports, a way to slow down a single reporter, programmatic access to the advisory conversation so triage tooling could help, and CI running on private security forks. Madison Ficorilli and Camilla Moraes carried that into the roadmap, and the GitHub Advisories team shipped five changes: structured forms that require a proof of concept, rate limits per reporter with an allow list, a comments API, confidential comments for the team only, and new GraphQL fields. The forms alone drastically cut the LLM-generated walls of text we receive. It is unbelievable how much this has changed our day to day, many frictions are simply gone. Thank you all for prioritizing maintainer needs.

Behind every CVE there are humans, and most records do not say who. Chandan published a CVE Credits Leaderboard: the most credited names in 2026 records, by finder, reporter, remediation developer and reviewer. Only about 42% of the CVEs published this year credit anyone at all. Every uncredited record hides hours of finding, fixing and reviewing, and leaderboards like this one are how that work gets seen. So if you run a CNA, fill in the credits whenever you can. At the OpenJS CNA we automated it with CVE Kit, built by Chris de Almeida, which loads the GitHub advisory and carries its credits into the CVE record. And for a sense of the volume all those credits sit inside, Jerry Gamblin built the CVE Tornado, every CVE published per day, one turn per year.

The OpenJS CNA has a public API, and the website follows it. The CNA API we have been building since issue 15 is now documented for member projects at cna.openjsf.org/api: one token per project and environment, dispatch an operation such as reserving or updating a CVE, poll for the result. The stack migration is done and the CNA now pulls reserved and published CVEs straight from MITRE, with advisory references resolved, so CVEs transferred to us get indexed automatically. That also let us redesign the security advisories page from a table into cards, which works far better on a phone.

The OpenJS Foundation CNA security advisories page, now listing each CVE as a card with its advisory link, repository and publication date

Next step: we deploy the API to production and start the pilot with Node.js on its next security release.

Cafรฉ con CVEs episode 3 is out, the second half of the npm v12 question. Together with Estefany Aguilar we ask: does blocking install scripts make you safe? We walk through why npm v12 removes a trigger and not the capability, and what to do about it with the permission model, sandboxing and logging.

Estefany wrote the companion article on the NodeSource blog.

๐ŸŽ–๏ธ Awesome People Doing Awesome Things

Alfredo Gonzรกlez is now an hbs committer. He has been driving the hbs 5.0 tracker for a year, [email protected] is out, and the next major is the next stop.

Murat Kirazkaya proposed a recommended issue and PR structure for the Express organization. This is a great opportunity to rethink how we want to manage labels.

Stephen Augustus shipped OpenSSF Scorecard v5.6.0 and scorecard-action v2.5.0, the first release since the hosted scans and REST API moved to AboutCode Foundation infrastructure. If you run the Scorecard GitHub Action, upgrade now: older versions pull their image from GCR, which has been retired, so they will fail. Workflow checks also follow YAML aliases now, so reused unpinned actions may lower your Pinned-Dependencies score.

Christian Bromann shipped WebdriverIO v10, and the post is as good as the release. The framework is now built for verification loops, where a coding agent checks its own work in a real browser or device and leaves behind a plain test that reruns without a model. The verdict stays out of the model's hands.

Mirko Swillus wrote up the Alpha-Omega roundtable at OSS EU 2026, where Apache, Erlang, Maven Central, Perl, PHP, Rust, Scala, the Sovereign Tech Agency and others compared notes. Two things came out of it. A working group of ten people will define a shared vocabulary for which projects count as critical, so every ecosystem stops inventing its own. And "Bernies", abandoned projects that make up 10 to 20% of the dependency trees under critical infrastructure, get ecosystem-level councils to deal with the ones with the biggest blast radius, starting with replacement recommendations at the package manager level. As Mirko puts it, there is no glory in prevention, which is exactly why this work needs to be visible.

CodeRabbit became a webpack sponsor on Open Collective with a $200 monthly contribution, joining the dozen other projects they already back, from Storybook and Solid to changesets and e18e.

Wbert Adriรกn Castro is speaking at MedellinJS on 28 October: JEV y los modelos de decisiรณn: cuando la IA elige, on what decision models add over the classifiers we already had, where they differ from LLMs, and when they are the right tool. If you are in Medellรญn, go.

๐Ÿ”— Interesting Stuff

Some awesome reads from my network:

๐Ÿ™Œ Thank You!

As always, your support as a sponsor makes all of this possible ๐Ÿ’–

Whether you're contributing code, giving feedback, or just following along. Thank you!

Stay awesome, Ulises Gascรณn