CVE-2026-28499 Overview
CVE-2026-28499 is a Cross-Site Scripting (XSS) vulnerability in LeafKit, a templating language with Swift-inspired syntax used in the Vapor web framework ecosystem. Prior to version 1.14.2, HTML escaping doesn't work correctly when a template prints a collection (Array / Dictionary) via the #(value) syntax. This flaw allows potentially untrusted input to be rendered unescaped in web pages, creating an XSS attack vector.
Critical Impact
Attackers can inject malicious scripts into web pages rendered by LeafKit templates when collections containing untrusted data are displayed. This can lead to session hijacking, credential theft, defacement, or malware distribution to end users.
Affected Products
- Vapor LeafKit versions prior to 1.14.2
- Web applications using LeafKit templating with collection rendering
- Vapor-based Swift web applications using vulnerable LeafKit versions
Discovery Timeline
- 2026-03-18 - CVE CVE-2026-28499 published to NVD
- 2026-03-18 - Last updated in NVD database
Technical Details for CVE-2026-28499
Vulnerability Analysis
This vulnerability exists in the HTML escaping logic within LeafKit's LeafData and LeafDataStorage components. When rendering collections such as Arrays or Dictionaries through the #(value) template syntax, the HTML escaping function fails to properly sanitize the content before output.
The root issue lies in how the htmlEscaped() function handled data conversion. The original implementation attempted to access the string property directly, which doesn't properly handle collection types. Collections would bypass the escaping logic entirely, allowing any HTML or JavaScript content within collection elements to be rendered directly into the page output without sanitization.
This vulnerability is exploitable over the network without authentication requirements. An attacker who can inject content into a collection that gets rendered by a LeafKit template can execute arbitrary JavaScript in the context of victims' browsers.
Root Cause
The vulnerability stems from improper input validation in the htmlEscaped() function within LeafData.swift. The function's guard statement checked self.string directly instead of first converting the data to a string type. When processing collections (Arrays or Dictionaries), this direct access would fail to produce a string representation, causing the function to return the data unescaped.
The fix modifies the guard statement to use self.convert(to: .string, .ambiguous).string, ensuring proper type conversion occurs before the HTML escaping check, allowing collection contents to be properly escaped.
Attack Vector
An attacker can exploit this vulnerability by injecting malicious JavaScript or HTML content into data that will be stored in an Array or Dictionary and subsequently rendered in a LeafKit template. Common attack scenarios include:
- User-supplied input stored in collections (e.g., lists of comments, tags, or user data)
- Data from external APIs that gets rendered without proper escaping
- Database content that includes malicious scripts in collection fields
The following patch shows the security fix applied in version 1.14.2:
/// Return a HTML-escaped version of this data if it can be converted to a string.
func htmlEscaped() -> LeafData {
- guard let string = self.string else {
+ guard let string = self.convert(to: .string, .ambiguous).string else {
return self
}
Source: GitHub Commit Details
The serialization logic was also updated to ensure consistent handling:
/// Final serialization to a shared buffer
func serialize(buffer: inout ByteBuffer) throws {
- switch self {
- case .bool, .int, .double, .string, .optional, .array, .dictionary:
- try buffer.writeString(self.serialize(), encoding: LeafConfiguration.encoding)
- case .data(let d):
- buffer.writeData(d)
- }
+ try buffer.writeString(self.serialize(), encoding: LeafConfiguration.encoding)
}
// MARK: - Equatable Conformance
Source: GitHub Commit Details
Detection Methods for CVE-2026-28499
Indicators of Compromise
- Unusual JavaScript execution patterns in rendered pages containing collection data
- Web application logs showing script injection attempts in array or dictionary fields
- Browser console errors related to Content Security Policy violations if CSP is implemented
- User reports of unexpected behavior or redirects when viewing pages with list/collection content
Detection Strategies
- Audit LeafKit templates for usage of #(value) syntax with collection types (Arrays/Dictionaries)
- Review application dependencies for LeafKit versions below 1.14.2
- Implement Web Application Firewall (WAF) rules to detect XSS payloads in input fields
- Monitor Content Security Policy (CSP) violation reports for injection attempts
Monitoring Recommendations
- Enable verbose logging for user input that gets stored in collection data structures
- Implement real-time alerting for XSS-related patterns in web request logs
- Deploy browser-based XSS detection mechanisms such as CSP reporting
- Monitor for anomalous JavaScript execution in user sessions
How to Mitigate CVE-2026-28499
Immediate Actions Required
- Upgrade LeafKit to version 1.14.2 or later immediately
- Audit all templates that render collection data using #(value) syntax
- Implement Content Security Policy headers to limit script execution as defense-in-depth
- Review and sanitize any user-controlled data stored in Arrays or Dictionaries
Patch Information
The vulnerability is fixed in LeafKit version 1.14.2. The patch modifies the htmlEscaped() function to properly convert collection types to strings before applying HTML escaping, ensuring all content is properly sanitized before rendering.
To update, modify your Package.swift dependencies:
.package(url: "https://github.com/vapor/leaf-kit.git", from: "1.14.2")
For detailed information, see the GitHub Security Advisory GHSA-6jj5-j4j8-8473 and the GitHub Release Version 1.14.2.
Workarounds
- Manually escape collection contents before passing to templates using custom sanitization functions
- Avoid rendering untrusted data within collections directly in templates
- Implement server-side input validation to strip HTML/script content from user inputs before storage
- Deploy strict Content Security Policy headers to prevent inline script execution as a mitigating control
# Example: Update Package.swift and rebuild
swift package update
swift build --configuration release
# Verify installed version
swift package show-dependencies | grep leaf-kit
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

