CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-97JJ-33GV-5XF9

GHSA-97jj-33gv-5xf9: Stored Cross-Site Scripting Bypass in league/commonmark DisallowedRawHtml Extension

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 30, 2026·6 min read·6 visits

Executive Summary (TL;DR)

A regular expression flaw in league/commonmark allows attackers to bypass the DisallowedRawHtml filter using unclosed tags at block boundaries, resulting in Stored Cross-Site Scripting (XSS).

A security vulnerability in league/commonmark versions 1.3.0 through 2.10.1 allows remote attackers to bypass Stored Cross-Site Scripting (XSS) protections in the DisallowedRawHtml extension. Due to an validation logic flaw in the regular expression parser, specifically handling bare, unclosed HTML blocks ending at the string boundary, raw HTML tags can be passed to the rendered output. When combined with browser-side parsing heuristics, an attacker can execute arbitrary JavaScript in the context of the user session.

Vulnerability Overview

The PHP Markdown parser library league/commonmark is widely used to convert Markdown text into compliant HTML. To secure applications from malicious raw HTML insertion, the library provides the DisallowedRawHtml extension (which is enabled automatically under GitHub Flavored Markdown config). This extension is designed to sanitize and escape hazardous HTML tags, such as <script>, <iframe>, or <style>, preventing potential script execution in a client browser.

However, a severe design flaw exists within the input validation structure of the DisallowedRawHtml extension. The module employs a regular expression pattern to intercept and escape dangerous tags. When processing highly malformed or truncated HTML blocks, the parser can fail to match and escape these elements, leaving raw script tags intact within the rendered HTML payload.

This flaw represents a Stored Cross-Site Scripting (XSS) vulnerability. Since the processed Markdown is stored in the database (e.g., comments, forum content, wiki pages) and rendered to other users, attackers can execute arbitrary JavaScript in the sessions of unsuspecting users who view the generated page.

Root Cause Analysis

The root cause of this vulnerability lies in an impedance mismatch between the CommonMark HTML block parser and the DisallowedRawHtmlRenderer validation regex. According to the CommonMark and GFM specifications, a line starting with an HTML tag name (such as <script or <iframe) with no trailing brackets or whitespace is interpreted as the beginning of a valid HTML block.

When league/commonmark compiles this into an HtmlBlock node, it retains the exact text segment. This output text ends abruptly at the tag name boundary itself (e.g., <script). It does not append a closing bracket or space. Prior to the fix, the DisallowedRawHtmlRenderer executed the following regular expression to intercept the disallowed tag names:

$regex = \sprintf('/<(\/?(?:%s)[\s\/>])/i', \implode('|', \array_map('preg_quote', $tags)));

The trailing character class [\s\/>] requires that the matched tag name be immediately followed by either a space, a forward slash, or a closing angle bracket. Because the compiled HtmlBlock ends exactly with the last character of the tag name (the letter 't' in <script), there is no trailing character available. The regex match fails entirely, and the unescaped tag is passed directly into the final document.

When a browser parses the resulting HTML document, it encounters the raw <script string. To ensure high compatibility with poorly structured web pages, modern web browsers automatically attempt to repair unclosed tags. The browser treats subsequent HTML attributes on the next lines as the attributes of the open <script tag, leading to script execution.

Code Analysis

The vulnerability was corrected in commit 411afcc2a7402756d96c89af8882c724d12d47ca by extending the regular expression to support end-of-string boundaries. Below is a comparison of the vulnerable and patched regex implementations in DisallowedRawHtmlRenderer.php.

- $regex = \sprintf('/<(\/?(?:%s)[\s\/>])/i', \implode('|', \array_map('preg_quote', $tags)));
+ // The tag name may also end the rendered HTML: the block parser accepts a bare
+ // `<script` line, and browsers treat the following block as its attributes.
+ $regex = \sprintf('/<(\/?(?:%s)(?:[\s\/>]|$))/i', \implode('|', \array_map('preg_quote', $tags)));

In the vulnerable implementation, the regex required an explicit trailing delimiter character. In the patched code, a non-capturing group (?:[\s\/>]|$) was introduced. This alternation ensures that the pattern matches the tag name if it is followed by a standard delimiter OR if it is situated at the absolute end of the target string ($).

This correction is robust and complete. It prevents the exploitation of any block structure where the tag terminates the string, regardless of whether the tag is at the end of the entire document or nested within structural blocks. Variant attacks trying to bypass the check by abusing boundary conditions are neutralized because the regex engine now treats the string boundary as a valid terminator.

Exploitation Methodology

To exploit this vulnerability, an attacker must have permission to submit Markdown text that is subsequently rendered to other users. The configuration parameter html_input must be set to allow (the library default), and the DisallowedRawHtml extension must be active (which is typical when using GFM).

An attacker can construct a payload where the disallowed tag is isolated on its own line without any trailing characters, thereby triggering the HTML block parsing rules. The attacker then places the execution context or external resource link on a subsequent block, which the browser's loose parsing engine will merge.

An example payload utilizes a <script tag followed by a blank line and an element that looks like an attribute list:

<div>
<script
 
<span src="/evil.js">

This input translates to the following rendered HTML output:

<div>
<script
<span src="/evil.js">

When a browser reads this, it parses the open <script tag, ignores the intermediate whitespace, and interprets the src="/evil.js" attribute as belonging directly to the script element, downloading and executing the remote script.

Impact Assessment

The impact of this vulnerability is Stored Cross-Site Scripting (XSS). If successfully exploited, the attacker can execute arbitrary client-side JavaScript within the browser context of any user who views the page containing the malicious rendered Markdown.

