Database row-level security works because the rule runs where the data lives. Postgres rewrites every query against a protected table, adding the policy predicate before planning, so a hand-written filter is not required and cannot be forgotten in the Postgres RLS guide. Supabase puts the same idea plainly: a policy is effectively a WHERE clause injected into every statement, which is why RLS still protects data reached through third-party tools in the Supabase docs.
Agents break the assumption underneath that pattern. A tenant parameter is only safe when the caller is a deterministic program whose behavior is fixed by its source code. When a language model supplies tool arguments, an adversary who can plant text in the context window can influence which tenant the model names. One study formalized this as the stochastic deputy problem and found that a correctly validated tenant parameter served every out-of-scope attempt in its trials: 26 of 26 in the arXiv paper. The validation was faithful. The specification was the vulnerability.
That is the reason to test tools the way you test rows, and then to go one step further. You are not testing whether the model behaves. You are testing whether the enforcement layer below the model holds when the model asks for something it should never get. OWASP frames the same risk as tool abuse and privilege escalation: agents exploiting overly permissive tools to reach unauthorized resources in the OWASP AI Agent Security Cheat Sheet.
The row-level habit you already have transfers directly. A Supabase pgTAP test seeds todos for two users, authenticates as one, and asserts the other user's rows are invisible or unmodifiable in the Supabase testing overview. Tool tests follow the same shape: two scopes, one actor, assert denial.



