Role chosen by the client at signup
What it looks like
// signup form -> supabase.auth.signUp
await supabase.auth.signUp({
email, password,
options: { data: { role: 'user' } }, // user_metadata
});
-- RLS policy reads it back
using ((auth.jwt() -> 'user_metadata' ->> 'role') = 'admin')What happens
A visitor who edits the signup request, or updates their own profile, can make themselves an admin.
Where it shows up
Descriptive, not a verdict: builders and stacks whose defaults make this reachable, or that a public incident names. Each hub states the tool's own security features.
Seen in public
Apiiro's analysis of repositories at Fortune 50 companies found AI-assisted developers produced 3 to 4 times more commits and 10 times more security findings, with privilege escalation paths up 322%.
- 3 to 4x Commits by AI-assisted developers vs peers
- 10x Security findings by AI-assisted teams
- more than 10,000 New AI-introduced findings per month by June 2025
- +322% Privilege escalation paths
- +153% Architectural design flaws
Sep 2025 · Apiiro · all sources
Check it yourself
Uses your builder's dashboard and your browser. No tools to install.
- Open your signup page, open developer tools (right-click, Inspect) and the Network tab, then submit the form with a test email.
- Find the signup request and read its body. A field named role, plan, is_admin or similar is the warning sign.
- Right-click the request, choose Copy as cURL, change that field to admin and run it with a new test email.
- Sign in as that account and open the admin area.
A bad result is the new account getting admin screens or data.
What we check
We submit signup and profile-update requests with every role and plan value found in the code, then test what each resulting account can reach. The report states which values were accepted and what they opened.
Fix direction
Store roles in a table that only the server or an administrator can write, and put them into the token through a server-side auth hook rather than reading user metadata. Supabase documents this with custom claims and a user_roles table; its Security Advisor also flags policies that reference user metadata.
Mechanism documented in: Users (verified 2026-09-21); Custom Claims & Role-based Access Control (RBAC) (verified 2026-09-21).
Covered by
Pre-launch check ($490, 48 hours) and Security sweep ($290, 24 hours)
Both include a re-check after your fixes.
Related patterns
- Authorization enforced only in the browserLogin and permissionsCritical
Anyone who calls the API directly, or edits the page in developer tools, gets the data and actions the screen was hiding.
- Admin routes without any login checkLogin and permissionsCritical
A stranger who types /admin or /api/admin into the address bar can see or change everything the owner can.
- Tokens trusted without server verificationLogin and permissionsCritical
Anyone can write their own token naming another user, or an admin, and the server will act as that person.
- Price or plan taken from the clientPaymentsHigh
A buyer can edit the request in their browser, pay one cent for the top plan, and your app records it as a full purchase.
Questions
can users make themselves admin in my supabase app
They can if the role lives in user metadata and a policy or route trusts it. Supabase's Users doc states that user_metadata is editable by the user without any checks and should not be used in RLS policies or authorization logic. Run the Copy as cURL test in the self-check to see whether your signup accepts a role field.
is it safe to store role in supabase user metadata
Not for anything that grants access. Supabase's own docs say not to use user metadata in security-sensitive contexts, and the Security Advisor has a check for policies that reference it. The documented alternative is a user_roles table plus a custom access token hook that writes the role into the JWT on the server.
how should roles be assigned in an app built with lovable
Ask the builder to create a roles table that only the service role or an admin can write, and to read roles from server-issued claims rather than from the signup form. Lovable's Supabase integration gives you the dashboard where the Security Advisor and the auth hook live. Apiiro's 2025 analysis of AI-assisted repositories reported a sharp rise in privilege escalation paths, so re-run the signup test after each change.
Back to the catalogue, or run the self-check for your stack.