Sep 18, 2026·4 min read·3 visits
Incomplete denylist validation of bare PHP functions in Grav Blueprints allows authenticated users to trigger arbitrary file writes and achieve remote code execution.
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.
Grav CMS relies on YAML configurations called Blueprints to dynamically define administration forms, page configurations, and data structures. To populate these structures with dynamic options, Blueprints use dynamic data directives indicated by an '@' suffix, such as 'data-options@'. These directives instruct the compiler to execute a designated callable using PHP's call_user_func_array function.\n\nBecause Blueprints can be altered by users with administrative or page-editing privileges, executing arbitrary PHP callables poses a direct security risk. Grav implements the Blueprint::isSafeDynamicCall method to validate and authorize dynamic callables before execution. In versions prior to 2.0.15, this safety mechanism was insufficient, allowing arbitrary function execution through unprotected call paths.
The primary defect resides in system/src/Grav/Common/Data/Blueprint.php within the isSafeDynamicCall method. While class method callables (e.g., Class::method) were constrained by a strict positive allowlist, bare string functions (e.g., 'system' or 'error_log') were checked against an incomplete denylist in Utils::isDangerousFunction.\n\nDenylists are architecturally prone to omission errors. In this implementation, dangerous built-in PHP functions like 'error_log' and 'stream_socket_client' were not registered within the denylist. Consequently, when an input specified 'error_log' as the dynamic function, the function returned true, designating the call as safe. This allowed unauthorized users to execute unrestricted administrative functions via the template processor.
Prior to version 2.0.15, the bare-function validation in system/src/Grav/Common/Data/Blueprint.php relied on checking whether a string function was registered in a list of dangerous functions:\n\nphp\n// Vulnerable Implementation\nif (is_string($function) && Utils::isDangerousFunction($function)) {\n return false;\n}\nreturn true;\n\n\nTo resolve this vulnerability in version 2.0.15, the developers removed the denylist model entirely and implemented a symmetrical allowlist-based verification. Bare functions must now be explicitly declared in the static allowlist array or registered by trusted plugins:\n\nphp\n// Patched Implementation (Commit d5f89d95d94cc155bc3be998ee85527a7be073dd)\nif (!is_string($function) || !isset(self::$allowedDynamicCallables[strtolower(ltrim($function, '\\'))])) {\n return false;\n}\n\n\nAdditionally, the patch introduced provenance-based trust. Blueprints compiled directly from local filesystem template files are marked as trusted and bypass certain allowlist restrictions. Blueprints derived from user-controlled page frontmatter are classified as untrusted, enforcing strict allowlist checks to block arbitrary call execution.
An attacker with page-editing or blueprint-configuration permissions can exploit this behavior by writing a crafted YAML payload into a page configuration or frontmatter section. The payload defines a dynamic directive pointing to 'error_log' and supplies arguments to trigger a file write. Because 'error_log' accepts a message, a message type, and a destination file path, it acts as an arbitrary file write primitive.\n\nyaml\nform:\n fields:\n exploit_field:\n type: text\n data-options@: ['error_log', ['<?php system($_GET["cmd"]); ?>', 3, 'user/pages/shell.php']]\n\n\nUpon receiving a request that triggers blueprint compilation, Grav parses the field and invokes error_log. The function creates the target PHP file 'user/pages/shell.php' inside a web-accessible directory. The attacker can then request this file directly to execute arbitrary operating system commands in the security context of the web server daemon.\n\nmermaid\ngraph LR\n A["Attacker Modifies Blueprint"] --> B["Grav Parses Blueprint Directive"]\n B --> C["isSafeDynamicCall Checks Bare Function"]\n C -->|"Bypasses Denylist"| D["call_user_func_array Executes error_log"]\n D --> E["PHP Payload Written to Disk"]\n
The vulnerability carries a CVSS base score of 8.8 (High) under CVSS v3.1, and 9.3 (Critical) under CVSS v4.0. Successful exploitation allows an authenticated user with low-level administrative or page-editing privileges to completely bypass intended access restrictions and execute arbitrary code on the hosting server.\n\nThis impact compromises host confidentiality, integrity, and availability. An attacker can read database credentials, exfiltrate sensitive application data, alter page content, or pivot laterally to other internal systems. This risk is particularly high in multi-tenant environments where page editors should not have server-level administrative access.
Remediation requires upgrading Grav Core to version 2.0.15 or higher. This release integrates the provenance-based trust engine and enforces the strict allowlist check for all dynamic callables.\n\nIf an immediate upgrade is not feasible, administrators should audit the filesystem for unauthorized dynamic directives. Inspect existing page frontmatter files for '@' characters combined with PHP system calls or raw string functions. Additionally, deploy web application firewall rules to block requests containing '@' suffixes in fields coupled with raw PHP function names.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Grav CMS Core getgrav | < 2.0.15 | 2.0.15 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-94 |
| Attack Vector | Network |
| CVSS v3.1 | 8.8 (High) |
| EPSS Score | 0.00777 |
| Exploit Status | PoC Verified |
| KEV Status | Not Listed |
The software constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes the input before it is executed.
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.
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.
CVE-2026-76461 is a critical, unauthenticated, remotely exploitable SQL Injection (SQLi) vulnerability in the email parsing engine of Cisco AsyncOS Software for Cisco Secure Email Gateway (SEG). An unauthenticated remote attacker can exploit this vulnerability by transmitting a specially crafted email message containing malicious SQL statements directly through an affected gateway.
CVE-2026-72819 is a high-severity Remote Code Execution (RCE) vulnerability in Grav CMS before version 2.0.13. The vulnerability lies in the validation of dynamic data providers (callbacks) within the Flex Objects plugin settings and blueprints, allowing administrative users to bypass validation checks via array-notation callables. This validation failure enables administrative users to execute arbitrary PHP classes and methods, including the GPM Installer unZip routine, leading to full remote code execution on the server.
Steeltoe, a popular framework for building cloud-native .NET applications, contains a critical data-exposure flaw in its HttpExchanges actuator endpoint before version 4.3.0. When explicitly configured to include query strings, the system records and stores sensitive values (such as OAuth tokens and credentials) in memory and application debug logs without sanitization, exposing them to unauthorized network actors.