The admin key is not a fix for a policy error
grep -rhoE "eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+" . next/ dist/ | sort -u | while read t; do echo "$t" | cut -d. -f2 | base64 -d 2>/ dev/ null | grep -o '"role": "[a-z_]*"'; done
Get every Fix AI Slop Code episode
The code it wrote, the code it should have written and a check, for every episode
What is going on
When a policy blocks a query, the fastest thing that makes the error go away is the service-role key, which bypasses every policy. The model reaches for it. Now the browser, or an edge function that trusts the browser, owns the database. One app in the research ran 41 days like that.
Where it bit
Research only. The detection is trivial, which is what makes it a good receipt: fetch the bundle, find a JWT, decode it, read the role claim.
The practice
Service-role key in server env only. Every server route verifies the caller's JWT before it does anything as admin. A CI grep of the built bundle for any JWT whose payload decodes to service_role.
Get this check as a script you can run tonight

The coding agent never holds production credentials
An agent with a production database URL will sooner or later run a migration or a cleanup against it, so production secrets never enter its env
Keys go in headers, never in URLs
A URL is written to server logs, CDN logs, browser history and error trackers, so an API key in a query string is a key in five places
Backups the app cannot reach, and one restore you have actually done
A backup on the same account the app or an agent can delete from is not a backup, and a restore you have never run is a number you do not have
If this check came back with more than you expected, that is worth a conversation