case-attachments has no tenant isolation
The private case-attachments bucket holds all confidential material: case evidence,
legal deliverables, the final dossier ZIPs, and portal uploads. Its storage policies gate
only on bucket_id — there is no per-company (or per-case) path check.
Impact: any authenticated user of any tenant can read or write any file in the
bucket, given (or guessing) the path. Paths are predictable ({case_id}/{uuid}.{ext},
dossiers/{case_id}/{export_id}.zip) and case_ids leak through the app. This is a
cross-tenant confidential-data breach and it directly contradicts the product's
"end-to-end encryption" claim (intent vs reality).
By contrast, company-logos and user-avatars do enforce a first-path-segment check —
so the pattern to fix this exists in the same codebase, just wasn't applied to the
sensitive bucket.
Rebuild implication
Enforce a per-company path prefix in the storage policy (mirror the company-logos
is_company_admin((storage.foldername(name))[1]::uuid) pattern), or serve all downloads
through an authorization-checking endpoint. Consider encryption at rest with per-tenant
keys if the E2E promise is to be honoured. Adopt one path convention.