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



CVE-2026-72819

CVE-2026-72819: Remote Code Execution in Grav CMS via Dynamic Callable Validation Bypass in Blueprint

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 17, 2026·9 min read·19 visits

Executive Summary (TL;DR)

Authenticated Remote Code Execution in Grav CMS before 2.0.13 via array-notation dynamic data providers.

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.

Vulnerability Overview

Grav CMS is a popular flat-file content management system written in PHP. The platform relies heavily on plugins and dynamic configuration files, known as blueprints, to render administrative forms and manage data objects. One of the core components facilitating structured content editing is the Flex Objects plugin. This plugin exposes an administrative interface that allows users to model and manipulate data fields based on YAML blueprint schemas.\n\nThe attack surface of concern involves the parsing of dynamic properties within these blueprints, specifically fields prefixed with data-*@. These fields allow forms to populate options or settings dynamically by executing specified PHP callables. To prevent malicious administrative users from executing arbitrary code, Grav CMS implements validation logic designed to restrict these dynamic calls to an approved set of safe methods.\n\nCVE-2026-72819 represents a critical bypass of this safety validation mechanism in the Blueprint class. By supplying the dynamic data provider as a PHP array rather than a standard string representation, an authenticated administrator can entirely evade validation checks. This bypass allows the direct execution of arbitrary PHP classes and methods available in the application scope, leading to unauthenticated remote code execution via local file upload mechanisms.\n\nThis vulnerability has been assigned CVSS base scores of 8.8 (CVSS v3.1) and 8.7 (CVSS v4.0), emphasizing its severity in compromised administrative contexts. The primary risk stems from the fact that administrative users, who are normally allowed to edit form designs, can abuse this privilege to gain underlying operating system shell access. Understanding the root cause requires a deep dive into how PHP handles dynamic callables and how the validation function processed them.

Root Cause Analysis

The root cause of CVE-2026-72819 lies in the discrepancy between how PHP identifies callable structures and how the validation function in Grav CMS parsed them. Prior to version 2.0.13, the Blueprint::isSafeDynamicCall() method, defined in system/src/Grav/Common/Data/Blueprint.php, was designed to inspect and sanitize any callback provided in blueprint configuration files. The method expected the callback to be represented as a scalar string, typically formatted with a scope resolution operator as Class::method.\n\nIf the input to the validation function matches this string format, the code performs strict validation. It evaluates whether the target class and method reside on a denylist or fall outside an allowed range of execution. However, PHP natively supports multiple representations of the callable type. Beyond the standard Class::method string representation, PHP permits callables to be structured as an array containing two elements: a class name or object at index 0, and a method name at index 1, such as [Class, method].\n\nWhen the validation engine encountered an array-based callback, the expression is_string($function) returned false. Consequently, the conditional block containing the validation, filtering, and denylist check was bypassed entirely. Because the validation routine did not explicitly reject array-based inputs, it defaulted to returning true, validating the call as safe. The unchecked callable array then reached the execution sink, call_user_func_array(), which correctly recognized the array structure as a valid callable and executed the target method on the server.\n\nThis flaw highlights a classic bug pattern where input validation logic is tightly coupled to specific data formats without accounting for alternative formats that the underlying runtime interpreter accepts. Because PHP's dynamic typing and flexible method invocation accept both string and array formats, validators must normalize all inputs to a uniform format before performing checks. Failing to do so allows alternative representations to slip past security filters while remaining fully executable by the engine.

Code Analysis

