DaemonCoreDBX home
Acme ProductionPRODUCTION
Run Scan
Findings
Critical

Potential cross-tenant access through SECURITY DEFINER function

Affected:
public.get_invoice(uuid)
Category:
Tenant Isolation
Confidence:
high
First detected:
2026-08-12 11:04Z
Last verified:
2026-08-16 09:41Z

Summary

public.get_invoice(uuid) runs with the privileges of its owner, is executable by authenticated, and reads public.invoices without an ownership constraint in the evaluated path.

Why this matters

Row Level Security on public.invoices is not applied inside a definer-rights function. Any signed-in user who can guess or enumerate an identifier can retrieve records belonging to another organization, and the function is reachable directly over the REST RPC endpoint.

Evidence

Role
authenticated
Object
public.get_invoice(uuid)
Function security
SECURITY DEFINER
search_path
public, pg_temp
Executable by
authenticated
Target relation
public.invoices
Exposed via RPC
true
Tenant validation
No qualifying ownership constraint detected in evaluated path

Facts above were derived by the scanner from database metadata. No model output is involved in the verdict.

Technical details

pg_proc.prosecdef is true and EXECUTE is granted to authenticated. The function body selects from public.invoices, whose tenant column is never compared against the caller's resolved tenant. Because the function owner bypasses RLS, the table's policies do not constrain the result set.

Attack path

definerdefinerINTERNETINTERNETanonymousROLEauthenticatedROLE!Data APIPOSTGRESTRPC/REST/V1/RPCget_invoice()SECURITY DEFINERrefresh_usage_total…SECURITY DEFINER!v_customer_billingDEFINER VIEW!profilesRLS ENABLED!invoicesRLS ENABLEDsupport_ticketsRLS ENABLED!webhook_endpointsRLS ENABLEDpricing_plansRLS ENABLEDsubscriptionRLS DISABLED!_http_responseRLS DISABLED!avatarsPUBLIC BUCKET!

internet → authenticated → rest → rpc → fn:public.get_invoice(uuid) → public.invoices

recommended remediation

Unlock the full security analysis

Buy full analysis

Constrain the definer function to the caller's tenant, or drop definer rights and let RLS apply.

Current

CREATE OR REPLACE FUNCTION public.get_invoice(uuid)
RETURNS SETOF public.invoices
LANGUAGE sql
SECURITY DEFINER
SET search_path = public, pg_temp
AS $$
  SELECT * FROM public.invoices WHERE id = $1;
$$;

Proposed

CREATE OR REPLACE FUNCTION public.get_invoice(uuid)
RETURNS SETOF public.invoices
LANGUAGE sql
SECURITY DEFINER
SET search_path = public, pg_temp
AS $$
  SELECT *
  FROM public.invoices
  WHERE id = $1
    AND organization_id = current_tenant_owner();
$$;

REVOKE EXECUTE ON FUNCTION public.get_invoice(uuid) FROM public;
GRANT EXECUTE ON FUNCTION public.get_invoice(uuid) TO authenticated;

Expected security effect

  • Authentication required
  • Tenant ownership enforced inside the definer boundary
  • Cross-tenant access path removed
  • EXECUTE narrowed to authenticated

Compatibility risk

low

Internal jobs that call this function outside a user session will resolve no tenant and receive zero rows. Give them a separate service-role path.

DBX never applies SQL to your database.