Does your weekly security digest actually show you the most dangerous thing in your database?
A Supabase project sent its weekly security email. One item: a table with RLS disabled. It didn't look urgent, so instead of deferring it again, I pulled the full advisor report via the Management API this time. The numbers were nothing like the email. 1 ERROR, 227 WARN, 19 INFO. The email told me about the 1 ERROR. The real hole was sitting in the WARN pile it never mentioned.
What would you do?
When a weekly digest tells you there's one issue, do you trust it and move on, or pull the full list yourself and count? Before August 26th, I was the former.
What was in the 227
Filtering the WARN pile: 106 security definer functions were callable with nothing but the anon key, and 23 of those had zero guard at all. The two worst were a function that granted unlimited credits to any UUID and one that could activate a subscription for any account. I grepped the entire app codebase for callers of both — zero, everything routed through Edge Functions or service_role — and revoked EXECUTE. None of this was visible from a one-line email.
Then I opened the two delete functions on the community board app: web_post_delete and web_comment_delete.
The real master key, hardcoded inside the function
Both function bodies had the operator token's sha256 hash baked in as a literal constant.
if sha256(input_token) = '9f2a...(constant)' then
delete from posts where id = post_id; -- no author check
end if;And both had anon EXECUTE granted. The problem: the anon key isn't a secret. It's baked into both the iOS Info.plist and the Android BuildConfig — anyone who decompiles the app can pull it out. Combine that public key with the constant hash sitting in the function body, and anyone could delete any post by calling the Supabase REST endpoint directly. I reproduced it: same constant, same call, and it came back 200. Deleted.
Someone had built an admin-delete feature at some point. There wasn't even an admin screen left that used it. A back door nobody was using anymore, unlocked by a key sitting in plain sight inside the app binary.
Why this one is worse
Unlimited credit grants are easy to spot. The function name says grant_credits, and the moment you see it takes a UUID argument, the alarm goes off. A constant hardcoded inside a delete function is different — the signature alone reads as an ordinary "check token, then delete." The danger lives in the constant's value, not the code shape, so a signature review misses it entirely; you have to open the body and actually read the literal. Even the advisor only tells you "anon can execute this function" — it says nothing about what's hardcoded inside it.
The fix
Not a patch — a deletion. I ripped out the entire admin-delete branch and unified deletion to a single owner-token check (same shape as the edit function). The constant is gone, and so is the branch that checked it. Removing a back door nobody needed turned out shorter and safer than trying to lock the one that was already open.
One more thing worth knowing: create or replace function keeps the existing grants. "I redefined it, so permissions must have reset" is a wrong assumption. Grants only reset on drop + recreate, or when the signature changes. Since this was a body-only edit, the anon EXECUTE grant would have survived silently unless I explicitly revoked it — the back door staying alive under the same function name.
Three self-checks
- Have you ever compared your vendor's security summary email against the full list pulled directly from their API? A summary only shows what the vendor chose to surface.
- Have you grepped the bodies of every function callable by an anon/public key for a hardcoded token, hash, or password?
- Are there parts of your permission design that quietly assume a key baked into a client binary is "effectively private"?
The story of a verification rehearsal that touched real user data and only rolled back one of three columns came out of the same security pass — one is "permissions were open too wide," the other is "the process fixing that opened a different hole." They pair well.
This one has a follow-up: the execute privilege I'd revoked had quietly come back in a later regeneration. Here the problem was a constant in the function body; there it's the function privilege itself coming back.
Pull the list of functions callable by your anon key right now, and read the body of each one for a hardcoded constant. A signature review will not catch it.