fix(security): upgrade Astro 5 -> 6.4.8 to fix the two CVEs the allowlist was hiding - #27
Merged
Merged
Conversation
…list was hiding islam.wiki is public and was serving both of these while the audit gate reported clean, because .audit-allowlist.json carried them: GHSA-8hv8-536x-4wqp reflected XSS via unescaped slot name patched >=6.3.3 GHSA-2pvr-wf23-7pc7 host-header SSRF in prerendered error page patched >=6.4.6 They were the only high advisories left after e97e8bb. Now on astro 6.4.8, so both are fixed rather than suppressed, and all six allowlist entries (each CVE is keyed three ways: numeric id, GHSA id, advisory title) are gone. The allowlist is empty and the gate still passes. Dependency set mirrors the sibling chatislam upgrade (1463844): @astrojs/vercel 10, @sentry/astro 10, @astrojs/react 6, vite pinned >=7.3.5 <8 with a direct devDependency so @tailwindcss/vite's vite peer is satisfied from one copy. @astrojs/vercel v8 collapsed /serverless into the root export, so the adapter import drops the subpath. Astro 6 requires node >=22.12, so engines.node and the CI workflows still on node 20 move to 22 (ci.yml's matrix drops the 20 leg). The hard part was the prerender pass, which is what reverted this upgrade on the first attempt: prerendering static routes This module cannot be imported from a Client Component module. server-only/index.js:1:7 (Node CJS loader) lib/** guards every admin-secret module with `import 'server-only'`. That package resolves to a no-op empty.js ONLY under the `react-server` export condition; otherwise index.js throws on load. Astro 5 had one server Vite environment, so the existing vite.ssr.noExternal + ssr.resolve.conditions block covered the whole server build. Astro 6 splits it into TWO environments -- `ssr` and a separate `prerender` one (dist/server/.prerender/) -- and Vite backfills the top-level `ssr.*` shorthand into `ssr` alone. The prerender pass therefore ran on defaults, left server-only external, and Node's own resolver (no react-server condition) loaded the throwing index.js while generating pages. Astro's core/constants.ts says this outright: "If your plugin runs in ASTRO_VITE_ENVIRONMENT_NAMES.ssr, you might want to add ...prerender too." Declaring vite.environments.prerender.resolve does not work -- Astro's createViteBuildConfig() spreads the user `environments` and then reassigns environments.prerender wholesale to its own { build } object, dropping any sibling resolve. Verified: identical failure. So the fix is a small Vite plugin using the configEnvironment hook, which runs later in config resolution and gets merged in. It matches on environment NAME, not config.consumer -- consumer is still undefined when that hook fires. What was deliberately NOT done: aliasing server-only to an empty module. That would have made the build pass by deleting the guard on the only side it protects. The plugin touches the ssr/prerender/astro environments only and never `client`, so client resolution is byte-for-byte what it was on Astro 5. Verified by experiment rather than assumption: adding an import of lib/hasura-admin to SearchInput.tsx put the throwing index.js into dist/client/_astro/SearchInput.*.js. Worth recording that this is a load-time throw in the browser, not a build-time error -- the build stays green either way -- which is weaker than the old comment in astro.config.mjs claimed. The comment is corrected rather than left flattering. Verified locally: pnpm build ok, astro check 0 errors, 38 test files / 586 tests pass (unchanged), pnpm audit --audit-level=high reports 0 high and 0 critical (6 low, 13 moderate remain), 0 external server-only imports anywhere in dist/, no react.react-server variant pulled into the server bundle, and 7061 of 7383 prerendered pages still contain rendered astro-island markup.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
🟢 Rampart Security Gate — CLEAN
Totals: 0 critical · 0 high · 0 medium · 0 low Mode: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
islam.wiki is public and was serving both of these while the audit gate reported
clean, because .audit-allowlist.json carried them:
GHSA-8hv8-536x-4wqp reflected XSS via unescaped slot name patched >=6.3.3
GHSA-2pvr-wf23-7pc7 host-header SSRF in prerendered error page patched >=6.4.6
They were the only high advisories left after e97e8bb. Now on astro 6.4.8, so
both are fixed rather than suppressed, and all six allowlist entries (each CVE is
keyed three ways: numeric id, GHSA id, advisory title) are gone. The allowlist is
empty and the gate still passes.
Dependency set mirrors the sibling chatislam upgrade (1463844): @astrojs/vercel
10, @sentry/astro 10, @astrojs/react 6, vite pinned >=7.3.5 <8 with a direct
devDependency so @tailwindcss/vite's vite peer is satisfied from one copy.
@astrojs/vercel v8 collapsed /serverless into the root export, so the adapter
import drops the subpath. Astro 6 requires node >=22.12, so engines.node and the
CI workflows still on node 20 move to 22 (ci.yml's matrix drops the 20 leg).
The hard part was the prerender pass, which is what reverted this upgrade on the
first attempt:
lib/** guards every admin-secret module with
import 'server-only'. That packageresolves to a no-op empty.js ONLY under the
react-serverexport condition;otherwise index.js throws on load. Astro 5 had one server Vite environment, so
the existing vite.ssr.noExternal + ssr.resolve.conditions block covered the whole
server build. Astro 6 splits it into TWO environments --
ssrand a separateprerenderone (dist/server/.prerender/) -- and Vite backfills the top-levelssr.*shorthand intossralone. The prerender pass therefore ran on defaults,left server-only external, and Node's own resolver (no react-server condition)
loaded the throwing index.js while generating pages. Astro's core/constants.ts
says this outright: "If your plugin runs in ASTRO_VITE_ENVIRONMENT_NAMES.ssr, you
might want to add ...prerender too."
Declaring vite.environments.prerender.resolve does not work -- Astro's
createViteBuildConfig() spreads the user
environmentsand then reassignsenvironments.prerender wholesale to its own { build } object, dropping any
sibling resolve. Verified: identical failure. So the fix is a small Vite plugin
using the configEnvironment hook, which runs later in config resolution and gets
merged in. It matches on environment NAME, not config.consumer -- consumer is
still undefined when that hook fires.
What was deliberately NOT done: aliasing server-only to an empty module. That
would have made the build pass by deleting the guard on the only side it
protects. The plugin touches the ssr/prerender/astro environments only and never
client, so client resolution is byte-for-byte what it was on Astro 5. Verifiedby experiment rather than assumption: adding an import of lib/hasura-admin to
SearchInput.tsx put the throwing index.js into dist/client/_astro/SearchInput.*.js.
Worth recording that this is a load-time throw in the browser, not a build-time
error -- the build stays green either way -- which is weaker than the old comment
in astro.config.mjs claimed. The comment is corrected rather than left flattering.
Verified locally: pnpm build ok, astro check 0 errors, 38 test files / 586 tests
pass (unchanged), pnpm audit --audit-level=high reports 0 high and 0 critical
(6 low, 13 moderate remain), 0 external server-only imports anywhere in dist/,
no react.react-server variant pulled into the server bundle, and 7061 of 7383
prerendered pages still contain rendered astro-island markup.