mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
fix: require owner identity for owner-enforced commands (#69774)
* fix: require owner identity for owner-enforced commands Stop wildcard channel allowlists from authorizing non-owner senders when a plugin requires owner-only commands. Add a regression test for the owner-enforced wildcard allowFrom path. * docs(changelog): note owner identity requirement for owner-enforced commands (#69774)
This commit is contained in:
@@ -9,6 +9,10 @@ Docs: https://docs.openclaw.ai
|
||||
- Onboard/wizard: simplify the security disclaimer copy (drop the yellow banner and warning icon in favor of plain-prose paragraphs), and flip remaining onboarding pickers with long dynamic option lists to searchable autocompletes (search provider, plugin configure, model provider filter).
|
||||
- Ollama/onboard: populate the cloud-only model list from `ollama.com/api/tags` so `openclaw onboard` reflects the live cloud catalog instead of a static three-model seed; cap the discovered list at 500 and fall back to the previous hardcoded suggestions when ollama.com is unreachable or returns no models. (#68463) Thanks @BruceMacD.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Auth/commands: require owner identity (an owner-candidate match or internal `operator.admin`) for owner-enforced commands instead of treating wildcard channel `allowFrom` or empty owner-candidate lists as sufficient, so non-owner senders can no longer reach owner-only commands through a permissive fallback when `enforceOwnerForCommands=true` and `commands.ownerAllowFrom` is unset. (#69774) Thanks @drobison00.
|
||||
|
||||
## 2026.4.20
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -706,9 +706,7 @@ export function resolveCommandAuthorization(params: {
|
||||
? true
|
||||
: ownerAllowlistConfigured
|
||||
? senderIsOwner
|
||||
: ownerState.allowAll ||
|
||||
ownerState.ownerCandidatesForCommands.length === 0 ||
|
||||
Boolean(matchedCommandOwner);
|
||||
: senderIsOwnerByScope || Boolean(matchedCommandOwner);
|
||||
const isAuthorizedSender = resolveCommandSenderAuthorization({
|
||||
commandAuthorized,
|
||||
isOwnerForCommands,
|
||||
|
||||
@@ -159,6 +159,48 @@ describe("resolveCommandAuthorization", () => {
|
||||
expect(otherAuth.isAuthorizedSender).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects wildcard channel senders when the plugin enforces owner-only commands", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "discord",
|
||||
plugin: {
|
||||
...createOutboundTestPlugin({
|
||||
id: "discord",
|
||||
outbound: { deliveryMode: "direct" },
|
||||
}),
|
||||
commands: { enforceOwnerForCommands: true },
|
||||
config: {
|
||||
listAccountIds: () => ["default"],
|
||||
resolveAccount: () => ({}),
|
||||
resolveAllowFrom: () => ["*"],
|
||||
formatAllowFrom,
|
||||
},
|
||||
},
|
||||
source: "test",
|
||||
},
|
||||
]),
|
||||
);
|
||||
const cfg = {
|
||||
channels: { discord: { allowFrom: ["*"] } },
|
||||
} as OpenClawConfig;
|
||||
|
||||
const auth = resolveCommandAuthorization({
|
||||
ctx: {
|
||||
Provider: "discord",
|
||||
Surface: "discord",
|
||||
ChatType: "direct",
|
||||
From: "discord:123",
|
||||
SenderId: "123",
|
||||
} as MsgContext,
|
||||
cfg,
|
||||
commandAuthorized: true,
|
||||
});
|
||||
|
||||
expect(auth.senderIsOwner).toBe(false);
|
||||
expect(auth.isAuthorizedSender).toBe(false);
|
||||
});
|
||||
|
||||
it("uses explicit owner allowlist when allowFrom is empty", () => {
|
||||
const cfg = {
|
||||
commands: { ownerAllowFrom: ["whatsapp:+15551234567"] },
|
||||
|
||||
Reference in New Issue
Block a user