diff --git a/docs/superpowers/plans/2026-06-06-enterprise-org-vault.md b/docs/superpowers/plans/2026-06-06-enterprise-org-vault.md index 549c097..d3b0b2e 100644 --- a/docs/superpowers/plans/2026-06-06-enterprise-org-vault.md +++ b/docs/superpowers/plans/2026-06-06-enterprise-org-vault.md @@ -4583,12 +4583,14 @@ fn enforce_owner_only_elevation( if !is_privileged(m.role) { continue; } - // Privileged now. Was it already privileged in the parent (no change)? - let already = parent_role(m.member_id.as_str()) - .map(is_privileged) - .unwrap_or(false); - if already { - continue; // not an introduction or elevation + // Privileged now. Skip ONLY if the role is unchanged from the parent + // (a no-op same-role entry). Any CHANGE into a privileged role — a new + // privileged member, Member→Admin/Owner, or Admin→Owner — must be + // owner-signed. (A naive "already privileged" skip is WRONG: Admin is + // also privileged, so it would let an Admin be elevated to Owner + // unchecked — the exact escalation this gate exists to stop.) + if parent_role(m.member_id.as_str()) == Some(m.role) { + continue; // unchanged role — not an introduction or elevation } // A new owner/admin, or a member elevated to owner/admin → owner-only. if !signer.role.can_manage_owners() {