To understand the mechanics of the vulnerability, we must examine the vulnerable code path inside system/src/Grav/Common/Data/Blueprint.php alongside the patched implementation. In the vulnerable version, the signature of isSafeDynamicCall received the $function parameter, which could be either a string or an array depending on how it was declared in the YAML blueprint.\n\nThe following code block shows the vulnerable validation logic. Notice how it expects $function to be a string containing double colons, failing to handle array structures:\n\nphp\n// Vulnerable Implementation (system/src/Grav/Common/Data/Blueprint.php)\npublic static function isSafeDynamicCall($function, array $params): bool\n{\n // The routine checks if the function is a string and contains '::'\n if (is_string($function) && str_contains($function, '::')) {\n // Validation logic for Class::method goes here\n // If dangerous, this block returns false\n }\n\n // Bare functions are checked here\n if (is_string($function) && in_array($function, self::$dangerous_functions)) {\n return false;\n }\n\n // If $function is an array, both checks are skipped and true is returned\n return true;\n}\n\n\nIn the patched version (2.0.13), the developers resolved this issue by normalizing the array input before executing any safety checks. If $function is detected as an array containing exactly two elements, the code translates it into the standard string format Class::method and processes it normally.\n\nphp\n// Patched Implementation (system/src/Grav/Common/Data/Blueprint.php)\npublic static function isSafeDynamicCall($function, array $params): bool\n{\n // Normalise array-based callables to standard string representation\n if (is_array($function)) {\n if (count($function) === 2 && isset($function[0], $function[1])\n && is_string($function[0]) && is_string($function[1])) {\n $function = $function[0] . '::' . $function[1];\n } else {\n // Refuse any non-standard array structure immediately\n return false;\n }\n }\n\n // Now, array callables converted to strings are properly checked\n if (is_string($function) && str_contains($function, '::')) {\n // Regular validation logic handles the converted string\n }\n\n // Bare function validation remains unchanged\n return true;\n}\n\n\nThe code fix completely neutralizes the bypass by standardizing the array input format into a single representation before any verification happens. Any array that does not match the precise structure of an array-callable (exactly two elements, both of which are strings) is immediately rejected. This prevents arbitrary object instances or multi-element arrays from bypassing the validation logic, closing both the primary exploit vector and potential variants.

Exploitation Methodology

Exploiting CVE-2026-72819 requires an attacker to have authenticated access to the administrative dashboard with sufficient privileges to modify blueprints or settings configurations. The attacker first prepares a payload by compressing a PHP web shell inside a ZIP archive. This archive is uploaded to the server using any available page-media or asset-upload feature, storing the compressed payload in a known directory on the target filesystem.\n\nNext, the attacker modifies a settings or blueprint file using the array-based callable syntax to call the GPM Installer's extraction routine. The blueprint configuration points the dynamic data provider to Grav\Common\GPM\Installer::unZip. The parameter list supplied within the blueprint dictates the source ZIP file and the destination directory, which is set to the web root.\n\nyaml\n# Example YAML payload targeting a blueprint field\nvulnerable_field:\n type: select\n data-options@: [\n ['Grav\\Common\\GPM\\Installer', 'unZip'],\n ['user/pages/01.home/payload.zip', './']\n ]\n\n\nOnce the modified blueprint is loaded or saved, the administrative backend parses the configuration. The application passes the array structure ['Grav\Common\GPM\Installer', 'unZip'] to the isSafeDynamicCall method. Because the validation is bypassed, the application proceeds to execute call_user_func_array(). This extracts the uploaded ZIP file to the web root, exposing the PHP shell for direct access via the web browser.\n\nThe following execution flow diagram details the sequence from user submission of the malicious blueprint through validation bypass to arbitrary code execution:\n\nmermaid\ngraph LR\n subgraph Client ["Client Side"]\n A["YAML Payload with Array Callable"]\n end\n subgraph Server ["Server Side Processing"]\n B["Blueprint::isSafeDynamicCall()"]\n C{"Is String?"}\n D["Validation Skipped"]\n E["call_user_func_array()"]\n F["GPM\\Installer::unZip()"]\n G["Web Root (shell.php)"]\n end\n A --> B\n B --> C\n C -- No --> D\n D --> E\n E --> F\n F --> G\n

Impact Assessment

The security impact of CVE-2026-72819 is classified as high, carrying a CVSS base score of 8.8 (NVD CVSS v3.1). The vulnerability allows full remote code execution in the security context of the web server daemon. An attacker who successfully executes arbitrary PHP code can read, write, or delete files across the application directory, access database credentials, and potentially pivot to other internal services.\n\nAlthough the vulnerability requires authentication, administrative access is a common prerequisite in modern web environments. The exploitability remains high because the payload uses built-in administrative features and standard PHP behaviors, requiring no external compiled dependencies. This increases the threat profile of the vulnerability, particularly in multi-author sites or where administrative access can be obtained via session hijacking or cross-site scripting (XSS).\n\nThis flaw illustrates the risk of partial validation in dynamic languages. When input validation is decoupled from the actual execution sink, minor syntactic variations can bypass security layers entirely. Organizations using Grav CMS must recognize that any user with access to form configurations can escalate their privileges to complete system compromise if the system is left unpatched.\n\nIn addition to direct remote code execution, the ability to write files to arbitrary locations on the server has long-term implications. Threat actors could plant persistent web shells, modify core application logic to intercept user credentials, or deploy ransomware across the hosting environment. Because the exploit runs under the web server's service account, any file writable by the server is vulnerable to modification or disclosure.

