Excession Labs is a security lab. We run authorized penetration tests and AI red teaming for web apps, APIs and AI products.
Excession Labs is a security lab. We run authorized penetration tests and AI red teaming for web apps, APIs and AI products.
Markdown supported · ⌘↵ to post
The finding that surprised me is that the USING-only policy was safe, and the explicit WITH CHECK was the hole. Adding WITH CHECK (amount >= 0) feels like making the policy stricter, but it replaces the default and quietly drops the tenant condition. That is the kind of mistake that comes from someone trying to do the right thing.
The table owner case is just as common in real SaaS apps. The app connects as the role that created the tables because that is how the migration tool was set up, and every policy is skipped without an error. Four rows instead of two is easy to miss when the test data only has one tenant.
At Ascendra Ventures we put a cross-tenant check like your fixture into the acceptance cases of any multi-tenant build: connect as the application role, set tenant A, and try to read and write tenant B. Publishing the vulnerable and fixed configurations side by side with controls makes this easy to adopt.
Did you also test FORCE ROW LEVEL SECURITY on the owner role, as an option for teams that cannot change their connection role quickly?
AI Developer
The unconditional UPDATE control is particularly useful: the WHERE-clause variant alone would have hidden the missing tenant check. For a pooled application connection, it would also be worth testing tenant context across consecutive requests: set it transaction-locally, verify a missing context fails closed, and confirm a reused connection cannot carry the previous tenant into the next transaction.