---
id: "GHSA-ff38-p3qj-4pmf"
page: "https://infrastack.ai/live/GHSA-ff38-p3qj-4pmf"
kind: "vulnerability"
aliases: ["GHSA-ff38-p3qj-4pmf"]
title: "XSS via unescaped code for unsupported languages in @astrojs/prism"
severity: "medium"
cvss: 5.4
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "@astrojs/prism", "fixed": ["4.1.2"], "affected": "<= 4.1.1", "ecosystem": "npm"}, {"name": "@astrojs/markdoc", "fixed": ["2.1.2"], "affected": ">= 0.3.0, <= 2.1.1", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["astro", "cms", "cwe-79", "markdoc", "package", "prism", "static-sites"]
not_affected_if: ["shiki-highlighting", "supported-languages-only", "trusted-authors"]
published_at: "2026-10-28T19:27:39+00:00"
first_seen_at: "2026-11-09T22:53:16+00:00"
updated_at: "2026-11-09T22:56:26+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/withastro/astro/security/advisories/GHSA-ff38-p3qj-4pmf", "first_seen_at": "2026-11-09T22:53:16+00:00"}]
exploit_sources: []
---

# XSS via unescaped code for unsupported languages in @astrojs/prism

Link for people: https://infrastack.ai/live/GHSA-ff38-p3qj-4pmf (this .md is for agents)

Code blocks with a language Prism does not support are inserted into the page as raw HTML instead of escaped text. An attacker who can write content, such as a CMS editor or outside contributor on a Markdoc site, can run scripts for every visitor.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:@astrojs/prism affected <= 4.1.1 fixed 4.1.2
- npm:@astrojs/markdoc affected >= 0.3.0, <= 2.1.1 fixed 2.1.2

## How to check

- Check the installed version of `@astrojs/prism` with `npm ls @astrojs/prism` and of `@astrojs/markdoc` with `npm ls @astrojs/markdoc`.
- Look for uses of the `<Prism />` component with untrusted `code` or user-controlled `lang` props.
- Look for the `prism()` extension in the Markdoc config.

## Fix

- `@astrojs/prism`: `4.1.2`
- `@astrojs/markdoc`: `2.1.2`

## Timeline

- 2026-11-09T22:53:16+00:00 ghsa-repo https://github.com/withastro/astro/security/advisories/GHSA-ff38-p3qj-4pmf

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/withastro/astro/security/advisories/GHSA-ff38-p3qj-4pmf

## From the sources

## Summary

`@astrojs/prism` did not escape code when the requested language was not supported by Prism. `runHighlighterWithAstro()` only HTML-escaped code through `Prism.highlight()` when a grammar was found. For any unsupported language, it returned the original code unchanged, and every caller inserted that result into the page as raw HTML.

As a result, a code block with an unsupported language label, including common labels such as `vue`, `svelte`, `mdx`, `console`, or `text`, was rendered as live HTML instead of displayed as code.

## Details

The affected fallback is in `packages/astro-prism/src/highlighter.ts`:

```ts
const grammar = Prism.languages[lang];
let html = code;
if (grammar) {
	html = Prism.highlight(code, grammar, lang);
}
```

The returned `html` is rendered without further escaping by:

- The `<Prism />` component in `@astrojs/prism`, through `set:html`.
- The `prism()` syntax highlighting extension in `@astrojs/markdoc` (`@astrojs/markdoc/prism`), for every code fence.

Supported languages, and code blocks with no language (which default to `plaintext`), were escaped correctly.

## Impact

Affected applications could be vulnerable to stored cross-site scripting.

- **Markdoc:** Markdoc does not render HTML by default (`allowHTML: false`). On sites that use the `prism()` extension, a content author could get around this by placing HTML inside a code fence with an unsupported language. The HTML and JavaScript would then be rendered and executed on the site's origin for every visitor. This matters for sites where Markdoc content is written by people who cannot otherwise add HTML or code to the site, such as CMS editors or outside contributors.
- **`<Prism />` component:** Applications that pass untrusted input to the `code` prop together with an unsupported or user-controlled `lang` were vulnerable in the same way.

Markdown and MDX content highlighted with `markdown.syntaxHighlight: 'prism'` goes through the same fallback. This does not add new capability there, because Markdown and MDX already allow raw HTML.

## Patches

Fixed in `@astrojs/prism` 4.1.2 and `@astrojs/markdoc` 2.1.2. Code is now escaped when no Prism grammar is available, so unsupported languages are displayed as plain text.

## Workarounds

- Use Shiki instead of Prism for syntax highlighting (the default for Markdown, and the `shiki()` extension for Markdoc).
- Only pass languages that Prism supports to the `<Prism />` component, or HTML-escape untrusted `code` before passing it in.
- For Markdoc content from less-trusted authors, avoid the `prism()` extension until a patched version is available.

## Credit

Reported by [@oss-security-shopify](https://github.com/oss-security-shopify).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
