The version policy lost to a CVE
My rule is to run the latest stable minor that has been out three months. For Astro that points at 6.4.8, which carries an unpatched critical RCE. The rule and the security floor cannot both hold, so one of them gives.
Picking a version for a blog should take a minute. This one took an afternoon, because the house rule and the security floor pointed at different releases and I had to decide which one was actually load-bearing.
The rule: run the latest stable minor that has been out at least three months. It
buys the post-release point-fix wave — the X.Y.0 → X.Y.2 churn — without sitting on
something EOL. On 2026-09-16 that pointed at Astro 6.4.8. The 6.4 line opened
2026-05-28, comfortably past the window.
Then I checked the advisory database.
What the advisories say
Three, all on the same shape.
GHSA-26w7-cxv4-gfx2 — critical, remote code execution through AVIF image
optimization. Affected range < 7.2.8. First patched version 7.2.8.
That range swallows every 6.x release that exists. The fix was not backported. Two
others rhyme with it: CVE-2026-73422 (reflected XSS via View Transition animation
properties, <= 7.0.9, patched 7.1.0) and CVE-2026-84376 (authorization bypass,
<= 7.2.3, patched 7.2.4). Neither backported either.
Astro 7.0 shipped 2026-06-22. Every security fix since has landed on 7.x only. So 6.x isn’t merely older — it is unmaintained for security, and “three months old” and “no known vulnerabilities” have stopped being satisfiable at the same time.
The part I got wrong first
My first instinct was to take the newest release and move on. 7.3.3 is latest.
That’s the wrong read of my own rule. The rule exists to avoid being first to find a regression, and 7.3 opened 2026-09-03 and took three patches in its first five days. It is mid-wave. Jumping to it trades a known CVE for an unknown regression, which is not obviously a trade at all.
The rule, applied properly, says: take the oldest line that carries the fix. That’s 7.2. It opened 2026-08-06, has had eleven patches, and the last was 2026-08-31 — its wave is over.
So: 7.2.10. Latest patch on the oldest line that clears the critical.
"astro": "7.2.10",
Exact, not ^7.2.10. A caret here would silently walk me onto 7.3 the first time
someone ran a fresh install, which is the entire thing I just decided against.
Receipts
Resolved tree, Node 24.21.0:
$ npm audit --audit-level=high
found 0 vulnerabilities
That’s the number that matters, and it’s the resolved tree rather than the six direct
dependencies. Astro pulls Vite transitively and Vite has a long advisory history, so
auditing only what’s in package.json would be auditing the wrong thing.
The install is pinned by a committed package-lock.json and npm ci in CI — never
npm install. Without that the table of pins is aspirational; with it, it’s true at
build time.
I have not verified the AVIF exploit myself. I’m taking the advisory’s affected range at face value, which is the normal thing to do and worth saying out loud rather than implying I reproduced it.
What I’d do differently
Check the advisory database before applying the version rule, not after. I spent the
first half of this deciding on 6.4.8 using a process that could never have produced a
safe answer, because the input it needed wasn’t in front of me yet. The rule isn’t
wrong — it just isn’t the first step.
The revisit date is 2026-12-03, when 7.3 turns three months old, or whenever the next advisory forces it.