Vulnerability GHSA-jmv2-qgxf-f995
Summary
Astro: Reflected XSS via unescaped slot names in @astrojs/solid-js
Details
Summary
The @astrojs/solid-js renderer wraps named slot content passed to Solid components in an <astro-slot> element, and writes the slot name into its name attribute without HTML escaping. A slot name containing " could end the attribute and inject arbitrary HTML into the page.
For example, a page that takes a slot name from the request:
<Tabs client:load active={tab}><div slot={tab}>…</div></Tabs>
rendered with a Solid component that renders a slot by name:
export default function Tabs(props) {
return <div>{props[props.active]}</div>;
}
would output a tab value such as x"><img src=x onerror=alert(1)> as live HTML.
Impact
Reflected cross-site scripting. An attacker who gets a user to open a crafted link can run JavaScript on the site's origin, but only in applications where all of the following are true:
- The page passes request-controlled input (such as a query parameter) as a slot name.
- The Solid component is hydrated with a
client:*directive. For non-hydrated components the slot wrapper is removed from the output, together with itsnameattribute. - The Solid component renders the attacker-chosen slot, which in practice means accessing slot props by a dynamic name. Components that never render the slot only output Astro's already escaped fallback template.
This is the @astrojs/solid-js counterpart of GHSA-8hv8-536x-4wqp (CVE-2026-50146), which fixed the same issue in astro core.
Affected versions
@astrojs/solid-js >= 0.2.0, <= 7.1.1.
Patches
Fixed in @astrojs/solid-js 7.1.2. Slot names are now HTML-escaped in the server renderer.
Workarounds
Upgrade to @astrojs/solid-js 7.1.2 or later. Before upgrading, do not use request-controlled input as a slot name, or map it to a fixed set of known slot names before passing it to a component.
Credits
Reported by @manus-pi.