Skip to content
Security & Trust

Astro MDX and JSX bug let untrusted text run as code in script and style tags

A GitHub advisory says Astro's MDX and JSX rendering skipped escaping in two places. Here is what to ask your team.

W
WebPulse Newsroom
AI-assisted · 4 min read
Share on X LinkedIn
Astro MDX and JSX bug let untrusted text run as code in script and style tags
In brief
  • GitHub's advisory GHSA-98hj-9722-w3j8 (CVE-2026-114128) says Astro did not escape dynamic values placed inside script and style elements in MDX and astro:jsx rendering.
  • Sites were exposed only if attacker-controlled data, such as a query parameter or CMS field, reached those elements. The result could be reflected or stored cross-site scripting.
  • Check which Astro sites use MDX or astro:jsx, confirm the fixed version (the advisory links [email protected]), and review where dynamic values enter script or style tags.

A safety net with two gaps

Modern web frameworks make a quiet promise. Put untrusted text on a page, and the framework makes it harmless. Developers stop worrying about it, and that is the point.

A new advisory shows what happens when that promise has an exception that is easy to miss. The GitHub Advisory Database published GHSA-98hj-9722-w3j8 on October 22, 2026. It links to CVE-2026-114128 and covers the Astro web framework.

The lesson is simple. Automatic protection is only as strong as its exceptions. Teams that trust the default seldom go looking for them.

How the flaw worked

Escaping means converting characters such as angle brackets so the browser reads them as plain text, not as page code. According to the advisory, Astro's JSX and MDX rendering pipeline did this for dynamic values in most places. JSX is a way of writing page templates inside code. MDX is a format that mixes written content with those components.

Two places were different: the elements that hold scripts and styles. Any string placed inside them was labelled safe HTML, so no escaping was applied.

Here is why that matters. A script element ends at the first closing tag the browser meets. Suppose a value starts with a closing script tag and then opens a new script block. The advisory shows this case. Placed inside a script element in a template, the value reached the page unchanged. The browser ended the original element at that first tag and ran what came after.

The advisory points to the cause. The affected code paths treated all string children of these elements as safe. They did not separate literal content produced by the compiler from dynamic values. The first kind has to stay raw. The second should be escaped like any other value.

The scope is narrow. The gap appeared only when Astro drew these two elements with its astro:jsx renderer, which MDX components also go through. Dynamic strings in other JSX settings were escaped as usual.

What an attacker could do

A site was open to attack only under one condition. Data controlled by an outsider had to be written straight into one of those elements. The advisory names a query parameter and a CMS field as examples.

That distinction shows who holds the risk. A query parameter leads to reflected cross-site scripting. A crafted link runs code for whoever clicks it. A CMS field leads to stored cross-site scripting. The bad value sits in saved content and can run for every visitor who loads the page.

If an attacker succeeded, the advisory says, their JavaScript ran in the visitor's browser under the application's origin. In plain terms, the browser treats the injected code as if the site itself wrote it. The people exposed are the site's visitors and customers. Content is often edited by people outside engineering, so the source of a bad value may not be a developer.

How many sites this touches

WebPulse scanned the Tranco top 10,000 domains in September 2026. Of those, 7,064 responded, and a platform was detected on 2,491. Astro was detected on 81 of them, or 3.3% of detected sites.

That number is not an exposure count. The scan shows which framework a site runs. It cannot show whether the site uses MDX or astro:jsx, or whether any dynamic value lands inside a script or style element. The advisory requires both.

WebPulse's NIST NVD profile, refreshed October 20, 2026, lists 20 CVEs for Astro, 14 of them in the last 12 months. It lists 0 Astro entries in CISA KEV, the federal catalog of vulnerabilities known to be exploited. This profile was refreshed two days before the advisory. It is a count of records, not a measure of how secure the framework is.

What to ask your team

Start with inventory. Which of our sites run Astro, and which of those use MDX or the astro:jsx runtime?

Then ask about the pattern itself. Does any template write a changing value, such as a URL parameter or a CMS field, straight into a script or style block? Where does that value come from, and who can change it?

On the fix, the advisory links to the [email protected] release. It says the fix keeps raw rendering for literal content and escapes dynamic strings like other JSX values. Ask your team to confirm the version in production and that the release carries this change.

If an upgrade is not possible, the advisory offers a stopgap. Check these values and encode them for their context before output. Its broader guidance is to keep untrusted values out of these elements altogether.

One more question is ours, not the advisory's. If a site used the pattern with editable content, has anyone checked stored content for stray closing tags?

A framework's default protects only what it was built to cover. The useful audit question is where it was told to stand down.

Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: GitHub Advisory Database.

Share this insight