Sep 18, 2026·7 min read·3 visits
An authenticated path traversal vulnerability in Grav CMS before 2.0.16 allows media administrators to delete arbitrary files on the system by bypassing incomplete directory validation checks in the MediaUploadTrait.
A path traversal vulnerability exists in Grav CMS versions prior to 2.0.16. The flaw occurs within the file validation mechanisms of the MediaUploadTrait, enabling authenticated users with media management privileges to bypass sandbox limitations. This allows the deletion of arbitrary files on the filesystem, which can result in denial of service or remote code execution.
Grav CMS is a flat-file content management system that relies on structured filesystem directories rather than database backends. In versions prior to 2.0.16, the system handles media-related transactions via functions defined in the MediaUploadTrait class. These operations are exposed through the administrative panel and through custom third-party plugins implementing the MediaUploadInterface structure.
The core vulnerability is classified under CWE-22 (Improper Limitation of a Pathname to a Restricted Directory). The validation routines fail to neutralize directory traversal sequences in user-controlled file deletion parameters. An attacker can manipulate input values to escape the root directory configured for media files, allowing operations to interact with other filesystem areas.
Because the administrative control panel allows authenticated users to upload and manage media files, this vulnerability is accessible to users with media management privileges. Although upstream controllers sometimes sanitize file parameters, direct trait calls inside custom extensions and default administrative deletion actions lack validation containment.
This flaw allows authenticated users with media management permissions to delete system configuration files, environmental variables, or security policy definitions. Removing critical system configuration files like security.yaml or .htaccess can alter application security postures, leading to application denial of service or opening paths to execute arbitrary code.
The technical root cause of CVE-2026-72695 resides in system/src/Grav/Common/Media/Traits/MediaUploadTrait.php inside the deleteFile() method. This method accepts a user-controlled $filename string and attempts to validate it before initiating the filesystem deletion sequence.
To perform validation, the system utilizes the static method Utils::checkFilename() against the isolated filename. However, before the check is executed, the code uses a filesystem utility to extract the base name of the path:
$basename = $filesystem->basename($filename);
if (!Utils::checkFilename($basename)) {
throw new RuntimeException(...);
}If an attacker inputs a traversal string such as ../../../../config/security.yaml, the filesystem helper extracts only the last segment of the path, which is security.yaml. Because security.yaml contains no restricted directory traversal sequences or invalid characters, Utils::checkFilename() validates the string and returns true.
The critical error is that the original, unvalidated $filename variable containing the directory traversal sequence is preserved and used in the actual file system call. This path parameter is forwarded downstream to doRemove($filename, $path), where it is concatenated directly with the target media root path and processed using PHP's native unlink() function. The operating system resolves the traversal indicators, allowing the deletion of files outside of the media root.
The vulnerable code implementation of the deleteFile method processed user input with insufficient checks before performing file operations. Below is the vulnerable segment of code:
// Vulnerable implementation in MediaUploadTrait.php
public function deleteFile(string $filename, ?array $settings = null): void
{
$settings = $this->getUploadSettings($settings);
$filesystem = Filesystem::getInstance(false);
// The application extracts only the basename for validation
$basename = $filesystem->basename($filename);
if (!Utils::checkFilename($basename)) {
throw new RuntimeException($this->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': ' . $filename, 400);
}
$path = $settings['destination'] ?? $this->getPath();
// The original unsanitized $filename is passed directly to the deletion handler
$this->doRemove($filename, $path);
}To mitigate this issue, the patch introduced the checkFilepath() helper function. This function analyzes the full directory path to ensure that traversal operations are identified and rejected:
// Patched helper function in MediaUploadTrait.php
protected function checkFilepath(string $filename): bool
{
return $filename !== ''
&& strpbrk($filename, "\\\0") === false
&& !str_starts_with($filename, '/')
&& !in_array('..', explode('/', $filename), true);
}The helper performs four sequential validation operations on the input string:
strpbrk to block backslash characters and null byte injection attempts....The deleteFile() method was updated to implement this validation step, checking the integrity of both the path structure and the basename:
// Patched implementation in deleteFile()
$basename = $filesystem->basename($filename);
if (!$this->checkFilepath($filename) || !Utils::checkFilename($basename)) {
throw new RuntimeException($this->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': ' . $filename, 400);
}This implementation closes the validation gap. It ensures that any input containing traversal components is blocked before reaching the deletion mechanism. Similar checks were also applied to file upload and renaming pathways in the trait.
Exploitation of CVE-2026-72695 requires an authenticated user session with media management permissions. The attack cannot be carried out by unauthenticated users under default configurations. This limitation narrows the attack surface to malicious insiders or attackers who have compromised lower-privileged administrative accounts.
The attack begins when the threat actor identifies a media deletion API endpoint. Instead of providing a standard filename inside the target media folder, the attacker crafts an HTTP request containing relative path indicators. The payload targeting a configuration file looks like this:
POST /admin/media/delete HTTP/1.1
Host: target-grav-site.local
Content-Type: application/json
Authorization: Bearer <valid_token>
{
"filename": "../../../../user/config/security.yaml"
}When the backend processes this request, the vulnerable deleteFile method parses the payload. The extraction component isolates security.yaml and verifies its validity. The method then executes the file removal, causing PHP to resolve the relative traversal indicators relative to the media folder. This resolves to the absolute system path /var/www/html/user/config/security.yaml and deletes the file.
The physical delete operation succeeds because the web server daemon has write permissions on the flat-file configuration directories. The system configuration is deleted, leaving the application in an unconfigured state or disabling specific security controls.
The primary impact of this vulnerability is arbitrary file deletion on the target filesystem. Because Grav CMS uses configuration files to define permissions, routing, and access controls, the deletion of key configuration components can severely disrupt system operations.
Deleting files such as user/config/security.yaml removes defined security policies, which can result in privilege escalation or the bypass of administrative restrictions. If an attacker deletes access control configurations like .htaccess, the web server may expose internal directories or execute files that were previously restricted. This exposure can be leveraged to achieve remote code execution.
According to the Common Vulnerability Scoring System (CVSS v3.1), the vulnerability has a base score of 8.1. The vector string is CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H. This reflects high impacts on both integrity and availability, balanced by the requirement for authenticated low-privilege access.
The Exploit Prediction Scoring System (EPSS) score is 0.00567, indicating a relatively low near-term likelihood of active exploitation in the wild. This is due to the authentication requirement and the absence of publicly released weaponized exploitation frameworks.
The primary mitigation for this vulnerability is upgrading Grav CMS to version 2.0.16 or newer. The update incorporates the checkFilepath() validation helper across all media manipulation interfaces within MediaUploadTrait to prevent path traversal.
Administrators who cannot apply updates immediately should implement system-level mitigations. Directory and file permissions must be audited to ensure that the web server user does not have write access to critical configuration directories. This prevents the deletion of configuration files even if a path traversal bypass is attempted.
Web Application Firewall (WAF) rule sets can be deployed to monitor inbound traffic for traversal sequences. Filtering parameters for structures containing ../ or encoded variations like ..%2f directed toward media management paths can help block exploitation attempts.
Software developers working with similar systems should ensure that input validation is applied to full logical paths rather than isolated file components. Relying on basename extraction for validation is an insufficient control when the original, unsanitized input is passed to filesystem interfaces.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Grav CMS getgrav | < 2.0.16 | 2.0.16 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22: Improper Limitation of a Pathname to a Restricted Directory |
| Attack Vector | Network (Unauthenticated: No, Requires authenticated media management privileges) |
| CVSS v3.1 Score | 8.1 (High) |
| EPSS Score | 0.00567 (Percentile: 45.53%) |
| Impact | Arbitrary File Deletion / Denial of Service / Remote Code Execution |
| Exploit Status | Proof-of-Concept (PoC) |
| KEV Status | Not Listed in CISA KEV Catalog |
The product 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 directory.
A protocol-level validation bypass in CoreDNS versions prior to 1.14.7 allows unauthenticated remote attackers to proxy unauthorized DNS UPDATE messages (Opcode 5) using modern alternative transport layers such as DoH, DoH3, DoQ, and gRPC. If upstream authoritative servers trust the CoreDNS server's source IP and do not enforce TSIG authentication, attackers can inject, alter, or delete DNS zone records, leading to potential zone takeover or traffic redirection.
An unauthenticated directory traversal vulnerability exists in Grav CMS prior to version 2.0.15. Due to an insecure string-based containment check (str_starts_with) in the pre-boot static asset server, attackers can read files in sibling directories sharing a prefix with the configured asset path when plugin-asset-map.php is enabled.
CVE-2026-75828 is a critical stored cross-site scripting (XSS) vulnerability in the getgrav Grav CMS before version 2.0.15. The vulnerability resides in the detectXss() security filter mechanism, where parser-differential mismatches between the regular-expression-based server-side validation and browser HTML5 tokenization allow authenticated editors to bypass event-handler detection and inject arbitrary JavaScript execution vectors.
An arbitrary file write and remote code execution vulnerability exists in Grav CMS before version 2.0.15. The vulnerability is caused by using an incomplete denylist validation approach for bare PHP functions in the Blueprint dynamic-data compiler, allowing authenticated users with page-editing or blueprint-configuration privileges to execute arbitrary functions such as error_log.
CVE-2026-75834 is a stored Cross-Site Scripting (XSS) vulnerability in Grav CMS core, caused by a design flaw in its input validation wrapper Security::detectXss(). Regular expressions using the PCRE UTF-8 /u modifier fail-open when encountering invalid UTF-8 sequences or when the PCRE JIT stack limit is exhausted, allowing authenticated users with page-editing privileges to save malicious HTML and scripts.
CVE-2026-75837 is a critical privilege escalation vulnerability affecting the Grav Flat-File Content Management System (CMS) in versions prior to 2.0.14. Due to a missing security guard on the access field within the core Flex group blueprint configuration file (system/blueprints/user/group.yaml), a delegated administrative operator can submit a crafted payload to elevate their permissions to super-administrator, which can then be leveraged to achieve remote code execution.