Remediation & Defense

The definitive solution for CVE-2026-72819 is upgrading Grav CMS to version 2.0.13 or later. This version incorporates the patch in the Blueprint class, ensuring that all array-based callables are properly normalized and vetted against safety denylists. Administrators should coordinate with their system operators to apply this update immediately, verifying that permissions on the update directory are correctly configured.\n\nIf upgrading is not immediately possible, several defensive mitigations can be deployed to reduce the risk of exploitation. Access to the Grav admin panel should be restricted to trusted IP addresses or placed behind a virtual private network (VPN). Additionally, file-system permissions should be hardened to ensure the web server user cannot write directly to the web root or executable directories, blocking the extraction phase of the exploit.\n\nA Web Application Firewall (WAF) can also be configured to inspect incoming administrative requests. Rules should target request bodies containing YAML array structures associated with dynamic attributes like data-*@ combined with sensitive PHP classes such as GPM\Installer or extraction functions. Security teams are advised to scan existing blueprint configuration files for any unauthorized array-formatted callback registrations.\n\nFinally, organizations should implement routine file integrity monitoring (FIM) and log analysis. File integrity checks can identify anomalous file additions, particularly within the root directory and the public assets folder. Reviewing administrative activity logs for unexpected updates to blueprint schemas or configuration files provides early detection of potential exploitation attempts prior to the execution of arbitrary payloads.

Official Patches

getgravUnified diff patch for Blueprint validation bypass

Fix Analysis (1)

Technical Appendix

CVSS Score
8.8/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
0.50%
Top 58% most exploited

Affected Systems

Grav CMS

Affected Versions Detail

Product
Affected Versions
Fixed Version
Grav CMS
getgrav
< 2.0.132.0.13
AttributeDetail
Vulnerability IDCVE-2026-72819
CWE IDCWE-94
CVSS v3.1 Score8.8 (High)
Exploit StatusProof of Concept (PoC) verified
Affected ComponentBlueprint Dynamic Callables
RemediationUpgrade to version 2.0.13

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1203Exploitation for Client Execution
Execution
CWE-94
Improper Control of Generation of Code ('Code Injection')

The product 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 the code segment is executed.

Known Exploits & Detection

GitHub Security AdvisoryAdvisory documenting technical reproduction steps and exploitation methodology

Vulnerability Timeline

Official patch committed to Grav CMS repository
2026-07-25
Public disclosure of vulnerability and CVE-2026-72819
2026-08-14
Release of Grav CMS v2.0.13 containing the fix
2026-08-14

References & Sources

  • [1]GitHub Security Advisory GHSA-r94f-hx44-8jqf
  • [2]Fix Commit 81740e23614c3f3f520dbd8dc7a7af21efd0b747

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

•1 day ago•CVE-2026-118777
4.8

CVE-2026-118777: Prototype Pollution in Forge HTTP Client Cookie Management

CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.

Amit Schendel
Amit Schendel
7 views•10 min read
•1 day ago•CVE-2026-118775
3.7

CVE-2026-118775: ASN.1 OID First Arc Truncation and Ambiguity in node-forge

CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.

Amit Schendel
Amit Schendel
8 views•10 min read
•1 day ago•CVE-2026-119194
7.5

CVE-2026-119194: Algorithmic Complexity Denial of Service in pyasn1 Schemaless ASN.1 Decoder

CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).

Alon Barad
Alon Barad
7 views•9 min read
•1 day ago•CVE-2026-119195
7.5

CVE-2026-119195: Quadratic-Time Denial of Service in pyasn1 BER/CER/DER Decoders

CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.

Amit Schendel
Amit Schendel
8 views•10 min read
•1 day ago•CVE-2026-119197
7.5

CVE-2026-119197: Quadratic Algorithmic Complexity Denial of Service in pyasn1 REAL Mantissa Decoder

An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.

Amit Schendel
Amit Schendel
7 views•10 min read
•1 day ago•CVE-2026-119196
7.5

CVE-2026-119196: Quadratic CPU Consumption in pyasn1 Constructed BIT STRING Decoding

A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.

Alon Barad
Alon Barad
8 views•10 min read