CVE-2026-69089 Overview
CVE-2026-69089 is a path traversal vulnerability [CWE-22] in Grav CMS 2.0.10 that allows disclosure of arbitrary image files outside the application's media sandbox. The flaw resides in ImageMedium::watermark(), which forwards an unsanitized $image argument to RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator::findResource(). The file:// scheme branch collapses .. segments lexically without performing a realpath() containment check. An editor with Markdown authoring privileges can supply traversal sequences that cause the watermark routine to composite arbitrary image files into a carrier image, which Grav then caches and serves from a public, unauthenticated URL.
Critical Impact
Anonymous visitors can retrieve image files outside Grav's media directory through cached watermarked outputs served on public URLs.
Affected Products
- Grav CMS 2.0.10
- Grav CMS versions prior to 2.0.11
- Deployments exposing Markdown authoring to untrusted or low-privilege editors
Discovery Timeline
- 2026-08-03 - CVE-2026-69089 published to NVD
- 2026-08-03 - Last updated in NVD database
Technical Details for CVE-2026-69089
Vulnerability Analysis
Grav CMS is a flat-file PHP content management system that renders Markdown documents into HTML pages. The ImageMedium::watermark() method accepts an image path from Markdown image syntax and composites it as a watermark over a carrier image. Before opening the file, the resolver UniformResourceLocator::findResource() normalizes the requested path. When the input uses the file:// scheme, the resolver only performs a lexical collapse of .. segments and does not verify that the resolved absolute path remains inside the configured media roots.
An authenticated editor authoring Markdown can craft a watermark reference such as file://../../../../etc/hostname (or any readable file on disk) and cause Grav to read that file and paint it onto a public carrier image. The compositing output is written to Grav's image cache under a deterministic hashed name and served from an unauthenticated URL, effectively converting arbitrary file read into anonymous file disclosure.
Root Cause
The root cause is missing containment validation in the file:// branch of UniformResourceLocator::findResource(). Lexical .. collapse without a subsequent realpath() check against permitted base directories is a canonical path traversal pattern classified under CWE-22.
Attack Vector
The attack requires network access to the Grav administration interface and the ability to author or edit Markdown content. Once the malicious watermark is rendered, the cached output URL is retrievable by any anonymous visitor, so the disclosure itself does not require authentication.
// Patch metadata from system/defines.php
define("GRAV", true);
-define("GRAV_VERSION", "2.0.10");
+define("GRAV_VERSION", "2.0.11");
define("GRAV_SCHEMA", "1.8.0_2026-06-09_0");
define("GRAV_TESTING", false);
Source: Grav commit db8c1fcd
Detection Methods for CVE-2026-69089
Indicators of Compromise
- Markdown source containing  references with .. sequences or absolute filesystem paths
- Files present in images/ or cache/images/ whose visual content resembles system files, configuration data, or private assets
- Web server access logs showing anonymous GET requests to cached image URLs immediately after a content-edit session
- Editor audit logs recording page saves whose Markdown body references the file:// scheme
Detection Strategies
- Grep authored Markdown and page frontmatter for file:// schemes and ../ sequences in image references
- Inspect the Grav image cache directory for recently created composites that do not correspond to legitimate media assets
- Alert on filesystem reads from the PHP process targeting paths outside the Grav web root, such as /etc, /home, or application config directories
Monitoring Recommendations
- Enable and centrally collect Grav admin audit logs to attribute page edits to specific editor accounts
- Forward web server and PHP-FPM logs to a SIEM and correlate content-save events with subsequent cache-image URL fetches
- Track file access patterns of the PHP worker process and alert on reads outside user/pages, user/images, and other permitted media roots
How to Mitigate CVE-2026-69089
Immediate Actions Required
- Upgrade Grav CMS to version 2.0.11 or later, which contains the fix committed in db8c1fcd, b282200a, and c569a533
- Audit the editor role membership and remove Markdown authoring privileges from accounts that do not require them
- Purge the Grav image cache after upgrading to remove any previously generated disclosure artifacts
- Review recent page revisions for Markdown that references the file:// scheme and rotate any secrets that may have been disclosed
Patch Information
The fix ships in Grav 2.0.11. Relevant commits are b282200a, c569a533, and db8c1fcd. See the GitHub Security Advisory GHSA-w3f4-8pj2-599w and the VulnCheck advisory for coordinated disclosure details.
Workarounds
- Restrict the Grav admin panel to trusted networks using firewall or reverse-proxy access control lists until the patch is applied
- Configure the PHP worker to run under a user whose read access is limited to the Grav application tree, blocking traversal reads at the OS layer
- Deploy a web application firewall rule that blocks Markdown submissions containing file:// schemes or ../ sequences inside image syntax
# Verify the installed Grav version after upgrade
grep GRAV_VERSION system/defines.php
# Purge cached watermark composites
rm -rf cache/images/*
# Restrict filesystem exposure of the PHP-FPM user (example)
chown -R www-data:www-data /var/www/grav
find /var/www/grav -type d -exec chmod 750 {} \;
find /var/www/grav -type f -exec chmod 640 {} \;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

