glossary
RPC EXECUTE Grants
RPC execute grants control which roles can call Postgres functions, and long-lived PUBLIC/anon grants often outlive their intended use. This page explains it in plain English, then goes deeper into how it works in Supabase/Postgres, what commonly goes wrong, and how to fix it without relying on fragile client-side rules.
What “RPC EXECUTE Grants” means (plain English)
Each RPC function needs an EXECUTE grant, so keeping PUBLIC or anon listed means the browser can trigger that function even if the UI stopped calling it.
How RPC EXECUTE Grants works in Supabase/Postgres (technical)
EXECUTE is managed per function signature; granting service_role alone while revoking PUBLIC/anon ensures only backend sessions can activate functions that otherwise bypass business logic.
Attack paths & failure modes for RPC EXECUTE Grants
- Public RPC exposes admin export: The team reused an internal export RPC for a customer feature and failed to shrink the grant list.
- Overloaded function signature was missed: A function exists with both parameterless and parameterized variants; only one signature had its EXECUTE privileges tightened.
- Public RPC exposes admin export: The function still had EXECUTE for PUBLIC/anon/authenticated, so attackers could call it directly and retrieve more data than intended.
- Overloaded function signature was missed: The remaining overload still granted PUBLIC access, so attackers triggered the privileged behavior through that path.
- Functions are executable by PUBLIC/anon/authenticated, so attackers can call business logic directly.
- RPC bypasses UI constraints; parameters can be used to access unintended rows.
- Security-definer functions can escalate privileges if not carefully designed.
- A function exposes sensitive data even if table RLS is strict (because the function runs with elevated rights).
- Exec grants drift over time as new functions ship without review.
Why RPC EXECUTE Grants matters for Supabase security
Exposed functions can return sensitive data or perform privileged actions because they live behind fewer checks than tables, making them lucrative attack targets.
Common RPC EXECUTE Grants mistakes that lead to leaks
- Revoking grants on one signature while other overloads remain callable.
- Forgetting to remove PUBLIC/anon grants after repurposing a function for customer-facing work.
- Assuming function-level logic is safe simply because the related tables are locked down.
- Public RPC exposes admin export: The function still had EXECUTE for PUBLIC/anon/authenticated, so attackers could call it directly and retrieve more data than intended.
- Overloaded function signature was missed: The remaining overload still granted PUBLIC access, so attackers triggered the privileged behavior through that path.
Where to look for RPC EXECUTE Grants in Supabase
- Function EXECUTE grants for PUBLIC/anon/authenticated roles.
- Functions marked SECURITY DEFINER or that read sensitive tables.
- Parameter handling: are you validating ownership/tenancy inside the function?
- Any frontend code paths that call RPC directly instead of through a backend layer.
How to detect RPC EXECUTE Grants issues (signals + checks)
Use this as a quick checklist to validate your current state:
- Try the same queries your frontend can run (anon/authenticated). If sensitive rows come back, you have exposure.
- Verify RLS is enabled and (for sensitive tables) forced.
- List policies and look for conditions that don’t bind rows to a user or tenant.
- Audit grants to
anon/authenticatedon sensitive tables and functions. - Public RPC exposes admin export: Audit function grants independently from tables.
- Public RPC exposes admin export: Check for overloads and multiple signatures every time.
- Public RPC exposes admin export: Expose exports through backend endpoints with logging.
- Re-test after every migration that touches security-critical tables or functions.
How to fix RPC EXECUTE Grants (backend-only + zero-policy posture)
Mockly’s safest default is backend-only access: the browser should not query tables, call RPC, or access Storage directly.
- Decide which operations must remain client-side (often: none for sensitive resources).
- Create server endpoints (API routes or server actions) for required reads/writes.
- Apply hardening SQL: enable+force RLS where relevant, remove broad policies, and revoke grants from client roles.
- Generate signed URLs for private Storage downloads on the server only.
- Re-run a scan and confirm the issue disappears.
- Add a regression check to your release process so drift doesn’t reintroduce exposure. Fixes that worked in linked incidents:
- Public RPC exposes admin export: Revoke EXECUTE from PUBLIC/anon/authenticated, call the function only from backend code using service_role, and limit the output per requester.
- Overloaded function signature was missed: Enumerate all overloads via
pg_procand apply REVOKE/GRANT per signature, then document the checklist for future audits.
Verification checklist for RPC EXECUTE Grants
- Enumerate functions and identify any with public EXECUTE privileges.
- Revoke EXECUTE from client roles for privileged functions and route calls through backend endpoints.
- Validate authorization inside server code (or inside the function if it remains callable).
- Attempt RPC calls as anon/authenticated to confirm they are denied where expected.
- Re-run checks after every migration that adds/changes functions.
- Public RPC exposes admin export: Audit function grants independently from tables.
- Public RPC exposes admin export: Check for overloads and multiple signatures every time.
- Public RPC exposes admin export: Expose exports through backend endpoints with logging.
SQL sanity checks for RPC EXECUTE Grants (optional, but high signal)
If you prefer evidence over intuition, run a small set of SQL checks after each fix.
The goal is not to memorize catalog tables — it’s to make sure the access boundary you intended is the one Postgres actually enforces:
- Confirm RLS is enabled (and forced where appropriate) for tables tied to this term.
- List policies and read them as plain language: who can do what, under what condition?
- Audit grants for anon/authenticated and PUBLIC on the tables, views, and functions involved.
- If Storage is involved: review bucket privacy and policies for listing/reads.
- If RPC is involved: review EXECUTE grants for functions and whether privileged functions are server-only.
Pair these checks with a direct API access test using client credentials. When both agree, you can ship the fix with confidence.
Over time, keep a small “query pack” for the checks you trust and run it after every migration. That’s how you prevent quiet regressions.
Prevent RPC EXECUTE Grants drift (so it doesn’t come back)
- Create a “function review” checklist for code review and migrations (who can execute what?).
- Prefer server-only wrappers for sensitive RPC operations.
- Track function inventory so new public functions don’t appear unnoticed.
- Keep one reusable verification test for “Public RPC exposes admin export” and rerun it after every migration that touches this surface.
- Keep one reusable verification test for “Overloaded function signature was missed” and rerun it after every migration that touches this surface.
Rollout plan for RPC EXECUTE Grants fixes (without breaking production)
Many hardening changes fail because teams revoke direct access first and only later discover missing backend paths.
Use this sequence to reduce both risk and outage pressure:
- Implement and verify the backend endpoint or server action before permission changes.
- Switch clients to that backend path behind a feature flag when possible.
- Then revoke direct client access (broad grants, permissive policies, public bucket reads, or broad EXECUTE).
- Run direct-access denial tests and confirm authorized backend flows still succeed.
- Re-scan after deployment and again after the next migration.
This turns security fixes into repeatable rollout mechanics instead of one-off emergency changes.
Incident breakdowns for RPC EXECUTE Grants (real scenarios)
Public RPC exposes admin export
Scenario: The team reused an internal export RPC for a customer feature and failed to shrink the grant list.
What failed: The function still had EXECUTE for PUBLIC/anon/authenticated, so attackers could call it directly and retrieve more data than intended.
What fixed it: Revoke EXECUTE from PUBLIC/anon/authenticated, call the function only from backend code using service_role, and limit the output per requester.
Why the fix worked: Only the trusted backend service can start the session, so application-level authorization runs before the export function executes.
Key takeaways:
- Audit function grants independently from tables.
- Check for overloads and multiple signatures every time.
- Expose exports through backend endpoints with logging.
- Sanitize output and enforce row/tenant boundaries.
Read full example: Public RPC exposes admin export
Overloaded function signature was missed
Scenario: A function exists with both parameterless and parameterized variants; only one signature had its EXECUTE privileges tightened.
What failed: The remaining overload still granted PUBLIC access, so attackers triggered the privileged behavior through that path.
What fixed it: Enumerate all overloads via pg_proc and apply REVOKE/GRANT per signature, then document the checklist for future audits.
Why the fix worked: Every signature is now locked down and the checklist keeps future deployments from missing an overload.
Key takeaways:
- Always inspect identity arguments to capture overloads.
- Treat grants as per-signature operations.
- Document grant changes for repeatable audits.
- Backend endpoints keep usage consistent across overloads.
Read full example: Overloaded function signature was missed
Real-world examples of RPC EXECUTE Grants (and why they work)
- Public RPC exposes admin export — An admin export function remained callable by authenticated users because EXECUTE permissions were never tightened.
- Overloaded function signature was missed — One overload stayed executable because the REVOKE skipped a signature.
Related terms
- Service Role Key →
/glossary/service-role-key - Row Level Security (RLS) →
/glossary/row-level-security
FAQ
Is RPC EXECUTE Grants enough to secure my Supabase app?
It’s necessary, but not sufficient. You also need correct grants, secure Storage/RPC settings, and a backend-only access model for sensitive operations.
What’s the quickest way to reduce risk with RPC EXECUTE Grants?
Remove direct client access to sensitive resources, enable/force RLS where appropriate, and verify via a repeatable checklist that anon/authenticated cannot query what they shouldn’t.
How do I verify the fix is real (not just a UI change)?
Attempt direct API queries using the same client credentials your app ships. If the database denies access (401/403) and your backend endpoints still work, your fix is effective.
Next step
Want a quick exposure report for your own project? Run a scan in Mockly to find public tables, storage buckets, and RPC functions — then apply fixes with verification steps.