CVE-2026-126362: Astro: Reflected XSS via unescaped slot names in @astrojs/svelte

Published Nov 12, 2026
·
Updated

Summary

The @astrojs/svelte renderer wraps slotted content passed to Svelte 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:

astro --- import Tabs from '../components/Tabs.svelte'; const tab = Astro.url.searchParams.get('tab'); --- <Tabs client:load active={tab}><div slot={tab}>…</div></Tabs>

rendered with a Svelte 5 component that renders its snippets by name:

svelte <script> let { active, ...snippets } = $props(); </script> {@render snippets[active]?.()}

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 Svelte component is hydrated with a client: directive. For non-hydrated components the slot wrapper is removed from the output, together with its name attribute. - The Svelte component renders the attacker-chosen slot, which in practice means a Svelte 5 component that renders snippets by a dynamic name. Components that never render the slot only output Astro's already escaped fallback template.

This is the @astrojs/svelte counterpart of GHSA-8hv8-536x-4wqp (CVE-2026-50146), which fixed the same issue in astro core. The same unescaped value was also used when hydrating the component in the browser.

Affected versions

@astrojs/svelte >= 5.7.3, <= 9.1.1.

Patches

Fixed in @astrojs/svelte 9.1.2. Slot names are now HTML-escaped in the server renderer and in the client-side hydration code.

Workarounds

Upgrade to @astrojs/svelte 9.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.

Other sources

Astro is a web framework for content-driven websites. From 5.7.3 until 9.1.2, the @astrojs/svelte renderer inserted a named slot into the quoted name attribute of an astro-slot wrapper without HTML escaping. Request-controlled slot names containing a quote could terminate the attribute and inject active HTML. Exploitation required a hydrated Svelte component using a client: directive and dynamic rendering of the attacker-chosen slot; components that did not render that slot emitted only Astro's escaped fallback content. Both server rendering and client-side hydration used the unsafe slot name. This issue is fixed in version 9.1.2.

— MITRE

Affected Software

2 affected componentsFixes available
npm/@astrojs/svelte>=5.7.3<=9.1.1
9.1.2
npm/@astrojs/svelte>=5.7.3<9.1.2
9.1.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@astrojs/svelte to a version that resolves this vulnerability.

    Fixed in 9.1.2
  2. Upgrade

    Upgrade @astrojs/svelte to a version that resolves this vulnerability.

    Fixed in 9.1.2
  3. Configuration

    Do not use request-controlled input directly as a slot name; map it to a fixed set of known slot names before passing it to the component.

    @astrojs/svelte request-controlled slot names = disabled or mapped to a fixed set of known slot names

Event History

Nov 12, 2026
CVE Published
via MITRE·10:29 PM
Data Sourced
via MITRE·10:29 PM
DescriptionWeakness
Data Sourced
via OSV·10:29 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·10:34 PM
Data Sourced
via GitHub·10:34 PM
DescriptionWeaknessAffected Software
Data Sourced
via OSV·10:34 PM
Affected Software
Nov 13, 2026
Data Sourced
via NVD·12:20 AM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Which applications are actually exposed to this issue?

Exposure requires all of the following: request-controlled input is used as a slot name, that slot is passed to a Svelte component, and the component uses a client:* hydration directive. Non-hydrated components are not affected because the slot wrapper is removed from the output.

2

What does an attacker need to exploit it?

An attacker needs to control a slot-name value, such as through a query parameter, and persuade a victim to open a crafted link. A value containing a double quote can terminate the generated name attribute and inject HTML that executes JavaScript in the site's origin.

3

How can I check whether my application is vulnerable?

Review Astro pages that pass request-derived values into slot attributes, such as slot={Astro.url.searchParams.get(...)}. Confirm whether the receiving Svelte component is hydrated with client:* and renders the relevant named snippet.

4

What version contains the fix?

The referenced release identifies @astrojs/svelte@9.1.2. The advisory and linked commit provide the upstream fix details.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203