Security & Data Protection
Last updated: July 2026
Why has_role stays executable under RLS
Our backend uses Row-Level Security (RLS) to make sure users can only read or change data they are allowed to see. Several policies need to know whether the current user is an admin, and they do that by calling a small helper function named has_role.
PostgreSQL evaluates RLS USING and WITH CHECK expressions under the calling role. If authenticated users could not execute has_role, every admin-gated RLS policy would fail at planning time and the protected tables would become unreachable.
Keeping has_role executable is safe because the function:
- Is marked
STABLEandSECURITY DEFINER, so it runs with the privileges of its owner, not the caller. - Has a fixed
SET search_path = public, preventing search-path injection. - Performs only a bounded
SELECT EXISTSagainstpublic.user_roles. - Returns only a boolean and never writes data, reads unrelated tables, or exposes user details.
In short, has_role is the canonical RLS helper for this app; revoking it would break access control rather than improve it.
Resolved security findings
The following findings were reviewed and addressed. Each fix was verified by re-running the security scan before marking it complete.
Anon access to security definer functions
ID: SUPA_anon_security_definer_function_executable
Revoked EXECUTE on email-queue helper functions from the PUBLIC, anon, and authenticated roles so unauthenticated users cannot invoke them directly.
Authenticated access to security definer functions
ID: SUPA_authenticated_security_definer_function_executable
Revoked EXECUTE on email-queue helper functions from authenticated users. The has_role helper remains executable intentionally because every admin-gated RLS policy relies on it (see below).
Mutable search path in security definer functions
ID: SUPA_function_search_path_mutable
Added SET search_path = public, pgmq to the email-queue helper functions so object resolution is deterministic and cannot be redirected by a malicious search_path.
Missing INSERT policy on contact leads
ID: contact_leads_no_insert_policy
Added a RESTRICTIVE INSERT policy that blocks direct inserts by anon and authenticated roles. Contact and quote forms submit through a trusted server route that writes with the service role, so leads are still captured while direct client writes are denied.
How we handle form submissions
Contact and quote forms post to server-side routes, not directly to the database. Those routes validate the input, write the lead record using a trusted service role, and then trigger notification emails. Because direct client inserts are explicitly blocked by RLS, a browser or API client cannot add leads on its own.
Questions?
If you have questions about how we protect your information, email eortiz@healthmarkets.com or call 402-699-2586.
