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



CVE-2026-32870
6.9

CVE-2026-32870: XML Injection via Unsafe CDATA Handling in Kirby CMS Toolkit

Amit Schendel
Amit Schendel
Senior Security Researcher

Apr 24, 2026·6 min read·4 visits

PoC Available

Executive Summary (TL;DR)

An input validation flaw in Kirby CMS allows attackers to bypass XML escaping by starting input with a CDATA tag. Attackers can terminate the CDATA block early and inject arbitrary XML tags, potentially altering data structures in RSS feeds, sitemaps, or API responses. Upgrading to versions 4.9.0 or 5.4.0 patches the vulnerability.

Kirby CMS versions prior to 4.9.0 and 5.0.0 through 5.3.x are vulnerable to XML Injection (CWE-91). An insecure heuristic within the Toolkit's XML handling methods permits an attacker to bypass entity encoding by prepending a CDATA identifier. This allows the injection of arbitrary XML elements into documents generated by the CMS or custom plugins.

Vulnerability Overview

Kirby CMS utilizes the Kirby\Toolkit\Xml class and the Kirby\Data\Data class to handle formatting and encoding of XML data. These components are frequently leveraged by site-specific templates and plugins to generate structured outputs such as RSS feeds, Sitemaps, SOAP responses, and REST API payloads. Untrusted input processed by these methods must be strictly encoded to prevent structural alteration of the resulting document.

This vulnerability, tracked as CVE-2026-32870 and GHSA-9wfj-c55w-j9qr, constitutes an XML Injection (CWE-91). The flaw originates from an insecure validation heuristic used to detect strings that are already safely encapsulated. By exploiting this flaw, an attacker can construct a payload that bypasses the escaping routines entirely.

The attack surface includes the Xml::value(), Xml::tag(), Xml::create(), and Data::encode($input, 'xml') methods. If an application routes attacker-controlled input through any of these functions, the attacker can manipulate the syntax of the generated XML document. The core rendering engine for Kirby pages is largely unaffected by default, restricting the primary impact to custom features or plugins explicitly using the toolkit for XML generation.

Root Cause Analysis

The root cause resides in the Xml::value() method within src/Toolkit/Xml.php. This method prepares strings for XML output by applying htmlspecialchars() to prevent characters like < and > from being parsed as structural tags. The method attempts to optimize processing by skipping this escaping process if the input is already encapsulated in a Character Data (CDATA) section.

Prior to the patch, the application used a superficial validation check to identify pre-escaped data. It relied exclusively on Str::startsWith($value, '<![CDATA['). If an untrusted input string began with this specific sequence, the method assumed the entire string was a single, valid CDATA block and returned it verbatim without applying any entity encoding.

Because the validation logic only inspected the prefix of the string, an attacker could supply a payload that opens a CDATA block, immediately terminates it using ]]>, and then appends raw XML syntax. The vulnerable code would identify the prefix, skip the htmlspecialchars() function, and inject the mixed payload directly into the XML document. Downstream parsers would correctly terminate the CDATA section and then interpret the attacker's appended tags as legitimate structural elements.

Code Analysis

The vulnerable implementation in src/Toolkit/Xml.php executed a simple string prefix match. The code lacked any verification regarding the termination of the CDATA block or the presence of malformed structural elements within the string payload.

// Vulnerable Implementation (Kirby < 4.9.0 / < 5.4.0)
public static function value(string $value): string
{
    // Flaw: Only validates the start of the string.
    // Attacker can terminate CDATA early and inject tags.
    if (Str::startsWith($value, '<![CDATA[') === true) {
        return $value;
    }
    
    return htmlspecialchars($value, ENT_QUOTES | ENT_XML1, 'UTF-8');
}

The remediation, applied in commits a88ef33e81ed286d9dddf5a2f2d239aa73cd0d31 and 9309d5242fbfddf6650dc6c5fd8212765ce49ee6, enforces a strict structural contract. To bypass escaping, the string must now satisfy three conditions: it must start with a CDATA opener, end with a CDATA closer, and contain no internal unescaped CDATA closures.

// Patched Implementation (Kirby 4.9.0 / 5.4.0)
public static function value(string $value): string
{
    // Fix: Validates complete encapsulation and prevents internal breaks
    if (
        Str::startsWith($value, '<![CDATA[') === true &&
        Str::endsWith($value, ']]>') === true &&
        Str::matches($value, '/\]\]>(?!<!\[CDATA\[|$)/') === false
    ) {
        return $value;
    }
    
    // Any malformed or injected data falls through to htmlspecialchars
    return htmlspecialchars($value, ENT_QUOTES | ENT_XML1, 'UTF-8');
}

