Skip to Content

v0.1.73 — 15 May 2026

Bug Fix — MCP-created collections now have RLS and permission policies applied

Who is affected: Anyone who used the MCP collections tool to create collections. All such collections were created without Row Level Security, making their data accessible to any authenticated Supabase session regardless of the DaaS permission model.

What was wrong

The MCP tool executed CREATE TABLE but skipped the two post-creation steps that the UI has always performed:

  1. change_table_owner — transfers table ownership so the SECURITY DEFINER function can create policies.
  2. apply_rls_to_collection — enables RLS and creates the full set of DaaS access policies (admin bypass, permission-based CRUD, and optional self-access for tables with a user_id column).

Additionally, the resource_uri performance index was not created, degrading query speed on every scoped API call for affected collections.

What changed

The MCP tool now performs all three steps immediately after CREATE TABLE, matching the UI behaviour exactly. New collections created via MCP are indistinguishable from those created via the UI with respect to RLS.

Upgrading — existing collections

A backfill migration is included: supabase/migrations/20260508000001_backfill_rls_mcp_collections.sql

It automatically applies RLS and the standard policies to every collection registered in daas_collections that currently has RLS disabled. Run it via supabase db push (or your normal migration pipeline).

Action required

If you have collections created via MCP, run the backfill migration before your next production deployment to close the permission gap.

supabase db push

Before / After

PropertyBefore this fixAfter this fix
RLS enabled on MCP-created table❌ Off✅ On
Admin bypass policy❌ Missing✅ Created
Permission-based policies (read/create/update/delete)❌ Missing✅ Created
Self-access policies (tables with user_id)❌ Missing✅ Created
resource_uri index❌ Missing✅ Created

AWS RDS environments

On RDS there is no true superuser, so the change_table_owner step may log a warning: must be able to SET ROLE "postgres". This is harmless — apply_rls_to_collection is independently SECURITY DEFINER and has sufficient privileges to enable RLS and create policies on its own.


Bug Fix — services.custom(name, { elevated: true }) now correctly elevates permissions in nested services

Who is affected: Anyone who calls services.custom('name', { elevated: true }) from a runtime extension or cron job, or anyone who experienced Custom service "name" not found or inactive errors from extensions in production.

What was wrong

Issue 1 — opts ignored: Passing { elevated: true } as the second argument to services.custom() had no effect. The nested custom service always ran with the calling user’s original permissions, so restricted writes inside the service were still blocked.

Issue 2 — production cache miss: In production Next.js builds, calling services.custom() from an extension could throw Custom service "name" not found or inactive even when the service was active. This happened because Next.js evaluates module singletons in separate chunk contexts — after a service was updated via the API, the extension runtime’s cache was empty and the lookup failed.

What changed

{ elevated: true } is now properly forwarded into the nested service’s accountability, bypassing its permission checks while the calling user is still recorded in the audit trail (user_created/user_updated and daas_activity).

The cache-miss issue is resolved with a database fallback: on a cache miss, the runtime now queries daas_custom_services directly and compiles the service on demand.

Before / After

ScenarioBefore this fixAfter this fix
services.custom('svc', { elevated: true }) from extension❌ opts ignored — policies still enforced✅ admin acc propagated — permission checks bypassed
services.custom() from extension after service update (production)❌ May throw “not found or inactive”✅ Falls back to DB lookup and compiles on demand
Triggering user in user_created / daas_activity when elevated✅ Preserved✅ Still preserved
Last updated on