// Lab note — 2026.10.29

Thirty-five tables, no policies, and nobody looking

#SecurityInvestigated to 2026.08.19From GetPharm

The question

What is actually reachable with the public API key of a database I have been treating as private?

What I assumed going in

That row-level security was on, because I had been enabling it per table as I added them. I was not auditing. I was adding an unrelated table and happened to look.

What I actually did

The data API was enabled and all 35 public tables were granted to the anonymous and authenticated roles with zero policies. Anyone holding the public key could read, modify or truncate production — including the table holding one-time sign-in codes, which is an authentication bypass rather than a data leak.

The field-level encryption on identifiers, licences and bank details was the only layer that had been doing its job.

What I learned

Closed the same day by disabling the data API, after verifying that nothing in the application used it. Then wrote a hardening script as a guard against it being turned back on.

The real finding is not the misconfiguration. It is that the control was my memory. Enabling security per table, by hand, as you go, works exactly as long as you never forget — and the failure mode is silent, undated and indistinguishable from success.

The later platform does it differently: every table gets row-level security, a restrictive no-access policy and no grants, and a database trigger locks each new table the moment it is created. There is nothing to remember.

What is still uncertain

Whether the trigger approach survives a migration tool that creates tables in a way the trigger does not see. I have not tried to break it on purpose.

What I would test next

Write a test that creates a table through each path a migration might take, then asserts from outside — using the public key, as an attacker would — that it answers nothing.

Found by accident while doing something else, which is the only reason it was found at all.

Logged 2026.10.29 · AshishNext note ↗
B-SIDEOff the record