CVE-2026-86431: league/commonmark AttributesExtension XSS bypass with U+000C

CVE-2026-86431 · Severity: high · CVSS 7.2 · Published 2026-09-07

The PHP League CommonMark library is a popular Markdown parser used to convert user-submitted content into safe HTML for display on websites. A vulnerability in its AttributesExtension allows attackers to inject malicious JavaScript by prefixing attribute names with an invisible control character, bypassing security filters designed to block dangerous event handlers like onclick and onerror. Exploits only execute if the parsed content is displayed in a browser, making it a stored or reflected XSS risk depending on the application's use of the library.

Technologies: league/commonmark (Packagist). Vendors: Packagist.

Quick answers

Is CVE-2026-86431 exploited in the wild?
No. Junglewise Threat Intelligence has no report of CVE-2026-86431 being exploited in the wild.
How severe is CVE-2026-86431?
High severity, with a CVSS score of 7.2, published 7 September 2026.
Which products and versions are affected?
league/commonmark (Packagist) ECOSYSTEM:introduced=2.7.0,fixed=2.9.1.
Is there a fix for CVE-2026-86431?
Yes. league/commonmark (Packagist): upgrade to 2.9.1 or later. Junglewise finds every place you run it, drafts the upgrade and applies it once you approve.
How is CVE-2026-86431 attacked?
It is attacked over the network.
Am I affected by CVE-2026-86431?
Check whether you run league/commonmark (Packagist) at an affected version. Junglewise does that check for you around the clock: connect your code, cloud and domains, and it matches new vulnerabilities like this one against what you actually run and tells you when one reaches you.

How to fix

  • league/commonmark (Packagist): upgrade to 2.9.1 or later
    composer require league/commonmark:^2.9.1

Technical details

The AttributesExtension filters harmful event-handler attributes (on* prefixes) and unsafe URI schemes (javascript:) using string comparisons in the filterAttributes() method. The vulnerability stems from three compounding issues: (1) PHP's trim() function does not remove the U+000C form feed byte, despite it being matched by the initial PCRE regex, leaving it inside attribute names; (2) the filter's case-insensitive string comparisons miss the malformed name because "\x0Conclick" ≠ "onclick"; and (3) the HTML renderer never escapes attribute names. When the HTML5 tokenizer parses the output, it treats U+000C as whitespace, collapsing the prefix and revealing the true attribute name. Exploitation requires untrusted Markdown input processed with AttributesExtension enabled; no prior authentication or user interaction beyond viewing the rendered HTML is required. Fixed in version 2.9.1 via attribute name normalization and stricter filtering.

Affected products

  • PHP League CommonMark >= 2.7.0, < 2.9.1

Identifiers

  • CVE-2026-86431
  • GHSA-f8fg-pg57-v4j8

Timeline

  • 2026-09-07: disclosed: CVE-2026-86431 published
  • 2025-05-05: patched: Fix committed (version 2.9.1)

References

This page as Markdown. Free to reuse under CC BY 4.0 with a link back.