CVE-2026-76901 Overview
CordysCRM is an open-source AI-powered customer relationship management (CRM) system supporting private deployment. CVE-2026-76901 is an Insecure Direct Object Reference (IDOR) vulnerability [CWE-639] affecting versions prior to 1.7.4. The flaw resides in the GET /pool/lead/get/{id} handler in PoolClueController.get and the GET /pool/account/get/{id} handler in PoolCustomerController.get. Both endpoints perform bare pool-read permission checks without the CsPermissionresourceId binding that enforces per-record data scope. Authenticated users holding the ordinary CLUE_MANAGEMENT_POOL:READ or CUSTOMER_MANAGEMENT_POOL:READ permission can supply another record's ID and retrieve leads or accounts owned by other users, departments, or organizations.
Critical Impact
Authenticated users can enumerate primary-key identifiers to disclose leads and accounts across tenant boundaries, exposing contact names, phone numbers, ownership attribution, and custom field values.
Affected Products
- CordysCRM versions prior to 1.7.4
- PoolClueControllerget endpoint (GET /pool/lead/get/{id})
- PoolCustomerControllerget endpoint (GET /pool/account/get/{id})
Discovery Timeline
- 2026-09-18 - CVE-2026-76901 published to the National Vulnerability Database
- 2026-09-24 - Last updated in NVD database
Technical Details for CVE-2026-76901
Vulnerability Analysis
The vulnerability is a broken object-level authorization flaw in CordysCRM's pool data retrieval endpoints. The affected controllers verify only that the caller holds the coarse-grained pool-read permission. They omit the CsPermissionresourceId binding responsible for enforcing per-record data scope. As a result, primary-key getter methods return any lead or account by ID without checking record ownership, department scope, or organization boundaries.
An attacker who owns even a single legitimate record can iterate numeric IDs to enumerate records owned by other users, departments, or organizations. Exposed fields include contact names, phone numbers, owner and department attribution, and custom field values. The vulnerability affects data confidentiality across tenant boundaries in shared deployments.
Root Cause
The root cause is missing authorization on primary-key lookups [CWE-639]. Method-level permission checks validate the caller's role but do not bind the request's id parameter to the record's owning scope. Without the resourceId binding, the ORM layer returns records regardless of whether the caller has legitimate access to that specific object.
Attack Vector
An authenticated user with CLUE_MANAGEMENT_POOL:READ or CUSTOMER_MANAGEMENT_POOL:READ sends a GET request to /pool/lead/get/{id} or /pool/account/get/{id}, substituting {id} with a target record identifier. The endpoint returns the full record payload without scope validation. Exploitation requires no elevated privileges and no user interaction.
// Patch excerpt from PoolClueService.java addressing pool permission handling
// Source: https://github.com/1Panel-dev/CordysCRM/commit/34c7c3e5de2585208744926007530037a4ce4da5
poolDTO.setUpdateUserName(userMap.get(pool.getUpdateUser()));
CluePoolPickRuleDTO pickRule = new CluePoolPickRuleDTO();
- BeanUtils.copyBean(pickRule, pickRuleMap.get(pool.getId()));
+ if (pickRuleMap.get(pool.getId()) != null) {
+ BeanUtils.copyBean(pickRule, pickRuleMap.get(pool.getId()));
+ }
+
CluePoolRecycleRuleDTO recycleRule = new CluePoolRecycleRuleDTO();
CluePoolRecycleRule cluePoolRecycleRule = recycleRuleMap.get(pool.getId());
- BeanUtils.copyBean(recycleRule, cluePoolRecycleRule);
- recycleRule.setConditions(JSON.parseArray(cluePoolRecycleRule.getCondition(), RuleConditionDTO.class));
+ if (cluePoolRecycleRule != null) {
+ BeanUtils.copyBean(recycleRule, cluePoolRecycleRule);
+ recycleRule.setConditions(JSON.parseArray(cluePoolRecycleRule.getCondition(), RuleConditionDTO.class));
+ }
poolDTO.setPickRule(pickRule);
poolDTO.setRecycleRule(recycleRule);
See the GitHub Security Advisory GHSA-hxp2-5w5p-2grq for full technical details.
Detection Methods for CVE-2026-76901
Indicators of Compromise
- Sequential or non-sequential enumeration of id values in requests to /pool/lead/get/{id} or /pool/account/get/{id} from a single authenticated session.
- Application access logs showing a user retrieving records whose owner or department attribution does not match the caller's scope.
- Elevated volumes of 2xx responses from the two affected endpoints for IDs outside the requestor's normal working set.
Detection Strategies
- Correlate authenticated session identifiers with the id path parameter and compare against each record's owner or department scope in the database.
- Baseline the number of unique pool record IDs each user accesses per hour and alert on statistical outliers.
- Deploy a web application firewall rule that flags rapid iteration of numeric IDs against the two vulnerable endpoints.
Monitoring Recommendations
- Enable verbose access logging on the CordysCRM API gateway with the authenticated user, endpoint, id parameter, and response size captured.
- Audit database query logs for pool_clue and pool_customer primary-key lookups that cross tenant or department boundaries.
- Retain application logs for a period sufficient to reconstruct enumeration attempts and support incident response.
How to Mitigate CVE-2026-76901
Immediate Actions Required
- Upgrade CordysCRM to version 1.7.4 or later, which restores the CsPermissionresourceId binding on the affected getters.
- Review recent access logs for /pool/lead/get/ and /pool/account/get/ for cross-scope retrievals and notify affected data owners as required.
- Rotate exposed contact data workflows and treat leaked phone numbers or custom fields as potentially compromised.
Patch Information
The fix is delivered in CordysCRM v1.7.4 via Pull Request #2976 and commit 34c7c3e. The patch enforces per-record scope on PoolClueController.get and PoolCustomerController.get and hardens the associated service layer against null rule references.
Workarounds
- Restrict the CLUE_MANAGEMENT_POOL:READ and CUSTOMER_MANAGEMENT_POOL:READ permissions to a minimal set of trusted users until the patch is applied.
- Place a reverse proxy or WAF rule in front of the two affected endpoints that rate-limits requests and blocks rapid ID enumeration per session.
- Segment multi-tenant deployments so that each department or organization runs against an isolated database schema until upgrade is complete.
# Upgrade CordysCRM to the patched release
git fetch --tags
git checkout v1.7.4
# Rebuild and redeploy according to your deployment method (Docker, Maven, etc.)
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
