{"id":"CVE-2026-54299","aliases":["GHSA-2pvr-wf23-7pc7"],"url":"https://o3.security/vulnerability/CVE-2026-54299","summary":"Astro: Host-header full-read SSRF in core prerendered error-page fetch (prerenderedErrorPageFetch default + unvalidated createRequestFromNodeRequest URL)","details":"## Summary\n\nAstro SSR apps with prerendered error pages (`/404` or `/500` using `export const prerender = true`) fetch those pages over HTTP at runtime when an error occurs. The URL for this fetch is derived from `request.url`, which in turn gets its origin from the incoming `Host` header. When the `Host` header is not validated against `allowedDomains`, an attacker can point the fetch at an arbitrary host and read the response.\n\n## Who is affected\n\nThis affects SSR deployments that:\n\n1. Have a prerendered 404 or 500 page\n2. Use `createRequestFromNodeRequest` from `astro/app/node` with `app.render()` **without** overriding `prerenderedErrorPageFetch` — this includes custom servers built on the public API and third-party adapters\n\n**Not affected:**\n- `@astrojs/node` >= 9.5.4 (reads error pages from disk)\n- `@astrojs/cloudflare` (uses the ASSETS binding)\n- The dev server (renders error pages in-process)\n\n## How it works\n\n`createRequestFromNodeRequest` builds `request.url` from the raw `Host` / `:authority` header. The `allowedDomains` option is accepted but only gates `X-Forwarded-For` — it does not constrain the URL origin. (The public `createRequest` does fall back to `localhost` for unvalidated hosts; this internal builder did not.)\n\nWhen `app.render()` encounters a 404 or 500 with a prerendered error route, `default-handler.ts` constructs the error page URL using the origin from `request.url` and fetches it via `prerenderedErrorPageFetch`, which defaults to global `fetch`. The response body is served to the client.\n\nAn attacker sends a request with `Host: attacker-host:port`, triggers an error (e.g., requesting a nonexistent path for a 404), and receives the response from the attacker-controlled host reflected back.\n\n## Remediation\n\nThe error page fetch origin is now validated against `allowedDomains` before use. When the host is validated, the original origin is preserved. Otherwise, it falls back to `localhost`. The fetch is also wrapped in a try/catch so that connection failures degrade gracefully to a plain error response.\n\n## Credit\n\n5ud0 / Tarmo Technologies","published":"2026-06-22T17:33:53.235Z","modified":"2026-08-12T03:51:08.479862895Z","cvss":{"score":7.5,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:N"},"epss":{"score":0.00333,"percentile":0.25861,"asOf":"2026-09-01"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"astro","fixedVersion":"6.4.6"}],"fix":null,"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/54xxx/CVE-2026-54299.json"},{"type":"ADVISORY","url":"https://github.com/withastro/astro/security/advisories/GHSA-2pvr-wf23-7pc7"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54299"},{"type":"PACKAGE","url":"https://github.com/withastro/astro"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:08.479862895Z"}}