Anyone can obtain a signed-in session without an account
Your Supabase project allows anonymous sign-ins: one unauthenticated request returns a valid session token, with no email, no password and no verification.
0% · n=37 · as of 16 September 2026 of sites UseShipReady scanned had this, counted across sites where this check completed.
Why it matters
Your Supabase project allows anonymous sign-ins: one unauthenticated request returns a valid session token, with no email, no password and no verification. That is a deliberate feature for guest carts and try-before-signup flows, but it changes what every other protection means. A table policy written as "authenticated users only", an Edge Function that checks for a session, or an API route behind a login are all reachable by anyone who asks — including routes that call a paid model, send an email or send an SMS. Confirm this is intentional, and that anything which costs money or exposes data distinguishes an anonymous session from a real account.
How UseShipReady detects it
Tests whether a Supabase project is readable by anyone. The project URL and anon key are read from the page's own JavaScript — both are published there by design. The anon key is then used exactly as a browser would use it. ──────────────────────────────────────────────────────────────────────────── WHAT THIS USED TO ASK, AND WHY IT MISSED THE APPS IT EXISTS FOR ──────────────────────────────────────────────────────────────────────────── The probe list was twelve hardcoded names — users, profiles, orders, posts. A bakery app whose tables are `bakery_orders` and `pickup_slots` was therefore invisible, however wide open it was, and the report said nothing. That is the whole finding class this check exists for: CVE-2025-48757 documents Lovable+Supabase apps shipping tables with RLS off or set to USING (true), readable by anyone holding the anon key the front end publishes. Resources are now DISCOVERED rather than guessed, from three sources, and each finding records which one found it: client-code `.from("bakery_orders")`, `.rpc("claim_slot")` and `/rest/v1/...` paths in the site's own bundles — the strongest signal, because the application itself names the resource it depends on. postgrest-schema the project's own OpenAPI document at /rest/v1/, which PostgREST publishes to any holder of the anon key. This is schema METADATA — path names — not data. common-name the original twelve, kept as a supplement so a project whose bundle is unreadable is no worse off than before. ──────────────────────────────────────────────────────────────────────────── NO ROW IS EVER RETRIEVED ──────────────────────────────────────────────────────────────────────────── The old probe was `GET ...?select=*&limit=1` and it stored the returned row in `evidence.observed_response`. It proved the point by holding a copy of the customer's data — an email address, an address, whatever the first row held — in our logs and our database. The probe is now `HEAD` with `Prefer: count=exact`. A HEAD response carries no body at all; PostgREST answers with `Content-Range: 0-0/1523`, which is the count and nothing else. So the finding says "1,523 rows are readable with a key published in your own JavaScript" and the scanner has not read one of them. Returning zero rows is still not a finding. A table an anon key can reach but whose rows are all filtered is what correctly configured RLS looks like, and it is indistinguishable from an empty table — so neither is reported. ──────────────────────────────────────────────────────────────────────────── WHAT A READABLE TABLE DOES AND DOES NOT PROVE ──────────────────────────────────────────────────────────────────────────── A non-zero count proves one thing: the public anon key can read rows of that table. It does not prove RLS is disabled — a table with RLS enabled and a deliberate `for select to anon` policy answers the same probe identically, and the anon key cannot read pg_class or pg_policies to tell the two apart. Nor does it prove the access is unintended: a public leaderboard, a product catalogue or published content is meant to be read this way. So the finding says what was observed — the table is publicly readable — and is MEDIUM rather than critical. It used to be titled "Missing RLS Policy" at critical, which asserted a cause the scan never saw and scored a public leaderboard like a leaked customer table. A table name is not evidence either way, so severity is not raised for tables that merely sound sensitive. The guidance covers both cases: restrict the table if it is not meant to be public, and if it is, check every column, because RLS filters rows and does not hide columns. WRITE ACCESS IS NOT TESTED, deliberately. Establishing it means attempting an insert against a stranger's production database, and a table whose columns are all nullable would take the row. There is no non-destructive proof available from outside, so the finding states that read access was tested and write access was not, rather than implying both. The probe sequence is memoised on the discovered project, so a project referenced by ten pages is tested once rather than ten times.
Detection is deterministic. UseShipReady reports this only when it observes the condition directly, and prefers to miss a real problem over inventing one. Rule version 1.5.0.
How to fix it
This is the prompt UseShipReady puts in your report — written to be pasted straight into Cursor, Claude Code, or whichever assistant built the app.
Your Supabase project allows anonymous sign-ins, which means anybody can obtain a valid signed-in session with one unauthenticated request and no email, password or verification. That is a legitimate feature for a guest cart or a try-before-signup flow, but it changes what 'logged-in only' protects: any endpoint, table policy or Edge Function that trusts an authenticated session is effectively public, including ones that spend money per call. Confirm this is intentional; if it is, make sure your RLS policies distinguish `auth.jwt()->>'is_anonymous'` from a real account, keep paid operations behind a permanent account, and rate-limit anonymous sessions. If it is not intentional, turn it off in Authentication → Providers → Anonymous sign-ins.
Frequently asked questions
- What does "Anyone can obtain a signed-in session without an account" mean?
- Your Supabase project allows anonymous sign-ins: one unauthenticated request returns a valid session token, with no email, no password and no verification.
- How serious is it?
- UseShipReady rates this medium. Fix soon. Meaningfully weakens a defence or degrades how the site works.
- How common is this?
- Across the sites UseShipReady has scanned where this check completed, 0% · n=37 · as of 16 September 2026.
- How do I fix it?
- Paste the fix prompt on this page into Cursor, Claude Code or your AI editor. It is the same prompt UseShipReady puts in your report.
- Can I check my own site?
- Yes — UseShipReady scans up to ten pages of any public site for free and reports this alongside every other check. The free report lists every issue it finds and shows full evidence and a fix prompt for the critical and high-severity ones; medium and low findings are counted and unlock on Pro.
Related checks
Run this check on your site
UseShipReady checks this and 196 other things across up to ten pages of your site, with an AI-ready fix for each. Free, no signup.