Fix multi-tenancy bypass: derive tenant_id from JWT, not from request headers #5
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
compliance/api/tenant_utils.py:46-58resolves tenant_id fromX-Tenant-IDheader or query param supplied by the client. There is no check that the authenticated user belongs to that tenant.Any authenticated user can set
X-Tenant-ID: <victim_uuid>and read or modify another tenant's compliance data — all VVT entries, DSFA documents, DSR requests, change requests, company profiles.Required Actions
tenant_idfrom the validated JWT claims (e.g.azpor a custom claim set by Keycloak)X-Tenant-IDheader as an input toget_tenant_id()— the header is untrusted user inputassert_tenant_owns(db, tenant_id, table, record_id)used in every GET/PATCH/DELETE handlerFiles to Change
compliance/api/tenant_utils.py— rewriteget_tenant_id()x_tenant_id: str = Header(...)Acceptance Criteria
X-Tenant-IDheader is ignored by all routes; tenant comes from JWT only