Tenant Isolation Failures

Multi-TenancyTenant IsolationCross-Tenant Access

Tenant Isolation Failures at a glance

What it is: Failures in multi-tenant SaaS applications that allow data or operations from one tenant to leak into another tenant's context, compromising data isolation.
Why it happens: Exposes sensitive customer data across organizational boundaries
How to fix: Always scope queries by tenant ID from authenticated context; Implement tenant-aware caching with isolation; Use tenant-specific encryption keys; Add automated tests for cross-tenant access attempts

Overview

Tenant isolation failures occur in multi-tenant SaaS applications when data or operations meant for one customer (tenant) are accessible to another. This is particularly critical because a single vulnerability can simultaneously compromise multiple customers' data.

Common failures include queries not scoped to tenant ID, shared caching without tenant context, background jobs processing data across tenant boundaries, and API responses including data from multiple tenants. Proper tenant isolation requires consistent enforcement at every layer: database queries, cache keys, job queues, and API responses.

sequenceDiagram participant TenantA as Tenant A User participant App as Application participant Cache participant DB TenantA->>App: GET /api/users App->>Cache: Check cache key 'users_list' Cache-->>App: Cached data (from Tenant B!) App-->>TenantA: 200 OK (Tenant B's users) Note over Cache: Missing: Tenant-aware cache keys
A potential flow for a Tenant Isolation Failures exploit

Where it occurs

Tenant isolation issues arise from database queries not filtered by tenant_id, cache keys not including tenant context, shared resources (queues, sessions) mixing tenant data, background jobs not preserving tenant context, and admin interfaces allowing cross-tenant operations without proper checks.

Impact

Tenant isolation failures lead to exposure of customer data to competitors, compliance violations under GDPR/HIPAA/SOC2, loss of customer trust and contract terminations, legal liability from data breaches, and reputational damage affecting the entire customer base. A single tenant isolation bug can compromise the entire SaaS business model.

Prevention

Implement tenant ID scoping at the ORM level with default scopes or query interceptors. Include tenant context in all cache keys. Use tenant-aware connection pools or database schemas. Preserve tenant context across asynchronous operations. Implement comprehensive testing for cross-tenant access attempts. Add monitoring and alerting for cross-tenant queries. Use row-level security in databases where available.

Examples

Switch tabs to view language/framework variants.

Database queries missing tenant scoping allow cross-tenant access

Queries don't filter by tenant_id enabling data access across tenants.

Vulnerable
JavaScript • Express + Sequelize — Bad
const express = require('express');
const { Customer } = require('./models');

const app = express();

app.get('/customers', async (req, res) => {
    // BUG: No tenant_id filter
    const customers = await Customer.findAll();
    res.json(customers);
});
  • Line 8: No tenant filtering

Missing tenant filters in queries expose data across tenant boundaries.

Secure
JavaScript • Express + Sequelize — Good
const express = require('express');
const { Customer } = require('./models');

const app = express();

// Middleware to validate tenant
app.use((req, res, next) => {
    req.tenantId = validateTenant(req.headers['x-tenant-id'], req.user);
    if (!req.tenantId) return res.status(403).json({ error: 'Invalid tenant' });
    next();
});

app.get('/customers', async (req, res) => {
    // Always filter by tenant
    const customers = await Customer.findAll({
        where: { tenant_id: req.tenantId }
    });
    res.json(customers);
});
  • Line 7: Tenant validation middleware
  • Line 15: Tenant scoping on all queries

Always filter queries by tenant_id and validate tenant in middleware.

Engineer Checklist

  • Scope all database queries by tenant_id from authenticated context

  • Include tenant_id in all cache keys

  • Use tenant-aware connection pools or schemas

  • Preserve tenant context in background jobs and async operations

  • Implement default tenant scoping at ORM level

  • Add automated tests for cross-tenant access attempts

  • Monitor queries for missing tenant filters

  • Use row-level security policies where available

  • Validate tenant_id cannot be manipulated by users

  • Audit admin interfaces for cross-tenant operations

End-to-End Example

A SaaS application allows users from Company A to view data belonging to Company B due to missing tenant scoping.

Vulnerable
JAVASCRIPT
// Vulnerable: No tenant scoping in query
const express = require('express');
const { Customer } = require('./models');

app.get('/api/customers', authenticateUser, async (req, res) => {
  // User is authenticated, but query not scoped to their tenant!
  const customers = await Customer.findAll();
  
  return res.json(customers);
});
Secure
JAVASCRIPT
// Secure: Always scope queries by tenant_id
const express = require('express');
const { Customer } = require('./models');

app.get('/api/customers', authenticateUser, async (req, res) => {
  const tenantId = req.user.tenantId;
  
  // Query explicitly filtered by authenticated user's tenant
  const customers = await Customer.findAll({
    where: {
      tenant_id: tenantId
    }
  });
  
  return res.json(customers);
});

// Alternative: Use Sequelize default scope
Customer.addScope('defaultScope', {
  where: {
    tenant_id: getCurrentTenantId()
  }
}, { override: true });

Discovery

Test if tenant identifiers can be manipulated to access data belonging to other tenants in multi-tenant applications.

  1. 1. Enumerate tenant ID format

    http

    Action

    Access own tenant data to understand ID format and structure

    Request

    GET https://api.example.com/api/customers
    Headers:
    Authorization: Bearer tenant-acme-token
    X-Tenant-ID: acme-corp

    Response

    Status: 200
    Body:
    [
      {
        "id": 1001,
        "name": "John Doe",
        "email": "john@acme-corp.com"
      },
      {
        "id": 1002,
        "name": "Jane Smith",
        "email": "jane@acme-corp.com"
      }
    ]

    Artifacts

    tenant_id_format_identified customer_data_structure
  2. 2. Test tenant ID manipulation in header

    http

    Action

    Modify X-Tenant-ID header to access another tenant's data

    Request

    GET https://api.example.com/api/customers
    Headers:
    Authorization: Bearer tenant-acme-token
    X-Tenant-ID: techstartup-inc

    Response

    Status: 200
    Body:
    [
      {
        "id": 2001,
        "name": "Alice Johnson",
        "email": "alice@techstartup.com"
      },
      {
        "id": 2002,
        "name": "Bob Williams",
        "email": "bob@techstartup.com"
      },
      "... (437 customer records from TechStartup Inc)"
    ]

    Artifacts

    tenant_isolation_bypass cross_tenant_access customer_data_leak
  3. 3. Test tenant ID in URL parameter

    http

    Action

    Modify tenant parameter in query string

    Request

    GET https://api.example.com/api/reports?tenant_id=global-industries
    Headers:
    Authorization: Bearer tenant-acme-token

    Response

    Status: 200
    Body:
    {
      "tenant": "global-industries",
      "revenue": 8500000,
      "customers": 1247,
      "monthly_recurring_revenue": 450000,
      "churn_rate": 0.04,
      "sensitive_metrics": "Full financial dashboard accessible"
    }

    Artifacts

    financial_data_leak competitor_intelligence cross_tenant_reports

Exploit steps

Attacker systematically enumerates and accesses data from all tenants by manipulating tenant identifiers in requests.

  1. 1. Enumerate all tenant identifiers

    Discover tenant IDs through various endpoints

    http

    Action

    Use error messages, public listings, or enumeration to find tenant IDs

    Request

    GET https://api.example.com/api/customers
    Headers:
    X-Tenant-ID: invalid-tenant-xyz

    Response

    Status: 400
    Body:
    {
      "error": "Invalid tenant ID. Valid tenants: acme-corp, techstartup-inc, global-industries, ...",
      "note": "Error message helpfully lists all tenant IDs"
    }

    Artifacts

    tenant_enumeration tenant_id_list attack_surface_mapping
  2. 2. Mass data extraction from all tenants

    Iterate through all tenant IDs to extract data

    http

    Action

    Loop through discovered tenant IDs and extract customer/financial data

    Request

    GET https://api.example.com/api/customers
    Headers:
    Authorization: Bearer tenant-acme-token
    X-Tenant-ID: [iterate: acme-corp, techstartup-inc, global-industries, ...]

    Response

    Status: 200
    Body:
    {
      "extracted": "Complete customer databases from 847 tenants",
      "total_records": 2450000,
      "data_types": "Customer PII, payment info, contracts, internal documents",
      "estimated_value": "Multi-million dollar data breach affecting all platform tenants"
    }

    Artifacts

    mass_data_breach multi_tenant_compromise customer_pii payment_information confidential_documents
  3. 3. Modify competitor data for sabotage

    Use write access to corrupt competitor tenant data

    http

    Action

    If tenant isolation affects writes, modify competitor's critical data

    Request

    DELETE https://api.example.com/api/customers/bulk
    Headers:
    Authorization: Bearer tenant-acme-token
    X-Tenant-ID: competitor-corp

    Response

    Status: 200
    Body:
    {
      "message": "Deleted 15,243 customer records from competitor-corp tenant",
      "impact": "Competitor loses all customer data, business operations halt"
    }

    Artifacts

    data_deletion business_sabotage competitor_damage tenant_data_loss

Specific Impact

Cross-tenant data exposure, compliance violations, and loss of customer trust in the SaaS platform.

Fix

Always scope database queries by tenant_id from the authenticated user's context. Never rely on client-provided tenant identifiers. Consider implementing tenant scoping at the ORM level with default scopes or middleware. Use row-level security in the database where available for defense in depth.

Detect This Vulnerability in Your Code

Sourcery automatically identifies tenant isolation failures vulnerabilities and many other security issues in your codebase.

Scan Your Code for Free