Supabase is one part of HIPAA compliance

By Munaf Khatri · October 29, 2026

Storing PHI on Supabase requires a signed BAA and a project set to High Compliance. Those cover the platform. They do not cover the RLS policies, functions or audit tables inside the project, and a HIPAA review will ask about those as well.

Supabase's shared responsibility model says the same. It asks customers to "always apply Row Level Security (RLS)" and leaves the access rules on sensitive tables to them.

What Supabase handles

On the hosted platform, Supabase encrypts data at rest and in transit, signs the BAA and checks project settings. Its HIPAA guide asks for Point in Time Recovery, SSL enforcement, network restrictions and Postgres connection logging to be turned on, and for MFA on every account with access to the project. The Security Advisor raises a warning if any of these is switched off.

The advisor and the database linter also flag some risky patterns, such as a table in public with RLS turned off. Neither of them runs the policies, so neither can say whether a nurse at one clinic is able to read visits from another, or whether a deleted record left a trace in the audit table.

What stays with the project owner

A HIPAA review asks three questions about the database.

These map onto the Security Rule. Access control falls under 164.312(a)(1), which requires that access go "only to those persons or software programs that have been granted access rights". Audit controls fall under 164.312(b). Integrity, under 164.312(c)(1), concerns protecting PHI "from improper alteration or destruction". 164.312(d) covers authentication, and 164.308(a)(8) requires all of this to be evaluated periodically and whenever the environment changes.

On Supabase, almost all of this lives in SQL written by the project team. A screenshot of the policies cannot show what the database actually does when authenticated calls one of those functions.

Collecting the evidence from a Supabase project

UnitAutogen covers this part with the unitautogen hipaa command, run from the project folder while the local stack is up.

supabase start
unitautogen --supabase hipaa --schema public

It connects to the local database reported by supabase status. That database is built from the migrations, so no patient data is involved at any point. The tool generates the tests and the rows they need, runs them and rolls the rows back. The report is written to supabase/tests/seccover/hipaa/public/, and the security tests it generates go into supabase/tests/seccover/security/, where supabase test db picks them up.

PHI tables are identified from the schema. Where the tool gets one wrong, the correction goes in a unitautogen.toml file in the project folder. Every entry taken from that file is labelled in the report, so a declaration is never read as a finding.

[phi]
tables = ["public.patients", "public.visits"]
not    = ["public.countries"]

[audit]
tables = ["audit.change_log"]

What it checks

Access. Functions, views and triggers that run as their owner bypass row policies. Each one is called as two different tenants, with data present on both sides, and reported as holding or leaking, along with the table, command and role. Row policies, column grants and personal data that escapes through error messages are covered as well.

The audit log. For every PHI table, and for each of insert, update and delete, the report states whether the change left an audit row. Each result is recorded, conditional, cancelled by the trigger, or untested. This matters on Supabase because connection logging, which the HIPAA guide asks to keep on, records only who connected and says nothing about which rows changed.

Tampering. For each audit table and each client role, the report checks whether that role can edit it, erase it or forge rows in it. One way this fails is a SECURITY DEFINER function exposed through .rpc() that writes to the audit table, which lets any logged-in user call it and write whatever they like.

Identity. Policies rely on auth.uid() and auth.jwt(). The report checks whether a client session is able to change what those return.

Everything goes into one HTML report with a JSON copy. Each safeguard is marked as evidence or partial, the gaps are ranked alongside the change that fixes each one, and the report is stamped with the database, the time, the role, the tool version and a SHA-256 of every file it drew on. If the report is edited afterwards, the hashes no longer match.

Running it on every schema change

Most Supabase changes arrive as a migration in a pull request, and Supabase already documents a GitHub Action that runs supabase test db. Adding the hipaa command to the same job, and keeping the dated report as a build artifact, covers the evaluation safeguard and removes the rush before each audit.

What it does not do

The report is evidence for an auditor and does not certify anything. It does not look at encryption or transmission, which Supabase handles, and it does not review logs. It also cannot judge whether a policy is the right policy. If a rule is wrong by design, the report will say the database enforces it, because it does. The risk analysis, the written policies and the BAA itself remain the responsibility of the organization.

unitautogen hipaa is part of the Enterprise edition of UnitAutogen for PostgreSQL. Early-stage Supabase teams can ask about the startup rate, and a free trial is available for running it on a real schema first.