Security

The mailbox is the biggest ask. Here is what protects it.

Four decisions carry most of the risk in a product like this. Each one was made deliberately, and each one is checked by the test suite rather than by good intentions.

Last updated 30 August 2026

Isolation lives in the database, not the code

Every table belonging to a workspace has PostgreSQL row-level security enabled and forced, and the application connects as a role that does not own those tables — so the policy applies to it too. A query that forgets to filter by workspace returns nothing rather than everything, because a missing workspace context matches no rows.

The test suite discovers those tables by reflection, so a new one cannot be added without being covered.

It cannot send mail, and not because it promises not to

The narrowest Gmail scope that permits drafts also permits sending; Google publishes no draft-only scope. So the guarantee cannot come from OAuth, and it is not left to hope either:

  • There is no send method in the Gmail client to call.
  • Sending is classed as a high-risk action by the approval engine, which refuses it at every confidence level.
  • A demo visitor holds no permission with an external side effect at all — asserted when the process starts, so it cannot boot otherwise.

Credentials are not in the database

A Gmail refresh token is the most dangerous credential this system will ever hold. It lives in AWS Secrets Manager; the database keeps only a reference to it. A database backup, a stray SELECT * typed while debugging, or a log line that dumped a row contains no usable token.

Each connection is separate and each can be revoked on its own from Settings, which deletes the credential as well as the grant.

Every route declares what it requires

Permissions are not a convention here. Each API route names the permission it needs, and the process refuses to start if any route does not — so a new endpoint cannot ship accidentally open.

Everything consequential is written to an append-only audit log in the same transaction as the change it records, which is also what makes the timeline trustworthy: state, timeline entry and audit row commit together or not at all.

What is deliberately not claimed

There is no SOC 2 report, no penetration test, and no security team — this is one person’s project, and pretending otherwise would be the least secure thing on the page. What there is: a small attack surface, no third-party scripts, encryption in transit and at rest, and the decisions above written down where they can be checked.

Found something? Email mike@mikemiller.ai — a real report gets a same-day answer. See also the privacy policy.