Sep 17, 2026·8 min read·35 visits
A missing security decorator in Grav's group blueprint allowed delegated admin users to assign themselves super-admin privileges, leading to potential remote code execution.
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.
The Grav Flat-File Content Management System (CMS) relies on YAML-based configurations known as blueprints to dynamically manage schemas, form structures, and access permissions. In Grav, administrative users are assigned various granular privileges, such as the ability to manage user accounts and groups (admin.users). This design allows for delegated administration where specific operators can handle lower-level user management tasks without obtaining full administrative control over the entire system.
CVE-2026-75837 identifies a critical flaw in how Grav handles privilege management within its user group configuration blueprints. Specifically, the core Flex group blueprint configuration file failed to declare appropriate security controls over its permission mapping field. Consequently, an administrative operator with delegated access can bypass intended privilege boundaries by directly injecting permissions into the group configuration.
This security vulnerability represents a classic privilege escalation scenario (CWE-269), wherein a low-privileged administrative user elevates their access level to that of a system-wide super-administrator (admin.super). Once an attacker achieves super-admin status, they can access sensitive features of the Grav administrative interface, such as custom Twig template rendering and task scheduling. These features can be exploited to execute arbitrary code on the underlying host, translating the privilege escalation into an interactive system compromise.
The underlying mechanism behind Grav's administrative security is the blueprint schema processor. When a form is submitted to modify user or group attributes, the backend engine processes the request using BlueprintSchema::filterArray(). This filtering step is responsible for validating, sanitizing, and casting input data before it is written to the flat-file database on the disk. To prevent unauthorized modifications, the engine relies on security decorators defined directly within the YAML blueprints.
During input processing, the schema engine executes Blueprint::dynamicSecurity(). This helper function evaluates security guards attached to individual fields. If a field configuration contains the property security@: admin.super, the dynamic security helper checks whether the currently authenticated user possesses the admin.super privilege. If the user does not have this privilege, the helper marks the field as validate.ignore. This instruction forces the validation engine to discard the field from the submitted input payload, rendering unauthorized modifications ineffective.
In versions of Grav prior to 2.0.14, the core blueprint for user groups (system/blueprints/user/group.yaml) omitted the security@: admin.super guard on the access field. Although the sibling blueprint for user accounts (account.yaml) correctly implemented this security restriction on its group and access fields, the group blueprint did not. The access field in group.yaml was configured with check_authorize: false, which only governed visualization rules within the administration panel's Twig templates and did not enforce server-side validation. Because the backend validation loop found no security decorator on the access property, it allowed the data to pass into the final configuration file unfiltered.
To understand how the flaw manifests, analyze the differences in blueprint definitions before and after the application of the official security patch. The vulnerable blueprint definition in system/blueprints/user/group.yaml was structured as follows:
access:
type: permissions
check_authorize: false
label: PLUGIN_ADMIN.PERMISSIONSIn this configuration, there is no server-side security constraint associated with the access property. An administrative user with the admin.users permission could manipulate the request payload to append arbitrary access fields. During execution, the following diagram illustrates how the request flows through the insecure pipeline:
To resolve this issue, the patch introduced in commit 5192316f5bf0f033636f43561829d7fc13a4ab64 inserts the security@ directive under the access block. Below is the updated and annotated blueprint configuration:
access:
# A group's access map is granted to every member, so writing it is a
# super-only capability — same as the account form's groups/access fields.
# `check_authorize` below only drives how the classic admin renders the
# permission rows; `security@` is what actually strips the field from a
# non-super's submitted data via Blueprint::dynamicSecurity(), so without
# it an `admin.users` operator could save `admin.super: true` onto a group
# they belong to and escalate. (GHSA-xhfv-7758-r9hx)
security@: admin.super
type: permissions
check_authorize: false
label: PLUGIN_ADMIN.PERMISSIONSWith this change, Blueprint::dynamicSecurity() detects the security@: admin.super property. When a user lacking the admin.super privilege submits a form containing group access modifications, the helper evaluates the restriction, identifies the missing privilege, and dynamically marks the access parameter as ignored. This prevents the unauthorized permissions from being written to disk, ensuring that non-super operators cannot elevate their status or that of any groups they control.
Exploitation of CVE-2026-75837 requires the attacker to have already acquired credentials or session access for an account with the admin.users permission. This permission allows the user to manage accounts and user groups. From this position, the attacker can leverage the missing validation check on group blueprints to escalate their privileges to super-admin.
First, the attacker identifies a group they belong to or creates a new group that they can assign to their own account. Using an HTTP interception proxy or by directly constructing a network request, the attacker triggers an update to the target user group. The request structure is modified to include the access[admin][super] parameter, mapping it to a value of true:
POST /admin/flex-objects/user-groups/ops HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Cookie: grav-admin-session=...
_csrf_token=1a2b3c4d5e...&groupname=ops&readableName=Operations&access%5Badmin%5D%5Bsuper%5D=trueWhen the Grav backend receives this payload, it processes the request and executes the blueprint validation. Since the system/blueprints/user/group.yaml file on the vulnerable server does not restrict the access field, the payload is successfully validated and written to the corresponding group configuration file on disk. The output file, typically stored at user/config/groups.yaml or within the flex directories, then contains the updated privilege map:
groupname: ops
readableName: Operations
access:
admin:
super: true
login: trueBecause the attacker is a member of the updated group, Grav dynamically merges the group permissions into the attacker's active session profile. This immediately elevates the attacker's privileges to admin.super. With super-admin privileges, the attacker gains the ability to execute administrative tasks, configure plugins, edit scheduled tasks, or exploit the built-in Twig template processor to execute arbitrary system commands on the hosting server.
The security impact of CVE-2026-75837 is classified as critical, receiving a CVSS v3.1 base score of 9.1 and a CVSS v4.0 score of 9.3. The primary driver of this high severity is the direct path from delegated administrative access to complete host compromise. By escalating privileges to admin.super, an attacker successfully bypasses the logical isolation of administrative roles within the CMS.
Once super-admin status is attained, the scope of the attack expands beyond the CMS itself. In a standard Grav deployment, a super-administrator can modify system configurations, manage file uploads, and define scheduled tasks. Additionally, the administrative interface allows the execution of Twig templates. Since Twig template processing can be leveraged to execute arbitrary PHP code, the privilege escalation directly leads to remote code execution (RCE) under the context of the web server user (e.g., www-data).
The vulnerability has an EPSS score of 0.00339, which indicates a low probability of immediate, automated exploitation in the wild, largely because exploitation requires pre-existing administrative credentials with the admin.users privilege. However, in enterprise environments or multi-tenant setups where administrative roles are strictly segregated, the vulnerability represents a significant risk, as it completely invalidates the security boundaries established between different administrative tiers.
The most effective remediation is upgrading the Grav installation to version 2.0.14 or later, which contains the official patch. The update modifies the default blueprint file for user groups to enforce proper security validations, preventing non-super administrators from submitting modified access maps.
If upgrading the entire CMS is not immediately possible due to production constraints, administrators can apply a manual hotfix. To do so, locate the file system/blueprints/user/group.yaml within the Grav installation directory. Open the file in a text editor, find the access field definition, and insert the security@: admin.super property. The modified section must match the following structure:
access:
security@: admin.super
type: permissions
check_authorize: false
label: PLUGIN_ADMIN.PERMISSIONSAfter saving the changes, clear the Grav cache to ensure the system compiles the updated blueprint definitions. This can be accomplished by executing the command bin/grav clear-cache via the command-line interface. Additionally, security teams should audit existing user and group configurations to identify unauthorized permissions. Inspect the files in user/config/groups.yaml and the flex objects directory for any instances of admin.super: true assigned to groups that are not intended to possess full administrative control.
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
grav getgrav | < 2.0.14 | 2.0.14 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-269 |
| Attack Vector | Network |
| CVSS v3.1 | 9.1 (Critical) |
| EPSS Score | 0.00339 (Percentile: 27.20%) |
| Exploit Status | PoC |
| KEV Status | Not Listed |
The software does not properly assign, modify, track, or validate privileges for an actor, creating opportunities for privilege escalation.
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.
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.
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).
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.
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.
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.