Skip to content

fix(security): upgrade Astro 5 -> 6.4.8 to fix the two CVEs the allowlist was hiding - #27

Merged
acamarata merged 1 commit into
mainfrom
fix/astro6-upgrade
Sep 5, 2026
Merged

acamarata merged 1 commit into
mainfrom
fix/astro6-upgrade

Conversation

@acamarata

Copy link
Copy Markdown
Contributor

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.

…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.
@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
islamwiki Ready Ready Preview Sep 4, 2026 7:48pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
ummat-islamwiki Ignored Ignored Preview Sep 4, 2026 7:48pm UTC

Request Review

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

🟢 Rampart Security Gate — CLEAN

Tool CRITICAL HIGH MEDIUM LOW
(no findings)

Totals: 0 critical · 0 high · 0 medium · 0 low

Mode: RAMPART_ENFORCE=warn

@acamarata
acamarata merged commit f206003 into main Sep 5, 2026
16 of 19 checks passed
@acamarata
acamarata deleted the fix/astro6-upgrade branch September 5, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant