Skip to content

docs: schedule closing the role-grant escalation gap before U-3 - #74

Merged
yufoxda merged 2 commits into
developfrom
docs/record-role-rls-gap
Sep 9, 2026
Merged

yufoxda merged 2 commits into
developfrom
docs/record-role-rls-gap

Conversation

@yufoxda

@yufoxda yufoxda commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

U-1(#73)のレビューで見つかった不足を、作業単位として記録します。あわせて U-1 自身の誤りを2点訂正します。

前提: 20260904000000_add_role_tables.sql はまだ本番に適用していません。適用済みマイグレーションを書き換えているわけではないため、この修正は安全です。

見つかった不足 — ロール付与が申告だけで通る

U-1 が入れたポリシーは、アプリが申告したロールだけを見ています。

with check ((select current_setting('app.current_user_role', true)) = 'admin')

members はこの守り方をしていません。 RLS に加えて app_private.enforce_member_workflow が、申告されたロールを app_accounts の実値と突き合わせます。アプリ層が侵害されても権限を偽装できないようにするためで、これが制約 C-4 の趣旨です。

member_roles は全権限の源泉であり、members より価値の高い標的でありながら、2つのうち弱いほうの防御しかありません。

現時点の危険はありません。 U-3 で判定を移すまで誰もこのテーブルを読み書きしないためです。ただし U-3 がまさにその境目なので、U-2.5 として U-3 の前に置きます。

U-1 → U-2 → U-2.5 → U-3 → U-4
              ↑ ここで閉じる

U-1 の訂正2点

① 要件範囲の過大申告

FR-4.1「ロールを作成・変更・削除できる」を実装したと書いていましたが、していません。app_roles には select しか付与しておらず、ロールを作る経路がありません。ロール管理は U-5 の範囲です。正しくは FR-4.2・4.3・4.6 です。

② コメントが存在しない強制を主張していた

is_system に「管理者が削除できない」と書いていましたが、強制していません。現状 delete 権限自体がないため実害はありませんが、コメントを実態に合わせ、U-5 で守るべきものとして書き直しました。

あわせて、管理者バックフィルの on conflict do nothing を削除しました。app_accounts.member_id が unique なので到達しません。前提が崩れた場合は黙って飛ばすより止まるほうが安全です。

🤖 Generated with Claude Code

A review of U-1 found the new policies on member_roles trust the role the
application claims, and nothing else:

    with check (current_setting('app.current_user_role', true) = 'admin')

members is not defended that way. It carries the enforce_member_workflow
trigger alongside its policies, which checks the claimed role against what
app_accounts actually says, so a compromised application layer cannot promote
itself. That is what constraint C-4 is for.

member_roles is where every permission now comes from — a higher-value target
than members — and has the weaker of the two defences. Nothing reads the table
until U-3 moves the checks across, so there is no exposure today, but U-3 is
exactly the point where this stops being theoretical. It becomes U-2.5, ordered
before it.

Also corrects two things in U-1 itself. Its requirement list claimed FR-4.1,
which it does not implement: there is no way to create or delete a role, only
select is granted, and role management is U-5's work. And the is_system comment
described an enforcement that does not exist, while the ON CONFLICT clause on
the admin backfill could never fire, since app_accounts.member_id is unique.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yufoxda
yufoxda merged commit 0531cfc into develop Sep 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant