قَالَ اللَّهُ تَعَالَى: {يَرْفَعِ اللَّهُ الَّذِينَ آمَنُوا مِنكُمْ وَالَّذِينَ أُوتُوا الْعِلْمَ دَرَجَاتٍ ۚ وَاللَّهُ بِمَا تَعْمَلُونَ خَبِيرٌ} (سورة المجادلة، الآية 11).
✍️ About Me
I'm Bassem (AKA. satan11), a bug bounty hunter and aspiring penetration tester. I publish real-world writeups to help others learn from the bugs I find in live programs.
📌 Summary
In this writeup, I break down a Broken Access Control vulnerability I discovered in a GraphQL API used by a major SaaS CRM platform. The bug allowed an authenticated user with View-Only privileges to leak internal employee data (names, emails, permissions) by abusing a GraphQL query.
The vulnerability stemmed from insufficient backend permission checks on a sensitive query (contacts_search
/ ListingLibCrmSearchQuery
), leading to PII exposure and potential internal mapping of roles and permissions — all without any elevated access.
⚙️ Severity:
Broken Access Control / Sensitive Data Exposure
🧑💼 Affected User Role:
Low-privilege user (View-Only
seat)
🧪 Technical Details & Steps to Reproduce
The issue was found in a GraphQL endpoint that failed to verify whether a user with minimal privileges should access internal CRM data.
✅ Steps to Reproduce
- Login with a View-Only user account. Navigating to the users page in the browser returns a restricted UI like this:

2. Send a Crafted Post Request to the GraphQL Endpoint:
POST /api/graphql/crm
Content-Type: application/json
Redacted-Csrf-Token: <ViewOnlyUserCsrfToken>
Cookies: sessiontoken=<ViewOnlyUserToken>; Redacted-Csrf-Token: <ViewOnlyUserCsrfToken>

Payload Used (redacted):
{
"operationName": "ListingLibCrmSearchQuery",
"variables": {
...
"objectTypeId": "0-115",
...
},
"query": "query ListingLibCrmSearchQuery(...) { ... }"
}
As you have seen in the response (Showed Above) this confirmed that the query bypassed privilege checks and returned sensitive information.
🔍 Data Exposed
The response revealed:
- First and Last Names
- Email addresses
- Internal role metadata
- User permission flags (view/edit/delete/communicate)
🎯 Impact
- PII Disclosure: Internal staff emails and names were exposed to low-privileged users.
- Reconnaissance: The data could help map internal org structure, aiding social engineering.
- Privilege Escalation Path Discovery: Attackers could analyze which users have elevated roles.
This violates the principle of least privilege and could have cascading effects if used creatively in a multi-stage attack.
🧩 Root Cause
The backend GraphQL resolver for ListingLibCrmSearchQuery
failed to:
- Enforce object-level authorization checks.
- Properly restrict sensitive fields based on the authenticated user's seat type.
- Scope queries to the appropriate dataset (e.g., only contacts the user should see).
Once Again this was triaged as Informative saying that accessing internal organization team data doesn't have any security impact:
