PostgreSQL / Supabase security intelligence

You vibe coded the app.
Who audited the database?

DBX reconstructs how your database can actually be reached — across RLS policies, grants, functions, storage, relationships, and tenant boundaries.

Zero credentials Deterministic engine Explainable findings

attack surface · acme productionsnapshot 04:12z
unauthenticatedEXECUTE → PUBLICelevatedrls bypassedfk: customer_idANONYMOUS USERROLE: ANONPUBLIC APIPOSTGREST / REST V1profilesRLS ENFORCEDordersRLS ENFORCEDRPC FUNCTIONGET_CUSTOMER_DOCUMENT()SECURITY DEFINERSEARCH_PATH MUTABLECUSTOMERS18,291 ROWSCUSTOMER_DOCUMENTSSTORAGE.OBJECTS →audit_logAPPEND ONLY
evaluating reachability…
43/100

database security

4 CRITICAL7 HIGH11 MEDIUM

engine

We don't check your code.
We check what your database actually allows.

Migrations describe intent. Permissions describe reality. DBX introspects the live security objects — policies, grants, routines, buckets, relationships — and resolves what each identity can reach in practice.

47
tables introspected
83
policies parsed
112
grants resolved
91
relationships traced
schemaforge://snapshot/acme-productionread-only · no credentials

deterministic findings

Every verdict arrives with its evidence.

CRITICAL

Anonymous users may reach customer documents

attack path

  1. ANON
  2. PUBLIC RPC
  3. SECURITY DEFINER
  4. CUSTOMER_DOCUMENTS
affected
18,291 potential records
evidence
public.get_customer_document(uuid)
reason
Function executes with elevated database privileges and does not enforce tenant ownership before returning the requested object.
HIGH

Tenant boundary not enforced on invoice documents

attack path

  1. AUTHENTICATED
  2. INVOICES
  3. INVOICE_DOCUMENTS
  4. STORAGE.OBJECTS
affected
6,402 potential records
evidence
policy invoice_documents_select ON public.invoice_documents
reason
The policy predicate filters on invoice_id alone. The relationship to the owning tenant is never evaluated, so any authenticated caller holding an invoice id can read the object.

database x-ray

Nine surfaces. One verdict each.

The scanner decomposes the database into the surfaces an attacker actually traverses, then reports what each one currently permits.

AUTH2 WARNINGSRLS12 ISSUESTABLES47 MAPPEDFUNCTIONS3 DANGEROUSSTORAGE1 EXPOSEDGRANTS6 EXCESSIVETENANT ISOLATIONFAILEDRELATIONSHIPS91 TRACEDINDEXESCLEANDATABASEPOSTGRES 15.6

path analysis

Findings are useful.
Attack paths are better.

A weak policy may look harmless by itself. DBX connects individual weaknesses to determine whether they form a usable path through your database.

attack path
5 hops
severity
critical
confidence
high
no sessionEXECUTE → PUBLICdeniedruns as ownerrls bypassedobject_idsigned readINTERNETUNTRUSTEDANONROLE: ANONAPIREST + RPCCUSTOMERSTABLERPCGET_CUSTOMER_DOCUMENT()RLS BLOCKPOLICY ENFORCEDSECURITY DEFINERELEVATED PRIVILEGESDOCUMENTSCUSTOMER_DOCUMENTSSTORAGESTORAGE.OBJECTSCUSTOMER FILEOBJECT REACHABLE

posture

43

Database security score

The score is a function of the findings, not an opinion. Every point deducted maps to a specific rule, a specific object, and the evidence that triggered it.

RLS
31
Tenant isolation
22
Function security
58
Permissions
71
Storage
64
Data integrity
89

remediation

Don't just find it.
Fix it.

Each deterministic finding carries a proposed migration tied to the exact object that produced it, with the expected security effect and the compatibility risk stated up front. Nothing is applied to your database for you.

currentreachable by anon
create policy "documents_select"
on public.customer_documents
for select
to anon, authenticated
using (true);

create function public.get_customer_document(doc uuid)
returns setof customer_documents
language sql
security definer
as $$
  select * from customer_documents
  where id = doc;
$$;
remediatedtenant enforced
create policy "documents_select"
on public.customer_documents
for select
to authenticated
using (
  tenant_id = (select auth.jwt() ->> 'tenant_id')::uuid
);

create function public.get_customer_document(doc uuid)
returns setof customer_documents
language sql
security invoker
set search_path = public
as $$
  select * from customer_documents
  where id = doc;
$$;

zero credentials

We don't want
your database password.

  1. 01

    Your database

    you run the introspection

  2. 02

    Read-only introspection

    catalog metadata only

  3. 03

    Security snapshot

    no rows, no data

  4. 04

    DBX

    snapshot in, findings out

  5. 05

    Deterministic analysis

    rules over evidence

No database password

No persistent connection

No agent

No production write access

The snapshot contains catalog metadata — schemas, policies, grants, routines, relationships. It never contains your rows. If the snapshot leaked, an attacker would learn what you already publish in your migrations.

Read the methodology

You vibe coded
the app.

Who audited
the database?

AI can generate PostgreSQL policies in seconds. That doesn't mean those policies actually isolate your customers.

pricing

Pay per audit. No subscriptions.

We don't want to be another monthly SaaS subscription. Scan your database, get the facts, fix your vulnerabilities, and move on.

Note: DBX operates entirely in your browser. We have zero data retention. Please save your PDF reports or remediation SQL before closing the tab.

Scanner Console

$0

  • Introspect unlimited schemas
  • View database topology & score
  • See finding counts and severity
  • Local analysis (data never leaves browser)
Run free scan
one-time

Full Security Report

$99 / 5 database scans

  • Valid for up to 5 unique databases
  • Unlock exact vulnerability details
  • Complete attack path graphs
  • Copy-paste SQL remediation
Explore the demo

Can someone reach something in your database that they shouldn't?

Run a read-only introspection and get an evidence-backed answer in under a minute.