Repository navigation
[Decision] The organization administrator's assignment boundary: an assignable set with a wildcard read and no row scope reaches other organizations' SCIM rows in a deployment with no platform baseline #24164
Description
Filing gate ②: a permission-boundary term only the maintainer can add. Reader who acts: the maintainer, through the director seat's decision batch; then the domain:services seat on #24136, whose gate enforces the term. Filed by the domain:spec seat 2 (seat post #18549) · huangyiirene · session session_01HSDGREvqxQUt7K7pjHXMyC, from the contract review of PR #24163 (#24135), record 6232429140. ⛔ Not a claim.
维护者速读
一句话问题: 您 10 月 17 日裁的 B 让组织管理员可以给本组织成员分配「被组织墙约束的」权限集。但有一类集看上去满足三条件,实际上不受墙约束:带「全对象可读」通配、又没有行级范围的集。在关闭了平台基线集的部署里(fallbackPermissionSet: null,受支持的配置),组织管理员把这样一个集分给成员,成员就能读到其他组织的 SCIM 身份记录(由身份提供方同步进来的用户、组、成员关系),而分配它的组织管理员自己都读不到这些。
已处理的部分: 平台出货的三个 MCP 代理上限集正是这种形状。按您裁决第 4 条的兜底(判不清就列拒绝清单,不放宽规则),它们已在 PR #24163 里进拒绝清单,不需要您裁。
要您裁的部分: 以后自建的同形状集怎么办。推荐 A:给边界加第四条可机器判定的条件,通配读取必须带上平台给这几张表配的行级范围,否则不能由组织管理员分配。实现进 #24136 的闸门,不改 schema,不改今天的产品行为(两张分配表到 #24136 落地前仍只读)。
您要做的(一个动作): 回一个字母(A / B / C / D)。
Governing text
- Ruling
6228728551on security: the 18 migration text says organization admins assign positions and permission sets to their members; the shipped organization_admin sets are read-only on both assignment objects and the server refuses #23960 (letter B, 「同意」), item 1: an organisation administrator assigns a set "when every distributed set … has no*wildcard superuser bits, noadminScope, and onlyscope: 'org'capabilities"; item 4: "if a shipped set cannot be classified by the three declared conditions … the ADR card names an explicit denylist for that set instead of widening the rule — no new box visit." The boundary's stated intent, director delta6228146260: 「只能分配被组织墙约束的目录项」. - ADR-0090 D10 rule 1, restated at
packages/spec/src/ai/mcp.zod.ts(about:158–:160): the agent ceilings are "pure capability ceilings — NO row-level security". packages/plugins/plugin-security/src/objects/default-permission-sets.ts, the member_default gives every authenticated member read on sys_scim_user / sys_scim_group with no row policy and no tenant column: one organization's IdP-provisioned users (emails, names) are readable from any other #20001 header (about:106–:165): the seven SCIM projection tables carry no tenant column, so "the organization wall (Layer 0) is inert on them", and "a set with no policy for an object leaves that object unfiltered"; "An organization-scoped SCIM directory is therefore a capability to decide and build (a tenant column on the projection, or a resolved connection set), not a predicate to add here."
Premises (each with its re-check command, on origin/main)
- The seven projection tables are Layer-0-inert:
git show origin/main:scripts/platform-object-tenancy-census.json | grep -A3 '"name": "sys_scim_'listssys_scim_user,sys_scim_subject,sys_scim_projection_grant,sys_scim_identity_tombstone,sys_scim_group,sys_scim_group_member,sys_scim_connection_bindingwithtenantField: null,reach: out(measured 2026-10-17T09:40Z). - A
'*'read reaches them and only a held set's row policy narrows it:git grep -n "scimProjectionRowScope" origin/main -- packages/plugins/plugin-security/src/objects/default-permission-sets.ts(spread intoorganization_admin,member_default,viewer_readonly, not into the agent ceilings). - No baseline is a supported deployment:
git show origin/main:packages/plugins/plugin-security/src/app-default-permission-set.ts | sed -n '38,58p'("nullstill means 'no baseline at all' and composes to[]"). - The assignment right does not exist yet:
organization_adminkeeps both assignment tables read-only until plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 lands (rbac-objects.test.ts:63), so nobody can be hit today.
Options
| What it does | What a customer sees | Workload | |
|---|---|---|---|
| A | A fourth, declaration-checkable condition: a distributed set whose '*' entry grants read must carry the platform's row scope on every Layer-0-inert object it reaches (today: the scimProjectionRowScope policies on the seven SCIM tables); otherwise it is outside the boundary. |
An org admin can still assign viewer_readonly and any authored set built the same way; an authored "read everything" set without the carve-outs is refused at assignment with a named reason. |
domain:services · rides #24136's gate (no extra PR) · precedent: the #20001 spread itself; size not measured |
| B | The org-level assignment right holds only when the platform baseline is composed; under fallbackPermissionSet: null an org admin cannot assign any set with a '*' read. |
Behaviour of the same Setup button changes with a deployment setting the org admin cannot see. | domain:services · rides #24136 · no precedent |
| C | Wall the projection tables themselves: give them an organization dimension (a tenant column, or a resolved connection set), so Layer 0 bounds them for every set. | No permission set can expose another organization's SCIM rows, whatever it carries. | domain:services + domain:engine · a capability build with a schema change on better-auth-managed tables · no precedent; feasibility not measured |
| D | Accept and document: the ADR states the boundary holds under the platform baseline; nothing enforces it. | A no-baseline deployment can leak another organization's identity records through an org admin's assignment. | none |
Business meaning: A = "only hand out sets whose reach is fenced, and check the fence when you hand it out"; B = "the hand-out right depends on a hidden server setting"; C = "fence the room itself, not each key"; D = "post a warning on the door".
四维分析(从业务立场)
- 实际业务需求: 今天零拉动:分配权在 plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 之前不存在,也没有实测到任何部署用
fallbackPermissionSet: null。但 plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 一落地,组织管理员就会分配权限集;自建「全读」集是常见做法(报表、只读审计员),所以拉动会随功能到来。 - 项目长远合理性: 终态应是数据层隔离:属于某组织的行由组织墙兜住,权限集不承担租户隔离(主流多租户平台,如 Salesforce 的 org、Workday 的 tenant,都在数据层隔离,权限只在租户内授予)。C 是这个终态,但它是一项能力建设,可行性(better-auth 托管表能否加组织维度)未实测。在 C 之前,A 是把「被组织墙约束」这句裁决原意精确化:可读面要么被 Layer 0 约束,要么被行级范围约束。它不是给某张表开特例,而是「墙约束」的可判定定义;C 落地后这条条件会自动变得多余。
- 防 AI 写代码犯错: A 在分配时响亮拒绝,AI 写出一个「全读」集并试图让组织管理员分配,会得到具名的拒收。B 的行为随部署配置静默变化,AI 看不到原因。D 是静默泄露,最差。
- 创业阶段不扩散需求: A 不新增键、不新增门禁,只是 plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 闸门里多判一条;C 是新能力,按创业阶段应在有拉动时再建。
os-decision-facets
- ① 项目长远合理性:A 把「被组织墙约束」写成可判定的定义,不新增特例;C 是更彻底的终态但需另行建设;B 让权限随隐藏配置分叉,扩大特例。
- ② 实际业务拉动:今天零命中(分配权未上线、无部署实测关闭基线);plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 落地即有拉动。
- ③ 防 AI 犯错:A 分配时响亮拒绝;B 随配置静默变化;D 静默泄露。
- ④ 创业阶段不扩散:A 零新键零新门禁;C 新能力,无拉动不建。
Prior rulings read:fallbackPermissionSet/scimProjectionRowScope/organization administrator assign→ 15 hits (member_default gives every authenticated member read on sys_scim_user / sys_scim_group with no row policy and no tenant column: one organization's IdP-provisioned users (emails, names) are readable from any other #20001, security(plugin-security): a non-system caller who resolves no permission set is admitted to every object and read with no row scope; an empty set list grants by absence instead of answering the deny baseline #21079, security(plugin-security): an organization-scoped grant row can be re-scoped by a non-system update so that it applies outside its organization — detail held by the filing seat #22278 …, all closed; none rules this term); ADR-0090 D10, D12; thread: security: the 18 migration text says organization admins assign positions and permission sets to their members; the shipped organization_admin sets are read-only on both assignment objects and the server refuses #239606228728551,6228146260
Recommendation
A. Fallback: C as the end state, filed as its own capability card when a deployment needs an organization-scoped SCIM directory. Confidence gap: whether any customer deployment runs with fallbackPermissionSet: null is not measured; C's feasibility on better-auth-managed tables is not measured.
只看①选 A;②③④ 是否翻转:否。
After the ruling
- A: the seat posts the term on plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136 (its gate adds the fourth check, with a pin: an authored
'*'-read set without the SCIM row scope is refused for an org-level assignment;viewer_readonlyis admitted), and amends ADR-0090 D12's 2026-10-17 note by a dated line (Tier H, rides plugin-security: organisation admins assign positions and permission sets to their own members inside the D12 boundary — gate branch, overrides, explain and my-delegable-scope, three-posture acceptance (ruling B on #23960) #24136's ADR follow-up or its own PR). - B / D: the same two places, with the corresponding term or the documented residual risk. C: a capability card on
domain:services, and A or D as the interim.
Related
#23960 (the ruling) · #24135 / PR #24163 (the ADR amendment; the three agent ceilings go into the ruling's item-4 denylist there) · #24136 (Blocked-by: this card for the gate's fourth condition) · #20001 (the SCIM row scope)
Dedupe
MCP search_issues on objectstack-ai/objectstack, closed included: SCIM projection tables cross organization read wildcard permission set no row scope fallbackPermissionSet null → 15 hits; the first ten read (#20001, #24089, #22278, #22250, #21669, #21079, #20555, #21063, #20136, #16870), all closed, none on this term.
Generated by Claude Code
Activity