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



GHSA-7HXC-F267-H5Q7

GHSA-7HXC-F267-H5Q7: Path Traversal via Validation-then-Normalization in Craft CMS

Alon Barad
Alon Barad
Software Engineer

Aug 7, 2026·8 min read·1 visit

Executive Summary (TL;DR)

Craft CMS local storage driver validates path containment before normalizing the path. This allows attackers to bypass boundary checks using protocol-prefixed traversal sequences, resulting in unauthorized local file access.

A path traversal vulnerability exists in the local filesystem driver of Craft CMS. Due to validation occurring before path normalization, directory containment checks can be bypassed by utilizing specific protocol schemes like 'file://' along with directory traversal sequences. This allows authenticated users with administrative privileges to access or manipulate files outside the defined storage root directory.

Vulnerability Overview

The local filesystem driver (Local.php) in Craft CMS is responsible for managing the physical storage and manipulation of assets within configured local storage volumes. It exposes an attack surface through asset management capabilities, where users can upload, index, or rename physical resources. To maintain security boundaries, Craft CMS enforces a directory containment validation mechanism to prevent users from referencing files outside of their designated storage root.

This vulnerability is characterized as an improper limitation of a pathname to a restricted directory, corresponding to CWE-22 and CWE-23. The flaw occurs because of a logical desynchronization between how paths are validated and how they are subsequently normalized before execution. This order-of-operations vulnerability allows directory containment validation to be bypassed completely when specific inputs are processed.

An attacker with administrative privileges or permission to modify asset configurations can submit paths that contain URI protocol schemes such as file:// alongside directory traversal sequences. Because the application evaluates security boundaries on the un-normalized string and then processes the normalized output, the safety guarantees of the filesystem driver are invalidated. This results in arbitrary file read and write operations depending on the downstream function executing the path.

Root Cause Analysis

The core issue is a validation-then-normalization vulnerability within the prefixPath method of src/fs/Local.php. When generating absolute file system paths, the application attempts to verify that the target path does not escape the storage volume root. This validation is delegated to Path::ensurePathIsContained(). Crucially, the application performs this validation check on the raw, uncanonicalized path input before any normalization takes place.

The helper method Path::ensurePathIsContained() calculates directory nesting levels by splitting the path into segments using standard separators (/ and \). It iterates through these segments, incrementing an integer counter for normal folders and decrementing it for parent directory markers (..). If this counter drops below zero, the method concludes that the path has traversed past the root directory and returns false. This simple state machine is effective for relative paths but fails when dealing with unexpected protocol prefixes.

When a path starts with a protocol scheme like file://, the validator splits the prefix into segments, such as file:. The validator treats file: as a regular subdirectory, which increments the internal depth counter. However, when the string is later processed by FileHelper::normalizePath(), a regular expression replaces the protocol prefix file:// with an empty string. The subsequent directory traversal segments (../) are then evaluated during the final canonicalization process, moving the directory depth higher than the root directory.

Because the protocol prefix artificially increases the validation depth, the directory traversal escapes the root directory without triggering the depth counter limit. The containment check succeeds, the protocol prefix is stripped during normalization, and the final absolute path resolved by the PHP engine points to local files outside the storage volume. This represents a classic validation bypass due to incorrect state tracking on desanitized parameters.

Code Analysis

To illustrate the vulnerability, we examine the original implementation of the prefixPath method in src/fs/Local.php before the patch:

protected function prefixPath(string $path = ''): string
{
    // Step 1: Validate containment on raw path input
    if (!Path::ensurePathIsContained($path)) {
        throw new FsException("The path `$path` is not contained.");
    }
 
    // Step 2: Normalize the path and append to the root directory
    return $this->getRootPath() . DIRECTORY_SEPARATOR . FileHelper::normalizePath($path);
}

The validator splits the input on forward and backward slashes. Consider the payload a/b/c/d/file://../../../../etc/passwd. The parsed segment list contains ['a', 'b', 'c', 'd', 'file:', '..', '..', '..', '..', 'etc', 'passwd']. The containment check processes these segments, raising the depth counter to five before encountering four parent directory indicators. The final depth counter never falls below zero, and validation succeeds. Next, the string is passed to FileHelper::normalizePath() which executes a regular expression clean-up:

public static function normalizePath($path, $ds = DIRECTORY_SEPARATOR): string
{
    // Strip file protocol wrappers
    $path = preg_replace('/^(file:\\/\\/)*/i', '', $path);
    ...
    $path = parent::normalizePath($path, $ds);
    return $path;
}

