fix(security): getReadFilter 对 on-behalf-of 读 fail-closed 哨兵(#2852 Gap 1 潜伏面) - #2988
Merged
Conversation
…Filter (#2852) getReadFilter — the read-scope provider the analytics/raw-SQL path binds to — resolves only the caller's own ceiling; the ADR-0090 D10 delegator RLS intersection that the engine middleware applies to find/count/ aggregate is absent on this path. Computing a filter here for a delegated (on-behalf-of) context would silently widen the read past the delegator's scope — the confused-deputy widening D10 prevents on the CRUD path. Until the intersection is threaded through computeRlsFilter (tracked with #2920 B1 / ADR-0095 D1), deny fail-closed (deny sentinel + error log) when context.onBehalfOf.userId is set. System on-behalf-of bypasses ahead of the guard; no agent surface reaches analytics today, so this is a latent-invariant guard, not a live-traffic change. Tests: 2 new getReadFilter cases (delegated context → deny sentinel + logged; system on-behalf-of → bypass). plugin-security 441 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012RE5oFswe4DUvExuAgvbg2
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 15, 2026 16:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
目的
关闭 #2852 剩余的 Gap 1 的潜伏面(Gap 2
/analytics/query无 context 已在 #2956 修复)。getReadFilter——analytics/raw-SQL 路径绑定的 read-scope 提供者——只解析调用方自身 ceiling;engine middleware 对 find/count/aggregate 施加的 ADR-0090 D10 delegator RLS 交集(resolveDelegatorContext,security-plugin.ts:689)在这条路径上缺位。因此对一个 delegated(onBehalfOf)上下文在这里算 filter 会静默放宽到 agent 自身(更宽)的 scope,正是 D10 在 CRUD 路径上防住的 confused-deputy 放宽。改动(哨兵,非完整交集)
getReadFilter在context.onBehalfOf.userId存在时 fail-closed:返回RLS_DENY_FILTER+ 响亮 error 日志,而不是 under-scope。与该函数已有的 fail-closed 风格(解析失败分支)一致。isSystem短路在哨兵之前(engine 自调用不被拒)。/mcp,不暴露 analytics——这是潜伏不变量守卫,不是 live 行为变更。把「将来某人把 analytics 桥进 agent 面时静默放宽」提前变成「显式拒绝 + 报错」。为什么是哨兵而非完整交集
完整修复要把 delegator 交集下沉进
computeRlsFilter/共享 helper(单缝,避免复制 middleware↔service 分叉),而 #2920 B1(租户隔离拆 Layer 0,ADR-0095 D1)会重构同一条缝。现在精雕会与 B1 冲突/白做,故只落 fail-closed 哨兵,完整交集随 B1(issue #2852 已记录两档计划)。验证
@objectstack/plugin-security:441 passed(新增 2:delegated context → deny sentinel + 日志;system on-behalf-of → 豁免放行)关联
#2852(read-scope D10 缺口,Gap 2 已修)· ADR-0090 D10 · #2920 B1 / ADR-0095 D1(computeRlsFilter 重构缝,完整交集落点)· #2949(explain-vs-enforcement 分叉先例)
🤖 Generated with Claude Code
https://claude.ai/code/session_012RE5oFswe4DUvExuAgvbg2
Generated by Claude Code