Supabase RPC function callable by anon? Revoke execute and check auth.uid()
Short answer: yes, by default a signed-out visitor can call any function in your public schema at /rest/v1/rpc/<name>. If the function shouldn't be public, run revoke execute on function public.my_function() from anon, public;. If it's security definer, also check auth.uid() inside and set search_path. To see what your own live site gives away, run a free SniffPup scan (SniffPup is a free passive security scanner for vibe-coded apps). Only check sites and projects you own.
Home › Guides › RPC function callable by anon · Last updated · By Ember, SniffPup
The fast way: a free SniffPup scan runs 15 checks from the outside, including Supabase read access using the public config your site already ships. No signup. Ember never calls your functions, so do the steps below too.
A 100 means no issues were found in our checks. It is never proof of security.
1. Why anon can call your functions
Postgres gives execute on every new function to public, which every role belongs to, including anon (see GRANT). Supabase's API exposes functions in the public schema as RPC endpoints, which is what supabase.rpc() calls. Your anon key ships in your frontend, so "only my app calls it" isn't a lock. Anyone with the key can send the same request.
2. Security definer without an auth.uid() check
Per Supabase's database functions docs, a security definer function runs as its owner, usually postgres, which bypasses Row Level Security. Pair that with anon execute and no check on the caller, and RLS on your tables stops mattering for whatever that function does. The Security Advisor flags it as lint 0028 (anon can execute a security definer function).
It's like a dog door that also opens the fridge. Handy for the dog. Less handy when the neighbor's dog finds it.
3. The fix: revoke execute from anon and public
Include the argument types if the function has any, then grant it back only to who needs it:
revoke execute on function public.my_function(uuid) from anon, public; grant execute on function public.my_function(uuid) to authenticated;
Revoking from anon alone isn't enough, because anon still inherits it through public. To stop new functions being public by default, you can also run alter default privileges in schema public revoke execute on functions from anon, public; (test that your app still works after).
4. Check auth.uid() inside, and set search_path
Signed-in users can still call it, so the function itself has to check who's asking. Prefer security invoker (the default) so RLS applies. If you need definer, filter by the caller and pin the search path, as Supabase's docs recommend for definer functions:
create or replace function public.get_my_orders() returns setof public.orders language sql security definer set search_path = '' as $$ select * from public.orders where user_id = (select auth.uid()); $$;
More on pinning it in Function Search Path Mutable. The Postgres docs explain why an unpinned definer function can be tricked into using planted objects.
5. Find functions anon can execute
select n.nspname as schema,
p.proname as function,
pg_get_function_identity_arguments(p.oid) as args,
p.prosecdef as security_definer
from pg_catalog.pg_proc p
join pg_catalog.pg_namespace n on n.oid = p.pronamespace
where n.nspname = 'public'
and has_function_privilege('anon', p.oid, 'execute')
order by p.prosecdef desc, 2;Rows with security_definer = true come first. Fix those first, then decide for each of the rest whether signed-out visitors really need it.
6. Re-check signed out
Rerun the Security Advisor in Supabase Studio: the 0028 warnings should be gone and the query above should only list functions you meant to be public. Then call one function from your own app while signed out and confirm you get a permission error. Related: a policy left as using (true) keeps a table open the same way, and Edge Functions with verify_jwt = false are the serverless version of this problem. For the full list, see the Supabase security audit.
FAQ
Can anon call my Supabase database function?
Usually yes. Postgres grants execute on new functions to public, and Supabase exposes functions in the public schema at /rest/v1/rpc/<name>, so anyone with your project URL and anon key can call them unless you revoke execute.
Why is security definer risky?
A security definer function runs with its owner's privileges, usually postgres, which bypasses Row Level Security. If anon can execute it and it doesn't check auth.uid(), any signed-out visitor gets whatever the function reads or writes. Supabase's Security Advisor flags this as lint 0028.
How do I stop anon calling a function?
Run revoke execute on function public.my_function(arg types) from anon, public; then grant execute only to the roles that need it, like authenticated. Include the argument types if the function has any.
Is revoking enough for a function signed-in users still call?
No. Any signed-in user can call it, so check auth.uid() inside the function and only touch rows that belong to that user, or make it security invoker so RLS applies.
Does a clean SniffPup report mean my functions are fine?
No. A score of 100 means no issues were found in our checks. It is never proof of security: an outside scan can't see your function grants, so use the SQL and the Security Advisor on this page too.
Sources: Supabase Database functions, Advisors lint 0028 and rpc() docs, and the Postgres GRANT and CREATE FUNCTION docs. Checked November 2, 2026.
A score of 100 means no issues were found in our checks. It is not proof that your app is secure.