Sign-ups need no email confirmation
Anyone can create a working account with any email address, including one they don't own.
- Severity
- Low
- Who can exploit it
- Anyone
- Found by
- PatchLabs Code: supabase/config.toml
- Lab proof
- Not lab-proven: file and line in the report
What it is
With email confirmation off, signUp() returns a working session straight away, for any address typed in. The account works before anyone proves they own the inbox. On its own that is a product decision, which is why this finding is low severity. It becomes a security problem in two situations:
- Access decided by email. A policy or admin check such as
(auth.jwt() ->> 'email') like '%@yourco.com'is passed by signing up with any new address at that domain. An allow-list of addresses is passed by signing up with one that hasn't registered yet. - Rules that trust "signed in". Every PL-002 and PL-012 becomes reachable by a script creating throwaway accounts with no inbox behind them.
Why AI builders produce it
Confirmation emails need an email provider and slow down testing, so they get switched off during development. The local supabase/config.toml created by the Supabase CLI has confirmations off by default, and that file reaches a hosted project if someone pushes the config.
Example of vulnerable code
Simplified from the patterns we see in AI-built apps. Synthetic: not taken from any real app.
# supabase/config.toml
[auth.email]
enable_signup = true
enable_confirmations = false
-- ...together with a policy that trusts the email claim
create policy "Staff read all orders"
on public.orders for select to authenticated
using ((auth.jwt() ->> 'email') like '%@yourco.com');
Check it yourself
Check the hosted project first: in your Supabase dashboard's authentication settings, the Email provider's Confirm email option should be on. Hosted projects start with it on. Then check the repo and your policies:
# In the repo
grep -n "enable_confirmations" supabase/config.toml
-- Policies that decide access from an email address
select tablename, policyname, qual, with_check
from pg_policies
where coalesce(qual, '') ilike '%email%'
or coalesce(with_check, '') ilike '%email%';
The fix
# supabase/config.toml
[auth.email]
enable_confirmations = true
And decide staff access from a table you control, not from what an address looks like:
drop policy "Staff read all orders" on public.orders;
create policy "Staff read all orders"
on public.orders for select to authenticated
using (exists (
select 1 from public.user_roles r
where r.user_id = (select auth.uid()) and r.role = 'staff'
));
Code findings come with the file, the line and a one-line fix in the report, for your engineer to make. PatchLabs never pushes to your repo.
How PatchLabs finds it
[SCAN] supabase/config.toml:42 [auth.email] enable_confirmations = false LEAK [FIX] confirm email in config and in the dashboard
PatchLabs reads your repo only, so it sees supabase/config.toml, not the live setting in your hosted project. When the file says confirmations are off, the report asks you to check the dashboard too. If the file is missing, there is nothing to flag, but the dashboard setting still matters.
When the pattern is intended
Fine for apps where an account holds nothing private and no access depends on the email address. Apps that sign in only with magic links or OAuth prove inbox or account ownership at every sign-in anyway.
Why it’s rated low
Low, because it exposes nothing by itself. It raises the stakes of other findings: with no confirmation, "anyone who signs up" means anyone with a script, using any address.
Related findings
Any signed-in user can read every row
Signing up unlocks other people's rows. If sign-up is open, that means anyone.
PL-019Access decided by user_metadata, which users can edit
Roles stored where users can rewrite them. One call from the browser and they're an admin.
PL-013 · comingUsers can make themselves admin
A role column or roles table that users can write to. One request turns a normal account into an admin.
Free check
Does your app have PL-018?
Paste your public repo. PatchLabs Code reads it for this and every other code finding, and the Lab rebuilds your database to test who can read what.
Last reviewed 10 Nov 2026. Finding IDs are stable: link to them freely. Spotted a mistake? Tell us.