Skip to main content
Back to Blog
Case StudiesSaaS Penetration Testing 14 min read July 18, 2026 Haider Amin

SaaS Penetration Testing Case Study: Preventing Cross-Tenant Data Exposure

How a manual SaaS penetration test uncovered cross-tenant object access, invitation-based privilege escalation, and excessive API data exposure before enterprise launch.

Tenant Isolation BoundarySLS · Anonymized Client Engagement
Tenant A

Standard user submits an authenticated request with a modified object identifier.

MALICIOUS PATH
Authorization Layer
Tenant-aware policy
Denied
Tenant B

Records, users, files and billing data remain isolated from other tenants.

PROTECTED
Contents

01

Executive summary

A growing B2B SaaS platform was preparing to onboard larger customers and undergo more demanding security reviews. The application used a shared multi-tenant architecture: several customer organizations operated on the same platform, while logical controls were expected to keep each tenant's users, records, files, billing data, and administrative functions isolated.

Stealth Layer Security performed an authorized grey-box assessment of the web application and supporting REST APIs. The objective was to determine whether a valid customer account could cross tenant boundaries, access another organization's objects, obtain elevated permissions, or receive sensitive properties that were not required for its role.

Manual testing identified three verified weaknesses. The most serious issue allowed a standard authenticated user to request an object belonging to another tenant by changing an identifier in an API request. A second weakness allowed the role associated with an invitation to be influenced by a client-controlled value. A third issue caused profile endpoints to return internal properties that were unnecessary for ordinary users.

The assessment converted these weaknesses into reproducible evidence, business-impact analysis, engineering guidance, and targeted retesting. After remediation, affected object requests were bound to the authenticated tenant, invitation roles were enforced server-side, and API responses were restricted through explicit schemas.

02

At a glance

Assessment typeAuthorized grey-box SaaS web and API penetration test
Primary concernMulti-tenant isolation and authorization
Verified findingsTwo High, one Medium
Primary frameworksOWASP Web Security Testing Guide, OWASP Top 10, OWASP API Security Top 10
OutcomeTenant-aware authorization controls implemented and affected paths retested
3
Verified findings
2 High
Cross-tenant + escalation
1 Medium
Excessive data exposure
Grey-Box
SaaS web & API test

03

Why tenant isolation matters

In a multi-tenant SaaS platform, several customers use the same application and often the same underlying service tier. Isolation is therefore not achieved simply because each customer sees a different dashboard. The server must enforce ownership and authorization whenever a user requests an object, invokes a function, changes a role, accesses a file, or performs an administrative action.

Authentication answers, “Who is making this request?” Authorization must separately answer, “Is this user permitted to perform this action on this specific object inside this specific tenant?” A platform can have strong passwords, multi-factor authentication, and secure sessions while still exposing customer data if the object-level authorization decision is incomplete.

04

Environment reviewed

The assessed environment included:

  • A multi-tenant B2B SaaS web application
  • REST APIs used by the browser client
  • Organization-based accounts and memberships
  • Standard user, manager, and organization administrator roles
  • Customer records, documents, invoices, and account settings
  • Invitation and account activation workflows
  • File upload and download functions
  • Administrative user-management functions
  • A dedicated staging environment with test accounts

05

Assessment objectives

The engagement was designed to answer practical buyer and engineering questions:

  • Can one tenant access another tenant's records?
  • Can a lower-privileged user invoke administrative functions?
  • Are object and property permissions checked server-side?
  • Can invitation, onboarding, or role workflows be manipulated?
  • Do APIs expose more data than the interface requires?
  • Are authorization decisions applied consistently across similar endpoints?
  • Can the engineering team reproduce and verify every finding?

06

Methodology

Testing combined structured coverage with manual validation. Automated tooling supported discovery and request handling, but findings were not reported until the behavior had been reproduced and its impact confirmed.

Coverage included

  • Application and API attack-surface mapping
  • Authentication and session review
  • Horizontal authorization testing between users at the same privilege level
  • Vertical authorization testing between standard and administrative roles
  • Object-level authorization testing across tenant-owned resources
  • Property-level authorization and excessive data exposure review
  • Business-logic testing of invitations and membership changes
  • File and document access-control testing
  • Negative testing using valid accounts that should not have access
  • Evidence capture, severity analysis, remediation guidance, and retesting

The assessment was aligned with the OWASP Web Security Testing Guide's authorization-testing practices, the OWASP Top 10 category for Broken Access Control, and the OWASP API Security Top 10 categories for Broken Object Level Authorization and Broken Object Property Level Authorization. For scoping practices, see our methodology.

07

Finding 1 — Cross-tenant record access

HIGH Broken Object Level Authorization Customer invoice API

What was observed

