#2040·chatbot-ui

delete_storage_object RPC is SECURITY DEFINER and executable by anon — any storage object can be deleted without auth

Author: hyojunlimCreated Sep 2, 2026Updated Sep 2, 2026

Summary

public.delete_storage_object(bucket, object) and public.delete_storage_object_from_bucket(...) in supabase/migrations/20240108234540_setup.sql (around line 47) are created as SECURITY DEFINER and perform an HTTP DELETE against Storage using the service role key. Because they live in the public schema, PostgREST exposes them at /rest/v1/rpc/..., and Supabase grants EXECUTE to anon and authenticated by default. Neither function checks auth.uid() or object ownership.

Impact

Anyone holding the public anon key (it ships in the browser bundle) can call the RPC and delete other users' files, message images, and assistant/workspace/profile images — without being logged in. The response also reveals whether an object exists.

Suggested fix

Keep the helpers callable only from the triggers that need them:

REVOKE EXECUTE ON FUNCTION public.delete_storage_object(text, text) FROM public, anon, authenticated;
REVOKE EXECUTE ON FUNCTION public.delete_storage_object_from_bucket(text, text) FROM public, anon, authenticated;

or move them to a non-exposed schema (e.g. private) and point the trigger functions there. Worth reviewing every other SECURITY DEFINER function in public the same way.

Context

Found by an automated full-codebase review (VibeAudit, Claude Fable 5.1). I've verified the reasoning against the migration but have not run it against a live deployment, so please double-check. Full report: https://vibeaudit-amber.vercel.app/a/fx06chatbotui — happy to close this if it's already mitigated somewhere I missed. Thanks for the project.