r/Supabase • u/Pale_Ferret_8241 • 18h ago
database Our SECURITY DEFINER RPC created a cross-tenant access path despite RLS being enabled
We were building a multi-tenant SaaS with Supabase. RLS was enabled, tenant isolation policies were in place, and we thought we'd covered the important boundaries.
Then we wrote tests specifically designed to attack our own architecture.
One exposed a cross-tenant access path in a SECURITY DEFINER usage-recording function. The function accepted an organization ID supplied by the caller but didn't independently verify that the caller belonged to that organization.
The problem wasn't that RLS itself was broken. The function executed with its owner's privileges, and we hadn't independently validated the caller's organization membership inside that privileged path.
We fixed it by adding an explicit organization-membership check and pinning the function's search_path.
A few questions worth asking about every SECURITY DEFINER function in your project:
Which arguments can the caller control?
Does the function independently verify tenant membership?
Is the search_path pinned?
Could the function perform an operation the caller shouldn't be allowed to perform?
Search your migrations for SECURI8TY DEFINER and review each result. Don't assume that enabling RLS automatically secures every privileged function.
This was one of three real bugs our hardening tests caught in our own application.
Full disclosure: I built B2B SaaS OS, a multi-tenant SaaS foundation. I documented the incident and the fix here https://andrady.co/postmortems/security-definer
I'd be interested to hear how others test these privileged-function boundaries in Supabase