This execution capability enables several critical attack paths. Attackers can steal session identifiers, session cookies (if not marked with the HttpOnly flag), or access tokens stored in LocalStorage. They can also perform unauthorized actions on behalf of the victim, alter the DOM to phish for user credentials, or deploy client-side keyloggers to capture sensitive user inputs.

The vulnerability is classified with a CVSS v3.1 score of 6.1 (Medium). The vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N highlights that while exploitation requires zero privileges (PR:N) and is of low complexity (AC:L), it does require a victim user to navigate to and view the page containing the injected content (UI:R), and triggers a scope change (S:C) because execution happens in the browser context.

Remediation and Mitigation Guidance

The primary and recommended mitigation is upgrading the league/commonmark package to version 2.10.2 or later. This release updates the core regex logic to handle string boundaries gracefully, ensuring that bare tag names are properly matched and escaped.

To update the dependency in a PHP application utilizing Composer, execute the following command:

composer update league/commonmark

If upgrading the library is not immediately possible due to dependency constraints, you can temporarily mitigate the vulnerability by adjusting the library configuration. Setting the html_input option to escape or strip prevents the parser from rendering any raw HTML tags, neutralizing the bypass vector.

use League\CommonMark\MarkdownConverter;
 
$config = [
    'html_input' => 'escape', // Escapes all user HTML, neutralizing XSS bypasses
];
 
$converter = new MarkdownConverter($config);

Official Patches

thephpleagueOfficial Security Advisory for GHSA-97jj-33gv-5xf9
thephpleagueLibrary Release Tag v2.10.2 with Security Patches

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Affected Systems

Applications using league/commonmark to render Markdown to HTML with raw HTML input enabled.

Affected Versions Detail

Product
Affected Versions
Fixed Version
league/commonmark
thephpleague
>= 1.3.0, <= 2.10.12.10.2
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork (AV:N)
CVSS6.1 (Medium)
EPSS ScoreN/A (No CVE assigned)
Exploit Statuspoc
KEV Statusfalse

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

GitHub Security AdvisoryProof of concept markdown rendering payload that bypasses DisallowedRawHtml using nested multiline sequences

References & Sources

  • [1]GitHub Advisory Database: GHSA-97jj-33gv-5xf9
  • [2]league/commonmark Security Advisory: XSS Bypass in DisallowedRawHtml
  • [3]Fix Commit 411afcc

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•14 minutes ago•CVE-2026-91777
7.5

CVE-2026-91777: Algorithmic Complexity Denial of Service in FasterXML jackson-databind

An uncontrolled resource consumption vulnerability in FasterXML jackson-databind allows remote unauthenticated attackers to cause a Denial of Service (DoS) via crafted JSON payloads containing out-of-order forward references in identity-enabled collections or maps.

Alon Barad
Alon Barad
5 views•6 min read
•about 2 hours ago•GHSA-P98J-92PF-MC4P
8.1

GHSA-P98J-92PF-MC4P: DOM-Based Cross-Site Scripting (DOM XSS) via Hook Detach Bypass in DOMPurify In-Place Sanitization

A DOM-based Cross-Site Scripting (DOM XSS) vulnerability in DOMPurify allows attackers to bypass sanitization when using the in-place sanitization configuration (IN_PLACE: true) combined with custom hooks. If custom hooks detach elements during post-processing phases, nested malicious payloads can escape sterilization and execute in the browser's context.

Amit Schendel
Amit Schendel
6 views•8 min read
•about 3 hours ago•CVE-2026-97711
2.3

CVE-2026-97711: Cross-Site Scripting (XSS) via Unescaped Script-Closing Tags in serialize-javascript

A security vulnerability in serialize-javascript v7.1.1 allows Cross-Site Scripting (XSS) due to an overly greedy regular expression (SCRIPT_CLOSE_REGEXP) used during function serialization. Two secondary defects involving a spoofed toString() validation bypass and a stateful native code validator are also addressed in the fixed version v7.1.2.

Alon Barad
Alon Barad
0 views•7 min read
•about 4 hours ago•CVE-2026-101918
5.3

CVE-2026-101918: Unauthenticated Denial of Service via Recursion Exhaustion in PyJWT

A Denial of Service (DoS) vulnerability exists in the PyJWT library when parsing unverified token payloads containing deeply nested JSON structures. Because PyJWT fails to catch RecursionError during payload parsing, an unauthenticated remote attacker can crash the application thread or worker by sending a specially crafted token.

Alon Barad
Alon Barad
8 views•5 min read
•about 5 hours ago•GHSA-VCVR-R3JV-PC5J
9.8

CVE-2026-94545: SVG-Serialization Markup Injection in Vercel Satori and Next.js ImageResponse

An improper output encoding and escaping vulnerability (CWE-116) in Vercel Satori allows unauthenticated remote attackers to perform markup injection in dynamic Open Graph images generated via Next.js's ImageResponse. Unsanitized parameter interpolation into SVG elements breaks XML structural boundaries. This exposes downstream parsing, rasterization, and rendering pipelines to Server-Side Request Forgery (SSRF), Local File Read, and Remote Code Execution (RCE).

Alon Barad
Alon Barad
8 views•7 min read
•about 6 hours ago•CVE-2026-102265
5.3

CVE-2026-102265: Unhandled RecursionError in PyJWT JSON Parser Leading to Denial of Service

An uncontrolled recursion vulnerability exists in PyJWT from version 2.13.0 to 2.14.0. The vulnerability allows remote, unauthenticated attackers to cause a Denial of Service (DoS) via crafted JWT headers that trigger stack exhaustion during JSON decoding.

Amit Schendel
Amit Schendel
8 views•5 min read