A standard user from Tenant A could retrieve an invoice object belonging to Tenant B by changing the invoice identifier in a legitimate API request. The endpoint verified that the request contained a valid session but did not consistently verify that the requested invoice belonged to the same tenant as the authenticated user.

Anonymized requestAnonymized / Reconstructed
GET /api/v1/invoices/inv_8F42C1
Authorization: Bearer <standard-user-token>

The user first requested an invoice belonging to their own tenant. The identifier was then replaced with another valid identifier discovered through a separate workflow. The server returned HTTP 200 and included the foreign invoice object.

Anonymized response fieldsAnonymized / Reconstructed
{
  "invoiceId": "inv_8F42C1",
  "organizationId": "org_B7C21",
  "customerName": "Example Customer",
  "billingReference": "BR-10482",
  "status": "paid",
  "total": "[redacted]"
}

Why the control failed

The data lookup was effectively based on the supplied invoice ID alone. The backend checked whether the user was authenticated, but the query was not consistently constrained by the authenticated tenant. This created a gap between identity validation and object ownership validation.

Business impact

A normal customer account could potentially access another organization's commercial information. Depending on the affected object type, the same authorization pattern could expose customer records, documents, account references, workflow metadata, or other tenant-owned data.

For a SaaS vendor, the impact extends beyond the individual record. Cross-tenant exposure can undermine enterprise onboarding, customer trust, contractual security commitments, incident-response obligations, and evidence presented during security reviews.

Remediation

  • Derive tenant context from the authenticated session or trusted server-side membership record.
  • Constrain every object query by both the object identifier and the authenticated tenant identifier.
  • Apply deny-by-default authorization policies.
  • Centralize authorization logic instead of duplicating checks in individual controllers.
  • Test all endpoints that accept object identifiers, including export, download, update, delete, and nested-resource routes.
  • Add automated negative tests that attempt cross-tenant access with valid user sessions.
  • Log denied cross-tenant requests as security-relevant events.
Secure query patternAnonymized / Reconstructed
SELECT * FROM invoices
WHERE invoice_id = :invoice_id
  AND tenant_id = :authenticated_tenant_id;
Before — Vulnerable
  1. 1Client sends object ID
  2. 2API verifies session only
  3. 3Query uses supplied ID alone
  4. 4Database returns any matching record
  5. 5Cross-tenant object exposed
After — Tenant-Aware
  1. 1Client sends object ID
  2. 2Tenant derived from authenticated membership
  3. 3Policy binds identity + tenant + object + action
  4. 4Query constrained by tenant_id
  5. 5Only authorized tenant records returned

08

Finding 2 — Privilege escalation through invitation workflow

HIGH Business-logic weakness Invitation acceptance

What was observed

The invitation acceptance request contained a role property controlled by the client. A user invited as a restricted member could alter the request and submit an organization-administrator role. The server validated the invitation token but trusted the modified role value instead of enforcing the role stored when the invitation was created.

Anonymized requestAnonymized / Reconstructed
POST /api/v1/invitations/accept
Content-Type: application/json

{
  "invitationToken": "<valid-token>",
  "requestedRole": "organization_admin"
}

Why the control failed

The invitation token established that an invitation existed, but it did not make every property in the acceptance request trustworthy. The authorized role should have been an immutable server-side attribute bound to the invitation record.

Business impact

Successful exploitation could allow a newly invited user to gain administrative functions such as user management, tenant configuration, data export, integration settings, or access to organization-wide records. In practice, this could turn a normal onboarding workflow into an administrative takeover path.

Remediation

  • Store the tenant, recipient, authorized role, issuer, expiration, and status in one server-side invitation record.
  • Ignore client-supplied privilege attributes during acceptance.
  • Enforce single use and expiration.
  • Verify that the authenticated recipient matches the invitation where appropriate.
  • Require step-up authentication for sensitive administrative changes.
  • Record invitation issuance, acceptance, role assignment, and privilege changes in the audit log.
  • Add negative tests for role tampering and replay.

09

Finding 3 — Excessive API data exposure

MEDIUM Broken Object Property Level Authorization Profile endpoints

What was observed

A standard user profile endpoint returned internal properties not required by the interface. The response included tenant identifiers, internal account-state values, workflow flags, and administrative metadata.

Why the control failed

The API serialized a broad internal model rather than using an explicit response schema for the requesting role. Although the user was permitted to retrieve the profile object, they were not necessarily entitled to every property on that object.

Business impact

Excessive properties can reveal internal structure, enable more precise enumeration, expose sensitive state, and provide useful context for chaining other authorization weaknesses. The risk increases when administrative flags, internal identifiers, integration references, or security-relevant status fields are included.