The regular expression strips out the file:// string, leaving a/b/c/d/../../../../etc/passwd. The underlying parent class resolves the parent directory markers, collapsing the string to ../etc/passwd. The function returns this relative path to prefixPath(), which concatenates it with the root path, producing /var/www/web/uploads/../etc/passwd. This path escapes the restricted boundary.

The vulnerability was corrected by changing the order of operations in src/fs/Local.php to ensure the input is normalized first:

protected function prefixPath(string $path = ''): string
{
    // Step 1: Normalize the path first
    $path = FileHelper::normalizePath($path);
 
    // Step 2: Perform containment checks on the normalized path
    if (!Path::ensurePathIsContained($path)) {
        throw new FsException("The path `$path` is not contained.");
    }
 
    // Step 3: Use the verified normalized path
    return $this->getRootPath() . DIRECTORY_SEPARATOR . $path;
}

In the patched version, the input a/b/c/d/file://../../../../etc/passwd is normalized to ../etc/passwd first. When passed to the validator, the initial segment .. immediately reduces the depth counter to -1, resulting in a validation failure and throwing an FsException. This fix is logically sound and completely addresses the desynchronization bug.

Exploitation Methodology

Exploitation of this vulnerability requires the attacker to have administrative or specific privileged access within Craft CMS. The attacker must target asset-management endpoints or configurations that accept user-controlled path parameters, such as the asset indexing tool or folders associated with local volumes. Because these tools translate user configurations into physical path resolutions, they act as the execution interface for the underlying filesystem driver.

To construct an exploit payload, the attacker must calculate the necessary depth of the target directory structure. If the volume root is located at /var/www/web/storage/user_uploads, the attacker needs to traverse four directory levels upward to reach the system root. To do this, the attacker creates a payload containing four directory padding segments, a file:// scheme, and four .. traversal sequences.

An example payload is formulated as follows:

folder1/folder2/folder3/folder4/file://../../../../etc/passwd

When processed by the vulnerable application, the validation function treats folder1 through folder4 and the file: segment as positive depth markers, keeping the overall state positive. After normalization, the padding folders are eliminated by the traversal sequences, leaving only the relative traversal to /etc/passwd. The application subsequently executes the file operation against the system file rather than a subdirectory of the volume root, exposing the target content to the administrative panel.

Security Impact Assessment

The concrete security impact of this vulnerability depends on the specific actions performed by the downstream components that call the local filesystem driver. If the path traversal is triggered within a read context, such as downloading or indexing assets, the attacker can read arbitrary files from the local filesystem that are readable by the PHP process. This includes administrative configurations, environmental files, database credentials, and system credentials.

In write contexts, such as renaming or moving files, the vulnerability could allow an attacker to overwrite system files or write files to writable web directories. An attacker could potentially upload a PHP web shell into the public web root by traversing out of the asset storage folder and writing into a publicly accessible directory. This turns the path traversal bypass into an arbitrary code execution vector.

This vulnerability is tracked under GitHub Security Advisory GHSA-7HXC-F267-H5Q7. The vendor has assigned a low-severity rating due to the prerequisite requirement of administrative privileges. However, in environments utilizing multi-tenant setups or delegated administration, this flaw represents an escalation path that compromises the host server. The estimated CVSS score is 4.9, with the vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N reflecting the high privilege requirement.

Detection & Remediation

Remediation requires upgrading Craft CMS core to a secure version. The development team has released patches for the affected branches. Organizations running Craft CMS 4.x must update to version 4.18.2 or later. Organizations running Craft CMS 5.x must update to version 5.10.6 or later. Upgrades are applied through PHP Composer by running the core package update command:

composer update craftcms/cms

To detect potential exploitation attempts, security operations teams should analyze server request logs and application error logs. Look for instances of administrative actions containing protocol indicators like file:// or file%3A%2F%2F in combination with directory traversal patterns like ../. Additionally, monitor application crash logs for craft\errors\FsException which indicate that a path containment validation failed.

System administrators should implement system-level hardening to limit the impact of directory traversal vulnerabilities. Ensure the web server and PHP-FPM processes run under a low-privileged dedicated user account. This user must be restricted from reading critical system files like /etc/passwd or accessing other directories outside of the active web root. Implementing restricted PHP configurations such as setting open_basedir can also prevent the PHP engine from accessing files outside specified paths.

Official Patches

Craft CMSPatch commit resolving GHSA-7HXC-F267-H5Q7 in Craft CMS 4.x
Craft CMSPatch commit resolving GHSA-7HXC-F267-H5Q7 in Craft CMS 5.x

Fix Analysis (2)

Technical Appendix

CVSS Score
4.9/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N

Affected Systems

Craft CMS 4.xCraft CMS 5.x

Affected Versions Detail

Product
Affected Versions
Fixed Version
Craft CMS
Craft CMS
>= 4.0.0, < 4.18.24.18.2
Craft CMS
Craft CMS
>= 5.0.0, < 5.10.65.10.6
AttributeDetail
CWE IDCWE-22
Attack VectorNetwork
CVSS Score4.9
Exploit StatusPoC available
CISA KEVNot Listed
Ransomware UseNo

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1005Data from Local System
Collection
T1556Modify Authentication Process
Defense Evasion
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The software uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize sequences such as '..' that can resolve to a location outside of the restricted directory.

Known Exploits & Detection

GitHub AdvisoryAdvisory containing conceptual proof of concept details for path containment bypass

Vulnerability Timeline

Security advisory published
2026-06-13
Patch released in Craft CMS 4.18.2 and 5.10.6
2026-06-13

References & Sources

  • [1]GitHub Advisory Database: GHSA-7HXC-F267-H5Q7
  • [2]Craft 4.x Fix Commit
  • [3]Craft 5.x Fix Commit
  • [4]Craft CMS 4.18.2 Release Notes
  • [5]Craft CMS 5.10.6 Release Notes

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.

More Reports

•8 minutes ago•CVE-2026-67434
7.3

CVE-2026-67434: OS Command Injection via Malicious Filenames in PHP_CodeSniffer Blame Reports

A critical OS command injection vulnerability exists in PHP_CodeSniffer's VCS blame report modules (Gitblame, Hgblame, Svnblame). Due to inadequate escaping of filenames passed to shell execution wrappers like popen(), an attacker who commits a file with a maliciously crafted name can execute arbitrary commands when the victim generates a blame report.

Alon Barad
Alon Barad
0 views•6 min read
•about 1 hour ago•GHSA-2RP4-X2J7-QMCC
8.2

GHSA-2RP4-X2J7-QMCC: Stored Cross-Site Scripting via Draft Names in Craft CMS Control Panel

An authenticated stored Cross-Site Scripting (XSS) vulnerability exists in the Control Panel helper of Craft CMS before version 5.10.8. Due to lack of HTML entity encoding within the elementLabelHtml method, unescaped draft names are rendered directly into administrative interfaces.

Amit Schendel
Amit Schendel
0 views•6 min read
•about 3 hours ago•GHSA-RVMM-V933-JGXQ
5.3

GHSA-rvmm-v933-jgxq: Missing Authorization Check in Craft CMS ChartsController

An authorization bypass vulnerability in Craft CMS allows unauthenticated or low-privileged users to query and obtain sensitive time-series user registration counts and demographic metrics. This is due to a missing authorization check inside the actionGetNewUsersData endpoint of the ChartsController class.

Alon Barad
Alon Barad
1 views•6 min read
•about 4 hours ago•GHSA-596P-6JV8-775V
5.1

GHSA-596p-6jv8-775v: Authenticated Leak of Secret Environment Variables in Craft CMS

An authenticated information disclosure vulnerability in Craft CMS allows high-privilege administrators to extract sensitive environment variables, including the CRAFT_SECURITY_KEY and database credentials, using a blind error-based template injection attack within element select condition rules.

Amit Schendel
Amit Schendel
3 views•5 min read
•about 5 hours ago•CVE-2026-71554
5.3

CVE-2026-71554: HTTP Request Smuggling via Duplicate Host Headers in h2 Protocol Stack

A protocol-parsing vulnerability in the pure-Python HTTP/2 library 'h2' (versions <= 4.4.0) allows unauthenticated remote attackers to perform HTTP Request Smuggling (CWE-444). The vulnerability exists because the library does not validate the uniqueness of 'Host' headers in incoming HTTP/2 request streams. When an upstream gateway parses such requests and downgrades them to HTTP/1.1 for internal backend servers, the resulting stream contains duplicate Host headers, which leads to parsing inconsistency and potential bypass of security filters.

Alon Barad
Alon Barad
3 views•5 min read
•about 6 hours ago•GHSA-957R-QF9P-67XW
4.9

GHSA-957R-QF9P-67XW: Arbitrary File Read via SplFileObject in Craft CMS Twig Extension

An information disclosure vulnerability in Craft CMS allows users with administrative or non-sandboxed template-authoring privileges to read arbitrary system and configuration files. The issue stems from an incomplete class instantiation blocklist in the Twig template extension, which omitted PHP's built-in SplFileObject class.

Alon Barad
Alon Barad
4 views•6 min read