Security Testing
Comprehensive guide to testing AuthzKit Tenant Guard protection mechanisms and verifying 100% tenant isolation in your application.
Overview
AuthzKit security testing ensures that your multi-tenant application is protected against all forms of cross-tenant data violations. This guide provides testing strategies, tools, and real-world attack scenarios to verify complete protection.
Quick Security Verification
1. Basic Cross-tenant Protection Test
import { PrismaClient } from '@prisma/client';
import { withTenantGuard } from '../src/tenant-guard';
const prisma = new PrismaClient();
async function basicSecurityTest() {
const tenant1Db = withTenantGuard(prisma, 'tenant-1');
const tenant2Db = withTenantGuard(prisma, 'tenant-2');
// Create user in tenant-1
const user1 = await tenant1Db.user.create({
data: {
tenantId: 'tenant-1',
email: 'alice@tenant1.com',
name: 'Alice'
}
});
// Try to access from tenant-2 (should be null)
const crossTenantAccess = await tenant2Db.user.findUnique({
where: { id: user1.id }
});
console.log('Cross-tenant access result:', crossTenantAccess); // Should be null
// Verify tenant-1 can access its own data
const legitimateAccess = await tenant1Db.user.findUnique({
where: { id: user1.id }
});
console.log('Legitimate access result:', legitimateAccess); // Should return user
}
basicSecurityTest();
2. Nested Operation Protection Test
async function nestedOperationTest() {
const tenant1Db = withTenantGuard(prisma, 'tenant-1');
const tenant2Db = withTenantGuard(prisma, 'tenant-2');
// Create tag in tenant-1
const tag1 = await tenant1Db.tag.create({
data: {
tenantId: 'tenant-1',
name: 'Confidential',
color: '#ff0000'
}
});
try {
// Try to connect tenant-1's tag to tenant-2's todo
await tenant2Db.todo.create({
data: {
tenantId: 'tenant-2',
title: 'Steal data',
authorId: 3,
tags: {
connect: [{ id: tag1.id }] // Should be blocked
}
}
});
console.error('❌ SECURITY BREACH: Cross-tenant connection succeeded');
} catch (error) {
console.log('✅ PROTECTED: Cross-tenant connection blocked');
}
}
nestedOperationTest();
Comprehensive Test Suite
Jest Test Framework
Create a comprehensive test suite using Jest:
// tests/tenant-guard.test.ts
import { PrismaClient } from '@prisma/client';
import { withTenantGuard } from '../src/tenant-guard';
describe('AuthzKit Tenant Guard Security', () => {
let prisma: PrismaClient;
let tenant1Db: ReturnType<typeof withTenantGuard>;
let tenant2Db: ReturnType<typeof withTenantGuard>;
beforeAll(async () => {
prisma = new PrismaClient();
tenant1Db = withTenantGuard(prisma, 'tenant-1');
tenant2Db = withTenantGuard(prisma, 'tenant-2');
});
afterAll(async () => {
await prisma.$disconnect();
});
describe('Basic Tenant Isolation', () => {
it('should prevent cross-tenant user access', async () => {
const user = await tenant1Db.user.create({
data: {
tenantId: 'tenant-1',
email: 'test@example.com',
name: 'Test User'
}
});
const crossTenantUser = await tenant2Db.user.findUnique({
where: { id: user.id }
});
expect(crossTenantUser).toBeNull();
});
it('should allow same-tenant access', async () => {
const user = await tenant1Db.user.create({
data: {
tenantId: 'tenant-1',
email: 'same@example.com',
name: 'Same Tenant User'
}
});
const sameTenantUser = await tenant1Db.user.findUnique({
where: { id: user.id }
});
expect(sameTenantUser).not.toBeNull();
expect(sameTenantUser?.tenantId).toBe('tenant-1');
});
});
describe('Nested Operation Protection', () => {
it('should block cross-tenant tag connections', async () => {
const tag = await tenant1Db.tag.create({
data: {
tenantId: 'tenant-1',
name: 'Secret Tag',
color: '#ff0000'
}
});
await expect(
tenant2Db.todo.create({
data: {
tenantId: 'tenant-2',
title: 'Malicious Todo',
authorId: 3,
tags: {
connect: [{ id: tag.id }]
}
}
})
).rejects.toThrow();
});
it('should allow same-tenant tag connections', async () => {
const tag = await tenant1Db.tag.create({
data: {
tenantId: 'tenant-1',
name: 'Legitimate Tag',
color: '#00ff00'
}
});
const todo = await tenant1Db.todo.create({
data: {
tenantId: 'tenant-1',
title: 'Legitimate Todo',
authorId: 1,
tags: {
connect: [{ id: tag.id }]
}
},
include: {
tags: { include: { tag: true } }
}
});
expect(todo.tags).toHaveLength(1);
expect(todo.tags[0].tag.id).toBe(tag.id);
});
});
describe('Direct Relationship Manipulation', () => {
it('should block direct TodoTag creation with cross-tenant IDs', async () => {
const tag = await tenant1Db.tag.create({
data: { tenantId: 'tenant-1', name: 'Tag', color: '#blue' }
});
const todo = await tenant2Db.todo.create({
data: { tenantId: 'tenant-2', title: 'Todo', authorId: 3 }
});
await expect(
tenant2Db.todoTag.create({
data: {
tenantId: 'tenant-2',
todoId: todo.id,
tagId: tag.id // Cross-tenant tag
}
})
).rejects.toThrow();
});
});
describe('Auto-injection Testing', () => {
it('should auto-inject tenantId in assist mode', async () => {
const assistTenantDb = withTenantGuard(prisma, 'tenant-1', 'assist');
const user = await assistTenantDb.user.create({
data: {
// tenantId omitted - should be auto-injected
email: 'autoinjected@example.com',
name: 'Auto User'
}
});
expect(user.tenantId).toBe('tenant-1');
});
});
});
Vitest Alternative
// tests/tenant-guard.test.ts (Vitest)
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { PrismaClient } from '@prisma/client';
import { withTenantGuard } from '../src/tenant-guard';
describe('AuthzKit Security Testing', () => {
// Same test structure as Jest
});
Real-World Attack Scenarios
Attack Scenario 1: Corporate Espionage
Simulate a sophisticated attack where a malicious tenant tries to access competitor data:
async function corporateEspionageTest() {
console.log('🚨 Testing Corporate Espionage Attack...\n');
const legitimateBusinessDb = withTenantGuard(prisma, 'acme-corp');
const maliciousActorDb = withTenantGuard(prisma, 'evil-corp');
// 1. Legitimate business creates confidential data
const confidentialTag = await legitimateBusinessDb.tag.create({
data: {
tenantId: 'acme-corp',
name: 'CONFIDENTIAL',
color: '#ff0000'
}
});
const businessPlan = await legitimateBusinessDb.todo.create({
data: {
tenantId: 'acme-corp',
title: 'Q4 Business Strategy',
description: 'Confidential business plans',
authorId: 1,
tags: {
connect: [{ id: confidentialTag.id }]
}
}
});
// 2. Malicious actor attempts various attacks
const attacks = [
{
name: 'Direct data access',
test: () => maliciousActorDb.todo.findUnique({ where: { id: businessPlan.id } })
},
{
name: 'Tag theft',
test: () => maliciousActorDb.tag.findUnique({ where: { id: confidentialTag.id } })
},
{
name: 'Cross-tenant connection',
test: () => maliciousActorDb.todo.create({
data: {
tenantId: 'evil-corp',
title: 'Stolen data',
authorId: 5,
tags: { connect: [{ id: confidentialTag.id }] }
}
})
},
{
name: 'Relationship manipulation',
test: () => maliciousActorDb.todoTag.create({
data: {
tenantId: 'evil-corp',
todoId: businessPlan.id,
tagId: confidentialTag.id
}
})
}
];
const results = [];
for (const attack of attacks) {
try {
const result = await attack.test();
if (result) {
console.log(`❌ SECURITY BREACH: ${attack.name} succeeded`);
results.push({ attack: attack.name, status: 'BREACH', result });
} else {
console.log(`✅ PROTECTED: ${attack.name} returned null`);
results.push({ attack: attack.name, status: 'PROTECTED' });
}
} catch (error) {
console.log(`✅ BLOCKED: ${attack.name} threw error`);
results.push({ attack: attack.name, status: 'BLOCKED', error: error.message });
}
}
return results;
}
Attack Scenario 2: Mass Data Extraction
async function massDataExtractionTest() {
console.log('🚨 Testing Mass Data Extraction Attack...\n');
const victim1Db = withTenantGuard(prisma, 'victim-1');
const victim2Db = withTenantGuard(prisma, 'victim-2');
const attackerDb = withTenantGuard(prisma, 'attacker');
// Create data in victim tenants
const victim1Data = await victim1Db.tag.createMany({
data: [
{ tenantId: 'victim-1', name: 'Private-1', color: '#red' },
{ tenantId: 'victim-1', name: 'Secret-1', color: '#blue' }
]
});
const victim2Data = await victim2Db.tag.createMany({
data: [
{ tenantId: 'victim-2', name: 'Private-2', color: '#green' },
{ tenantId: 'victim-2', name: 'Secret-2', color: '#yellow' }
]
});
// Attacker tries to steal all data
try {
const stolenTodo = await attackerDb.todo.create({
data: {
tenantId: 'attacker',
title: 'Data harvest',
authorId: 99,
tags: {
connect: [
{ id: 1 }, { id: 2 }, // victim-1 tags
{ id: 3 }, { id: 4 } // victim-2 tags
]
}
}
});
console.log('❌ SECURITY BREACH: Mass data extraction succeeded');
return { status: 'BREACH', data: stolenTodo };
} catch (error) {
console.log('✅ PROTECTED: Mass data extraction blocked');
return { status: 'PROTECTED', error: error.message };
}
}
Automated Security Testing
GitHub Actions CI/CD
Create automated security testing in your CI/CD pipeline:
# .github/workflows/security-test.yml
name: AuthzKit Security Testing
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
security-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate Prisma client and AuthzKit metadata
run: npx prisma generate
- name: Run security tests
run: npm run test:security
env:
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
TENANT_GUARD_MODE: strict
- name: Run attack simulations
run: npm run test:attacks
NPM Scripts
Add security testing scripts to your package.json
:
{
"scripts": {
"test:security": "jest tests/security --verbose",
"test:attacks": "tsx tests/attack-scenarios.ts",
"test:all": "npm run test:security && npm run test:attacks"
}
}
Load Testing with Tenant Isolation
Performance Under Attack
Test AuthzKit performance under simulated attack conditions:
// tests/load-test.ts
import { performance } from 'perf_hooks';
async function loadTestTenantIsolation() {
const iterations = 1000;
const tenants = ['tenant-1', 'tenant-2', 'tenant-3'];
console.log(`Running ${iterations} operations across ${tenants.length} tenants...\n`);
const start = performance.now();
const results = [];
for (let i = 0; i < iterations; i++) {
const tenantId = tenants[i % tenants.length];
const tenantDb = withTenantGuard(prisma, tenantId);
try {
// Simulate normal operations
const user = await tenantDb.user.create({
data: {
tenantId,
email: `user-${i}@${tenantId}.com`,
name: `User ${i}`
}
});
// Simulate cross-tenant attack
const otherTenantId = tenants[(i + 1) % tenants.length];
const attackerDb = withTenantGuard(prisma, otherTenantId);
const attack = await attackerDb.user.findUnique({
where: { id: user.id }
});
results.push({
iteration: i,
tenant: tenantId,
legitimate: !!user,
attack_blocked: !attack
});
} catch (error) {
results.push({
iteration: i,
tenant: tenantId,
error: error.message
});
}
}
const end = performance.now();
const duration = end - start;
// Analyze results
const successful = results.filter(r => r.legitimate && r.attack_blocked);
const breaches = results.filter(r => !r.attack_blocked && !r.error);
console.log(`Performance Results:`);
console.log(`Total time: ${duration.toFixed(2)}ms`);
console.log(`Average per operation: ${(duration / iterations).toFixed(2)}ms`);
console.log(`Successful protections: ${successful.length}/${iterations}`);
console.log(`Security breaches: ${breaches.length}/${iterations}`);
if (breaches.length > 0) {
console.error('❌ SECURITY FAILURES DETECTED');
return false;
} else {
console.log('✅ ALL OPERATIONS PROTECTED');
return true;
}
}
Security Monitoring in Production
Runtime Protection Monitoring
Monitor AuthzKit protection in production:
// monitoring/security-monitor.ts
import { withTenantGuard } from '../src/tenant-guard';
const securityMetrics = {
violations_blocked: 0,
auto_injections: 0,
legitimate_operations: 0
};
export const createMonitoredTenantClient = (prisma: PrismaClient, tenantId: string) => {
return withTenantGuard(prisma, tenantId, {
mode: 'assist',
onWarn: (warning) => {
securityMetrics.auto_injections++;
// Log to monitoring service
monitoring.increment('authzkit.auto_injection', {
tags: {
tenant_id: tenantId,
model: warning.model,
operation: warning.operation
}
});
},
onError: (error) => {
securityMetrics.violations_blocked++;
// Alert on security violations
alerting.sendSecurityAlert({
type: 'tenant_violation_blocked',
tenant_id: tenantId,
error_code: error.code,
timestamp: new Date().toISOString()
});
}
});
};
// Health check endpoint
export const getSecurityMetrics = () => securityMetrics;
Compliance Testing
Test AuthzKit compliance with security standards:
// tests/compliance.test.ts
describe('AuthzKit Compliance Testing', () => {
it('should meet SOC 2 Type II requirements', async () => {
// Test that tenant data is completely isolated
// Verify audit trails are maintained
// Ensure no data leakage between tenants
});
it('should meet GDPR requirements', async () => {
// Test data deletion across tenant boundaries
// Verify personal data isolation
// Ensure right to be forgotten compliance
});
it('should meet HIPAA requirements', async () => {
// Test healthcare data isolation
// Verify access controls work correctly
// Ensure audit logging is comprehensive
});
});
Security Test Checklist
Use this checklist to verify comprehensive AuthzKit protection:
✅ Basic Protection Tests
- [ ] Cross-tenant user access blocked
- [ ] Cross-tenant data queries return null/empty
- [ ] Same-tenant operations work correctly
- [ ] Auto-injection works in assist mode
- [ ] Strict mode blocks missing tenant fields
✅ Nested Operation Tests
- [ ] Cross-tenant connect operations blocked
- [ ] Cross-tenant create operations blocked
- [ ] Cross-tenant update operations blocked
- [ ] Complex nested operations validated
- [ ] Many-to-many relationships protected
✅ Advanced Attack Tests
- [ ] Corporate espionage scenario blocked
- [ ] Mass data extraction prevented
- [ ] Direct relationship manipulation blocked
- [ ] SQL injection attempts handled
- [ ] Authorization bypass attempts failed
✅ Performance Tests
- [ ] Load testing under attack conditions
- [ ] Performance impact measurement
- [ ] Memory usage monitoring
- [ ] Concurrent tenant operations
- [ ] Database connection efficiency
✅ Production Monitoring
- [ ] Security violation alerting
- [ ] Auto-injection monitoring
- [ ] Performance metrics collection
- [ ] Audit log generation
- [ ] Compliance reporting
Next: Troubleshooting - Learn to diagnose and fix common issues.