Remediation

  • Define explicit response schemas for each role and use case.
  • Return only properties required by the client.
  • Separate administrative and standard-user serializers.
  • Apply property-level authorization where the same object has role-dependent fields.
  • Include response-contract tests in the API test suite.
  • Review GraphQL selections, bulk endpoints, exports, and mobile APIs for equivalent exposure.

10

Attack chain

  1. The attacker registers or uses a legitimate standard SaaS account.
  2. The attacker captures an API request for an object owned by their tenant.
  3. The object identifier is changed to a valid identifier associated with another tenant.
  4. The API verifies the session but omits the tenant-ownership decision.
  5. The foreign object is returned.
  6. Additional endpoints are tested to determine whether the same authorization pattern is systemic.
Attack PathSLS · Anonymized Client Engagement
Authenticated User
Standard tenant account
Object ID Modified
Client-controlled value
API Verifies Login
Session only
Tenant Check Missing
Authorization gap
Foreign Record Returned
Cross-tenant exposure

11

Risk analysis

The primary severity was rated High because exploitation required only a valid low-privileged account and a controllable object reference. No administrative access, malware, or infrastructure compromise was required. The exposed boundary was also fundamental to the SaaS trust model: separation between paying customer organizations.

Severity considered

  • Required privileges
  • Exploit complexity
  • Sensitivity of exposed objects
  • Potential number of affected tenants
  • Repeatability across endpoints
  • Detectability through existing logs
  • Effect on enterprise and compliance commitments

12

Business impact

Customer trust

Customers expect the SaaS provider to prevent one organization from accessing another organization's data. A failure at this boundary can become a material trust event even when the exposed record set is limited.

Enterprise onboarding

Larger buyers commonly ask how tenant isolation is enforced and tested. Reproducible authorization evidence and retesting results give the vendor a stronger, more defensible answer than a general claim that the platform is secure.

Security and compliance readiness

A penetration test does not itself create compliance, but the findings and remediation evidence can support risk-management, control-validation, and customer-assurance activities. The value comes from showing that critical access paths were independently challenged and corrected.

Engineering confidence

The report gave developers concrete request examples, affected endpoints, root-cause analysis, secure query patterns, and negative test cases. That reduces ambiguity and makes remediation easier to verify. A comparable example of evidence depth is available in our sample report.

13

Remediation program

The product team addressed the findings through four coordinated changes.

1. Centralized tenant-aware authorization

A shared policy layer derived the tenant from the authenticated membership and enforced ownership before object access.

2. Server-controlled privilege assignment

Invitation roles were removed from the trusted client input and bound to the server-side invitation record.

3. Explicit response schemas

API responses were separated by role and business purpose. Internal model fields were not serialized by default.

4. Negative authorization testing

The engineering test suite added cases in which valid users attempted to access foreign-tenant objects, administrative functions, and restricted properties.

Engagement TimelineSLS · Anonymized Client Engagement
Step 1
Scope & authorization
Written approval
Step 2
Attack-surface mapping
Web + API
Step 3
Manual assessment
Role-aware testing
Step 4
Validation
Reproducible evidence
Step 5
Evidence-grade reporting
Impact + remediation
Step 6
Debrief
Engineering walkthrough
Step 7
Remediation support
Guidance on fixes
Step 8
Retesting
Targeted verification

14

Retesting

Targeted retesting covered the original proof paths and adjacent endpoints with similar behavior.

The retest confirmed

  • Foreign-tenant invoice requests returned a consistent denial response.
  • Object queries were constrained by authenticated tenant context.
  • Invitation acceptance ignored modified role properties.
  • Replayed and expired invitation tokens were rejected.
  • Standard profile responses no longer included restricted internal properties.
  • Relevant denial and privilege-change events appeared in audit logs.

15

Key lessons for SaaS teams

  1. Authentication is not tenant isolation. A valid session proves identity, not ownership of the requested object.
  2. Every object route needs an authorization decision. Read, update, delete, export, download, search, nested, and bulk endpoints can fail differently.
  3. Client-controlled roles are untrusted input. Privilege must be derived from server-side state.
  4. Data minimization belongs in API design. Returning an entire model and hiding fields in the interface is not an authorization control.
  5. Negative tests are essential. Test what a valid user must not be able to do, not only what the user should be able to do.
  6. Multi-tenant authorization should be centralized. A shared policy layer reduces inconsistent checks and makes the control easier to audit.

16

Conclusion

The assessment demonstrated how a seemingly small authorization inconsistency could undermine the central security promise of a multi-tenant SaaS platform. The issue was not a failure to authenticate users. It was a failure to bind authenticated identity, tenant membership, requested object, and permitted action into one enforceable server-side decision.

By validating the behavior manually, documenting the exploit path, and retesting the remediation, the engagement gave the product team evidence it could use with engineering leadership, enterprise buyers, and internal risk stakeholders.