Jul 9, 2026·8 min read·14 visits
Authenticated path traversal in Craft CMS allows reading local SVG files and executing Stored XSS via malicious file paths.
An authenticated path traversal and arbitrary local file read vulnerability exists in Craft CMS versions 4.x up to 4.17.6 within the assets/icon endpoint and Assets helper classes. By exploiting this vulnerability, an authenticated user can traverse directories and read arbitrary .svg files on the server's filesystem, or execute Stored Cross-Site Scripting (XSS) if they can upload a malicious SVG.
This vulnerability, designated as GHSA-C43V-4CR8-6MVP, is an authenticated path traversal and local file read flaw in the content management system Craft CMS. The issue resides within the application asset management subsystem, specifically involving how the platform retrieves and processes file extensions for rendering system and custom icons. Specifically, the vulnerability manifests within the assets/icon endpoint and the associated helper methods Assets::iconPath() and Assets::iconUrl() located in the src/helpers/Assets.php component.
An authenticated user with low-level privileges can craft a specialized HTTP request containing path traversal sequences directed at the extension query parameter. Due to the lack of strict input sanitization at the boundary of the path construction utility, the application resolves paths outside the intended asset directories. If the requested target file is a valid vector graphics document, the application reads its content and returns it within the HTTP response, circumventing filesystem restrictions.
In addition to arbitrary file disclosure of graphics assets, this vulnerability poses a nested security risk by serving as an administrative entry point for Stored Cross-Site Scripting (XSS). If an attacker possesses privileges to upload file structures to any directory accessible to the web server, they can upload a malicious SVG payload and execute it by traversing to that file through the icon rendering endpoint. The resulting script execution occurs under the origin of the host application, which can facilitate administrative session hijacking.
The primary defect within Craft CMS stems from improper input validation and subsequent unsafe string concatenation in the static utility class src/helpers/Assets.php. When a client requests an icon asset via the controller action handling assets/icon, the application passes the user-controlled extension parameter directly to the helper method Assets::iconPath(). The function uses sprintf() to append this user-controlled string to the directory path returned by Craft::$app->getPath()->getAssetsIconsPath().
The system fails to perform path verification or character sanitization prior to executing standard PHP filesystem operations on the constructed path. Specifically, the method uses the PHP library function file_exists() on the unchecked string, allowing relative path traversal operators such as ../ or ..\\ to be processed natively by the operating system filesystem driver. This design pattern permits an attacker to escape the designated asset directories and reference any arbitrary location on the filesystem that is readable by the web server process.
When PHP functions such as file_exists() or fopen() receive a string path, they delegate the resolution of the path to the underlying operating system's filesystem APIs. On UNIX-like and Windows platforms, the directory separator characters and relative path tokens (. and ..) are processed iteratively. This means that when the application constructs a path containing relative sequences, the operating system resolves each segment by moving up the directory hierarchy, completely escaping the restricted boundary.
While the application did contain a regular expression validation check (preg_match('/^\w+$/', $extension)) within downstream logic, this defense was misplaced inside the fallback Assets::iconSvg() function. The fallback function is only executed when the initial path resolution via Assets::iconPath() returns false, meaning that the requested file does not exist on disk. Because the early return path in iconPath() successfully resolves existing files and bypasses the fallback logic, any target file that exists on the filesystem entirely evades this validation filter.
To understand the structural flaws, analyzing the vulnerable implementation of the helper methods within src/helpers/Assets.php is necessary. The methods iconUrl and iconPath lacked early-stage validation, allowing raw input propagation directly into filesystem checks. The following PHP code block demonstrates how the input parameter $extension was processed without validation in the vulnerable versions:
// Vulnerable Code Path in src/helpers/Assets.php
public static function iconUrl(string $extension): string
{
// User input from the query parameter is passed directly
return UrlHelper::actionUrl('assets/icon', [
'extension' => $extension,
]);
}
public static function iconPath(string $extension): string
{
// Unsanitized concatenation occurs here via sprintf
$path = sprintf('%s%s%s.svg', Craft::$app->getPath()->getAssetsIconsPath(), DIRECTORY_SEPARATOR, strtolower($extension));
// file_exists executes on the resolved path containing traversal sequences
if (file_exists($path)) {
return $path; // Early return bypasses downstream validation filters
}
...The corresponding patch implemented in version 4.17.7 inserts rigid input validation at the absolute entry points of both functions. By introducing a regular expression filter before any path manipulation or URL generation occurs, the application ensures that only safe alphanumeric strings are handled. The corrected code is shown below:
// Patched Code in src/helpers/Assets.php
public static function iconUrl(string $extension): string
{
// Restrict input strictly to alphanumeric characters and underscores
if (!preg_match('/^\w+$/', $extension)) {
throw new InvalidArgumentException("$extension isn’t a valid file extension.");
}
return UrlHelper::actionUrl('assets/icon', [
'extension' => $extension,
]);
}
public static function iconPath(string $extension): string
{
// Restrict input strictly to alphanumeric characters and underscores
if (!preg_match('/^\w+$/', $extension)) {
throw new InvalidArgumentException("$extension isn’t a valid file extension.");
}
$path = sprintf('%s%s%s.svg', Craft::$app->getPath()->getAssetsIconsPath(), DIRECTORY_SEPARATOR, strtolower($extension));
if (file_exists($path)) {
return $path;
}
...This validation design successfully mitigates the flaw by terminating execution immediately when special characters such as dots or slashes are present. Because the validation runs before the file_exists() check, the logical gap that previously allowed existing files to bypass the filter is fully closed.
Exploitation of this vulnerability requires an authenticated session with privileges sufficient to access the administrator control panel or invoke asset action controllers. An attacker can construct a payload targeting the assets/icon action by specifying a relative path in the extension query parameter. The following sequence outlines the methodology of a standard local file read attack:
To retrieve a target SVG file stored outside the designated icon directory, the attacker sends an HTTP GET request to the controller endpoint. The parameter must point to the relative location of the target file, excluding the .svg extension, as the application appends it automatically. For example, a request with extension=../../../../some_internal_resource maps to a path check for some_internal_resource.svg relative to the server webroot.
The execution of the script in the context of the browser depends on the response headers returned by the server. When the assets/icon endpoint serves the traversal target, it sets the Content-Type header to image/svg+xml. In modern web browsers, when an SVG is loaded directly as a document, embedded JavaScript is executed under the document's origin. By directing a user to the controller URL, the attacker forces a direct document load, satisfying the browser's execution conditions and enabling Stored XSS.
The impact of GHSA-C43V-4CR8-6MVP is divided into data exposure and cross-site execution vectors. While the local file read capability is restricted to files ending with the .svg extension, sensitive cryptographic keys, application configurations, or internal metadata stored in SVG formats can be disclosed. Additionally, the ability to read arbitrary SVGs can allow an attacker to reconstruct directory structures and verify the existence of specific files on the server.
The secondary risk of Stored Cross-Site Scripting (XSS) significantly elevates the severity of this vulnerability. Because the application processes and returns the SVG content directly through an administrative controller context, browser security policies render the executable scripts inside the SVG within the origin of the Craft CMS application. If an administrator triggers the rendered vector, the attacker can execute arbitrary API commands, alter system settings, or retrieve session tokens.
This vulnerability is tracked under the GitHub Security Advisory database with low-to-moderate complexity. Since the exploit does not require advanced tools or complex memory manipulation, it represents an accessible target for adversaries who have established basic authenticated access. The threat is especially relevant in shared hosting environments where file write access is distributed across multiple tenants.
Remediation of this vulnerability requires upgrading the installation of Craft CMS to version 4.17.7 or subsequent releases in the 4.x and 5.x branches. The upgrade applies the strict alphanumeric validation filter to the Assets helper, preventing the processing of path traversal sequences. Administrators should verify their current version via the composer utility or the control panel dashboard to confirm the patch is active.
If immediate patching is not feasible, administrators can apply mitigation strategies at the network and server configuration levels. Restricting access to the assets/icon action using web application firewall (WAF) rules or URL rewriting can block requests containing traversal sequences. A sample rule matching traversal patterns in the query string should be deployed to analyze incoming traffic to the controller endpoint.
Additionally, implementing strict Content Security Policy (CSP) headers can limit the execution of embedded scripts within SVG files. Specifically, setting the policy default-src 'self'; object-src 'none'; or serving user-uploaded SVGs with headers that prevent script execution helps isolate the application from XSS vectors. Regular audits of user upload directories should also be conducted to identify and purge unauthorized SVG documents containing active script tags.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Craft CMS craftcms | >= 4.0.0, <= 4.17.6 | 4.17.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| Attack Vector | Network |
| CVSS Score | 6.5 (Medium) |
| EPSS Score | N/A (No CVE assigned) |
| Impact | Local File Read & Stored Cross-Site Scripting (XSS) |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located under a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.
A critical SQL injection vulnerability exists in the GeoTools open-source Java library. This vulnerability is situated within the post-processing phase of OGC Filter conversion inside the PostGIS DataStore module. Specifically, the `jsonArrayContains` function does not validate or sanitize its arguments before constructing PostgreSQL SQL/JSON path evaluation queries. An unauthenticated remote attacker can exploit this weakness by submitting crafted filters via standard OGC services like WFS or WMS to execute arbitrary SQL commands on the underlying database system.
CVE-2026-61824 is a high-severity Cross-Site Scripting (XSS) vulnerability in kepano/defuddle before version 0.19.1. Custom site extractors for platforms such as X/Twitter, Substack, and YouTube constructed HTML representations via template string interpolation without output escaping. This allowed malicious pages to bypass standard parser sanitization routines and execute arbitrary JavaScript.
A high-severity vulnerability exists in KeystoneJS, a popular Node.js CMS and GraphQL framework, where the query resolution engine fails to validate signed negative integers within the pagination subsystem. Unauthenticated remote attackers can leverage this flaw to bypass the 'graphql.maxTake' safety boundary. By sending large negative values in the 'take' query parameter, the underlying Prisma ORM interprets the value as an instruction to fetch rows from the end of the collection, allowing malicious actors to bypass pagination limits, trigger database resource exhaustion, and execute application-level Denial of Service (DoS) attacks.