Exploitation Mechanics

Exploitation requires an attacker to inject controlled input into a field processed by the Xml toolkit or the Data::encode() wrapper. Common injection points include blog post titles, user profile fields, or custom metadata that a site administrator later exports to an RSS feed or third-party integration.

The core exploitation technique leverages early termination of the CDATA block. An attacker supplies a payload formatted as <![CDATA[test]]><malicious_tag>payload</malicious_tag>. When the vulnerable application calls Xml::value() on this string, the prefix matches, and the raw payload is written to the output file.

When an external system parses the resulting document, the XML parser interprets <![CDATA[test]]> as a valid character block containing the word 'test'. The parser then encounters <malicious_tag> and evaluates it as an active document node. Attackers can also utilize comment smuggling techniques, such as <![CDATA[test]]><!-- comment -->, to hide injected logic or bypass WAF signatures looking for standard tags.

The proof-of-concept payloads from the patch test suite confirm that inputs like <![CDATA[ ]]> <juhu>haha</juhu> successfully bypass the escaping mechanism. In a patched environment, this same payload is safely encoded as <![CDATA[<![CDATA[ ]]]]><![CDATA[><juhu>haha</juhu>]]>, neutralizing the injection.

Impact Assessment

This vulnerability carries a CVSS 4.0 base score of 6.9, described by the vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:H/SA:N. The score reflects a high impact on system integrity, specifically the integrity of the generated XML documents, with no required privileges or user interaction.

The concrete impact depends heavily on the downstream consumer of the generated XML. If the XML is an RSS feed, an attacker can modify the feed's structure to inject unauthorized links or content. If the generated XML is a configuration file or a SOAP request used in a backend integration, the attacker may bypass business logic or trigger unexpected application behavior in the consumer system.

While the vulnerability permits arbitrary tag injection, it does not directly enable Remote Code Execution (RCE) on the Kirby server itself. Furthermore, if the generated XML is rendered directly in a web browser without proper content-type headers, the injected tags may result in Cross-Site Scripting (XSS).

Remediation and Mitigation

The definitive remediation for CVE-2026-32870 is upgrading Kirby CMS to a patched release. Administrators must update installations to either version 4.9.0 or version 5.4.0. These releases contain the necessary regular expression fixes to enforce proper CDATA encapsulation.

For environments where immediate patching is unfeasible, developers should audit site-specific templates and plugins. Any calls to Kirby\Toolkit\Xml methods or Kirby\Data\Data::encode($val, 'xml') that process untrusted data must be identified. Developers can implement an interim manual sanitization layer by pre-processing user input with htmlspecialchars() before passing it to the Kirby toolkit.

Security teams can monitor for exploitation attempts by applying Web Application Firewall (WAF) rules or Intrusion Detection System (IDS) signatures. Rules should inspect incoming HTTP request bodies and URL parameters for the sequence <![CDATA[ immediately followed by ]]> within the same field payload, as this strongly indicates an attempt to exploit the parsing heuristic.

Official Patches

KirbyKirby CMS 4.9.0 Release Notes and Patch
KirbyKirby CMS 5.4.0 Release Notes and Patch

Fix Analysis (2)

Technical Appendix

CVSS Score
6.9/ 10
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:H/SA:N

Affected Systems

Kirby CMS ToolkitKirby CMS Data handlers

Affected Versions Detail

Product
Affected Versions
Fixed Version
Kirby CMS
Kirby
< 4.9.04.9.0
Kirby CMS
Kirby
>= 5.0.0, < 5.4.05.4.0
AttributeDetail
CWE IDCWE-91
Attack VectorNetwork
CVSS Base Score6.9
ImpactHigh System Integrity
Exploit StatusProof of Concept
Affected ComponentKirby\Toolkit\Xml

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1566Phishing
Initial Access
CWE-91
XML Injection

Improper Neutralization of Special Elements used in an XML Document

Known Exploits & Detection

Patch Unit TestsProof of concept payloads present within the patch unit test suite.

Vulnerability Timeline

Initial fix commit for Kirby 4.x (a88ef33)
2026-03-16
Merge of fix into release branch 5.3.4 (later 5.4.0)
2026-03-30
CVE and GHSA officially published
2026-04-24

References & Sources

  • [1]GitHub Security Advisory: GHSA-9wfj-c55w-j9qr

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.