{
  "id": 7340213,
  "title": "Postgres RLS in Symfony: three green isolation tests, and the UPDATE that moves tenant 1's invoices into tenant 2's books",
  "url": "https://urgent.news/2026/09/14/postgres-rls-in-symfony-three-green-isolation-tests-and-the-update",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-09-14T15:06:17.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/mollenthiel/postgres-rls-in-symfony-three-green-isolation-tests-and-the-update-that-moves-tenant-1s-invoices-4bjh"
  },
  "original_language": "en",
  "account": "In a recent investigation, it was discovered that the Postgres role responsible for running migrations bypasses every row-level security policy. This revelation led to the creation of three assertions that cover every broken database environment. Marco highlighted that these assertions never leave the enforcement boundary they are checking, making a green suite testing ineffective. A single line of SQL revealed that tenant 1 could move every one of its invoices into tenant 2's books using just one statement, while all isolation tests remained green.\n\nThe issue arises when a table has FORCE ROW LEVEL SECURITY, making the owner subject to the policy. This becomes apparent during the seeding process, where the connection is the owner, and the policy reads current_setting( app.tenant_id ). The seeding step runs as the owner, under FORCE with no context, causing the first two tenants' rows to be refused due to the policy. The obvious fix is to relax the check by creating a policy that allows tenant_id to match current_setting(app.tenant_id). However, this fix inadvertently creates a hole in the security system, allowing tenant 1 to move every one of its invoices into tenant 2's books while all isolation tests remain green.",
  "summary": "Two articles ago I wrote that the Postgres role which runs your migrations bypasses every row-level security policy. Last week I wrote that with one tenant in the fixture, your isolation suite passes with no policy at all. Both came out of the same comment thread, and by the end of it we had three assertions that, together, cover every broken database I had been able to build. Then Marco pointed…",
  "key_points": [
    "Postgres role bypasses row-level security policies during migrations",
    "Tenant 1 can move all invoices into tenant 2's books with one SQL statement",
    "Fixing policy allows security hole for tenant 1 to move invoices"
  ],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}