Access audit of baresql_fx_saas

21 October 2026, 09:00 UTC · PostgreSQL 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1) · 1 login · BareSQL 0.1.0

0high
1medium
1low
1logins that read personal data
5columns with personal data
BareSQL logged in as postgres (a superuser) over an unencrypted connection and read the system catalogs inside one read-only transaction. It read up to 200 rows of each table to see what the columns hold; the values were looked at in memory and are not in this report. For every login, the server's own privilege checks were asked about every table and column, and each answer below comes with the grant, membership, ownership or view that gives it.

Findings

MEDIUMRow security on app.audit_log is not forced and its owner saas_migrator can log in: sessions logged in as saas_migrator see every row.

rls-owner-login · app.audit_log

LOWRow security is on for app.api_keys but it has no policies: only its owner and roles that bypass row security see any rows.

rls-no-policies · app.api_keys

Who can read personal data

LoginPersonal dataColumnsTablesChangesNotes
saas_agentemail addressperson's name210

Columns and tables count base tables, partitions and materialized views, reached in any way listed below. Changes counts tables with personal data the login can insert into, update, delete from or empty.

Personal data in this database

ColumnHoldsHow BareSQL knowsRead by
app.accounts.email
table · text
email address
high confidence
30 of 30 sampled values are email addressessaas_agent
app.accounts.full_name
table · text
person's name
medium confidence
the column name suggests person's namesaas_agent
app.accounts.phone
table · text
phone number
high confidence
30 of 30 sampled values are phone numbersno audited login
app.api_keys.api_key
table · text
key, token or secret
high confidence
3 of 3 sampled values look like random tokens; 3 of 3 sampled values contain a key or tokenno audited login
app.audit_log.actor_email
table · text
email address
high confidence
20 of 20 sampled values are email addressesno audited login
support.ticket_context.email
view · text
email address
high confidence
comes from app.accounts.emailsaas_agent
support.ticket_context.full_name
view · text
person's name
medium confidence
comes from app.accounts.full_namesaas_agent
support.ticket_context_invoker.email
view · text
email address
high confidence
comes from app.accounts.emailsaas_agent
support.ticket_context_invoker.full_name
view · text
person's name
medium confidence
comes from app.accounts.full_namesaas_agent

Logins

saas_agent

member of saas_support · no password set

Personal data it can readHoldsHow
app.accounts.email
table
email address
  • column granted to saas_support; rows allowed by policy support_read
  • through view support.ticket_context (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_context_invoker (rights of the reader); rows allowed by policy support_read
app.accounts.full_name
table
person's name
  • column granted to saas_support; rows allowed by policy support_read
  • through view support.ticket_context (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_context_invoker (rights of the reader); rows allowed by policy support_read
support.ticket_context.email
view
email address
  • granted to saas_support
support.ticket_context.full_name
view
person's name
  • granted to saas_support
support.ticket_context_invoker.email
view
email address
  • granted to saas_support
support.ticket_context_invoker.full_name
view
person's name
  • granted to saas_support
17 other columns it can read
ColumnHow
app.accounts.id
  • column granted to saas_support; rows allowed by policy support_read
app.tickets.id
  • granted to saas_support; rows allowed by policy support_read
  • through view support.ticket_context (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_context_invoker (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_list (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_overview (rights of saas_owner), then through view support.ticket_list (rights of the reader); rows allowed by policy support_read
app.tickets.tenant_id
  • granted to saas_support; rows allowed by policy support_read
app.tickets.account_id
  • granted to saas_support; rows allowed by policy support_read
app.tickets.subject
  • granted to saas_support; rows allowed by policy support_read
  • through view support.ticket_context (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_context_invoker (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_list (rights of the reader); rows allowed by policy support_read
  • through view support.ticket_overview (rights of saas_owner), then through view support.ticket_list (rights of the reader); rows allowed by policy support_read
app.tickets.body
  • granted to saas_support; rows allowed by policy support_read
app.tickets.created_at
  • granted to saas_support; rows allowed by policy support_read
support.invoice_summary.id
  • granted to saas_support
support.invoice_summary.amount
  • granted to saas_support
support.ticket_context.id
  • granted to saas_support
support.ticket_context.subject
  • granted to saas_support
support.ticket_context_invoker.id
  • granted to saas_support
support.ticket_context_invoker.subject
  • granted to saas_support
support.ticket_list.id
  • granted to saas_support
support.ticket_list.subject
  • granted to saas_support
support.ticket_overview.id
  • granted to saas_support
support.ticket_overview.subject
  • granted to saas_support
2 columns it may select that give it nothing today
ColumnHow
app.invoices.id
  • through view support.invoice_summary (rights of saas_owner); no rows (row security on, no policy lets this role read)
app.invoices.amount
  • through view support.invoice_summary (rights of saas_owner); no rows (row security on, no policy lets this role read)

Everyone (PUBLIC)

What every role can read, including roles created after this audit.

No personal data is open to every role.

Method

Schemas audited: app, public, support. Connection: postgres://[email protected]:5432/baresql_fx_saas, login method md5.

BareSQL never calls a function written in SQL or a procedural language, never reads views or foreign tables, and never writes. Sampled values are turned into text by their type's own output function, never by a cast, and each table is read on its own, without its partitions or child tables. Views are traced to the columns they read from their stored definitions, without running them.

Every fact in this report is also in audit.json, which baresql diff and baresql audit --baseline compare with a later audit.