rls-policy

rls-policy is a cursor rule for Cursor from YuDefine/nuxt-supabase-starter. It costs 0 tokens per session (2,163 once invoked), scanned A, original, MIT.

A locked specification for Supabase row-level security, which controls which database rows each user or role may read or change. It covers policies, table permissions, storage uploads and trusted server access.

In plain words
What is it for?
Use it when creating database migrations, granting table access, writing row policies, protecting user data and configuring Supabase Storage operations.
Why use it?
It prevents false security assumptions, such as treating a privileged server role as protected by a policy it already bypasses, or forgetting permissions required for updates and uploads.

Cursor rule for Cursor

Written for Cursor: installed under .cursor/.

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add rules/yudefine/nuxt-supabase-starter/rls-policy
Clone the repo
git clone --depth 1 https://github.com/YuDefine/nuxt-supabase-starter

Made for: Cursor.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for rls-policy

README.md
[![agentmods](https://agentmods.dev/badge/rules/yudefine/nuxt-supabase-starter/rls-policy.svg)](https://agentmods.dev/rules/yudefine/nuxt-supabase-starter/rls-policy)
Your own site
<a href="https://agentmods.dev/rules/yudefine/nuxt-supabase-starter/rls-policy"><img src="https://agentmods.dev/badge/rules/yudefine/nuxt-supabase-starter/rls-policy.svg" alt="Measured on agentmods" height="20"></a>
Per session 0 Nothing until a file matches its globs; then the whole rule loads.
When invoked 2,163 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00000 $0.02163
Opus 5 $0.00000 $0.01081
Sonnet 5 $0.00000 $0.00433
Haiku 4.5 $0.00000 $0.00216

Measured 2d ago against content hash af31f4c08835, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-06, from the pricing page.

Security

Grade A, and why

rls-policy scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

template/.cursor/rules/rls-policy.mdc · 100 lines

How it starts

The opening of the file, as written. The whole thing — 100 lines — stays where its author put it; the contents beside it link to each section on GitHub.

RLS Policy

  • NEVER 在 write policy 加 (SELECT auth.role()) = 'service_role' 當 bypass 條件 — Supabase service_role 具備 PostgreSQL BYPASSRLS,本來就略過所有 RLS,policy 內加這條件對 service role 沒有任何實際保護作用,只會讓後續 agent 誤以為 privileged write path 由 policy 控制。privileged 寫入的安全邊界見下方「service_role 與 privileged client isolation」。
  • SELECT: TO public for client reads, TO authenticated for server-only
  • UPDATE policy 需要搭配 SELECT policy — Postgres RLS 的 UPDATE 必須先 SELECT row,缺少 SELECT policy 會靜默回傳 0 rows(無報錯)
  • Storage upsert 需要 INSERT + SELECT + UPDATE 三個 policy — 只有 INSERT 時新上傳正常,但覆蓋(upsert)會靜默失敗
  • NEVER use user_metadataraw_user_meta_data)in RLS policies — 使用者可自行修改,改用 app_metadata
  • See supabase-rls skill for policy templates and TO public 陷阱

本檔是 clade 投影,NEVER 就地編輯。專案特化寫進自家 .cursor/rules/local/;要改本檔請回 clade 源檔並 propagate。

GRANT 先於 RLS——table privilege 驗證

PostgreSQL 先檢查 table-level privilege(GRANT)再評估 RLS policy。只建 CREATE POLICY ... TO authenticated 但沒有對應的 GRANT SELECT ON <table> TO authenticated,結果是 42501(permission denied),RLS policy 完全不被評估

Migration 新增 RLS policy 時 MUST

  1. 同一支 migration 內顯式 GRANT <privilege> ON <table> TO <role>,或
  2. 註明 table 已有既存 GRANT(引用授予 GRANT 的 migration 編號)

驗證方式——在 dev DB 查 pg_catalog

SELECT grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_schema = '<schema>' AND table_name = '<table>';

若目標 role 不在結果中,RLS policy 寫再多都是死的。

靜默失敗陷阱

  • auth.uid() IS NULL 陷阱 — 未認證時 auth.uid() 回傳 null,null = user_id 永遠 false,policy 靜默拒絕。要明確區分「沒登入」與「沒權限」,在 policy 開頭寫 auth.uid() IS NOT NULL AND ...
  • DELETE 同理 UPDATE — 沒有 SELECT policy 時 DELETE 也靜默成功但不刪除任何 row
  • TO role 指定的 policy 會對所有 role 執行 — 明確指定 TO authenticatedTO public,避免 anon 不必要地觸發 policy 評估
  • Views 預設繞過 RLSCREATE VIEW 必須加 WITH (security_invoker = true),見 migration.md

Read the full file on GitHub · 100 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 100 lines · 0 tokens per session scan A af31f4c08835

Subscribe to this mod's changes

rls-policy is a cursor rule published in the GitHub repository YuDefine/nuxt-supabase-starter (45 stars, last pushed today), licensed MIT. It costs nothing until one of its globs matches a file; then it loads 2,163 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-03.