Files
ColaFlow/colaflow-api/SECURITY-FIX-CROSS-TENANT-ACCESS.md
Yaojia Wang 32a25b3b35 In progress
2025-11-03 20:02:41 +01:00

5.8 KiB

SECURITY FIX: Cross-Tenant Access Validation

Executive Summary

Status: IMPLEMENTED ✓ Priority: CRITICAL Date: 2025-11-03 Modified Files: 1 Build Status: SUCCESS (0 warnings, 0 errors)

Security Vulnerability

Issue Identified

During Day 6 integration testing, a critical security gap was discovered in the Role Management API (TenantUsersController):

Vulnerability: Users from Tenant A could access and potentially manage Tenant B's users and roles by manipulating the tenantId route parameter.

Impact:

  • Unauthorized access to other tenants' user lists
  • Potential unauthorized role assignments across tenants
  • Breach of multi-tenant data isolation principles

Severity: HIGH - Violates fundamental security principle of tenant isolation

Implementation

Modified File

src/ColaFlow.API/Controllers/TenantUsersController.cs

Endpoints Fixed

Endpoint Method Authorization Policy Validation Added
/api/tenants/{tenantId}/users GET RequireTenantAdmin ✓ Yes
/api/tenants/{tenantId}/users/{userId}/role POST RequireTenantOwner ✓ Yes
/api/tenants/{tenantId}/users/{userId} DELETE RequireTenantOwner ✓ Yes
/api/tenants/../roles GET RequireTenantAdmin N/A (Static data)

Validation Logic

Each protected endpoint now includes:

// SECURITY: Validate user belongs to target tenant
var userTenantIdClaim = User.FindFirst("tenant_id")?.Value;
if (userTenantIdClaim == null)
    return Unauthorized(new { error = "Tenant information not found in token" });

var userTenantId = Guid.Parse(userTenantIdClaim);
if (userTenantId != tenantId)
    return StatusCode(403, new { error = "Access denied: You can only manage users in your own tenant" });

Security Flow

  1. Extract JWT Claim: Read tenant_id from authenticated user's JWT token
  2. Claim Validation: Return 401 Unauthorized if tenant_id claim is missing
  3. Tenant Matching: Compare user's tenant ID with route parameter tenantId
  4. Access Control: Return 403 Forbidden if tenant IDs don't match
  5. Proceed: Continue to business logic only if validation passes

Expected Behavior After Fix

Scenario 1: Same Tenant Access (Authorized)

User: Tenant A Admin (tenant_id = "aaaa-1111")
Request: GET /api/tenants/aaaa-1111/users
Result: 200 OK + User list

Scenario 2: Cross-Tenant Access (Blocked)

User: Tenant A Admin (tenant_id = "aaaa-1111")
Request: GET /api/tenants/bbbb-2222/users
Result: 403 Forbidden + Error message

Scenario 3: Missing Tenant Claim (Invalid Token)

User: Token without tenant_id claim
Request: GET /api/tenants/aaaa-1111/users
Result: 401 Unauthorized + Error message

Verification

Build Status

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.24

Code Quality

  • ✓ Consistent validation pattern across all endpoints
  • ✓ Clear security comments explaining purpose
  • ✓ Proper HTTP status codes (401 vs 403)
  • ✓ Descriptive error messages
  • ✓ No code duplication (same pattern repeated)

Technical Details

JWT Claim Structure

The tenant_id claim is added by JwtService.GenerateToken():

new("tenant_id", tenant.Id.ToString())

Location: src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Services/JwtService.cs (Line 34)

Authorization Policies (Unchanged)

Existing policies remain in place:

  • RequireTenantOwner - Checks for TenantOwner role
  • RequireTenantAdmin - Checks for TenantAdmin or TenantOwner role

Important: These policies validate roles, while the new validation checks tenant membership.

Why GetAvailableRoles Doesn't Need Validation

The /api/tenants/../roles endpoint returns static role definitions (TenantOwner, TenantAdmin, etc.) and doesn't access tenant-specific data. The existing RequireTenantAdmin policy is sufficient.

Security Best Practices Followed

  1. Defense in Depth: Validation at API layer before business logic
  2. Fail Securely: Return 403 Forbidden on mismatch (don't reveal if tenant exists)
  3. Clear Error Messages: Help legitimate users understand authorization failures
  4. Consistent Implementation: Same pattern across all endpoints
  5. Minimal Changes: API-layer validation only, no changes to command handlers or repositories

Remaining Work

Testing Recommendations

  1. Unit Tests: Add tests for tenant validation logic
  2. Integration Tests: Update RoleManagementTests.cs to verify cross-tenant blocking
  3. Security Testing: Penetration test with cross-tenant attack scenarios

Future Enhancements

  1. Centralized Validation: Consider extracting to an action filter or middleware
  2. Audit Logging: Log all 403 responses for security monitoring
  3. Rate Limiting: Add rate limiting on 403 responses to prevent tenant enumeration

References

  • Original Report: DAY6-TEST-REPORT.md - Section "Cross-Tenant Access Validation"
  • JWT Service: src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Services/JwtService.cs
  • Modified Controller: src/ColaFlow.API/Controllers/TenantUsersController.cs
  • Authorization Policies: src/ColaFlow.API/Program.cs (Lines configuring authorization)

Sign-Off

Implemented By: Backend Agent (Claude Code) Reviewed By: Pending code review Status: Ready for integration testing Next Steps:

  1. User to commit the staged changes (1Password SSH signing required)
  2. Add integration tests to verify cross-tenant blocking
  3. Deploy to staging environment for security testing

Note: The implementation is complete and builds successfully. The file is staged for commit but cannot be committed automatically due to 1Password SSH signing configuration requiring user interaction.