GHSA-vqvg-86cc-cg83: OpenClaw: Mutating internal `/allowlist` chat commands missed `operator.admin` scope enforcement
Fixed in OpenClaw 2026.3.24, the current shipping release.**Title**  
Mutating internal `/allowlist` chat commands missed `operator.admin` scope enforcement**CWE**  
CWE-862 Missing Authorization**CVSS v3.1**  
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N  
Base score: **6.5 (Medium)****Severity Assessment**  
Medium. This is a real authorization flaw in OpenClaw’s internal control plane. The issue does not require host access, trusted local state tampering, or multi-tenant assumptions, but exploitation does require an already authenticated internal Gateway caller with `operator.write`.**Impact**  
An authenticated internal Gateway caller limited to `operator.write` can perform state-changing `/allowlist` actions without `operator.admin`, even though comparable mutating internal chat commands already require `operator.admin`. The reachable effects are persistent changes to config-backed `allowFrom` entries and pairing-store-backed allowlist entries.This is not a semantic-modeling complaint and not a generic “trusted operator can do things” claim. It is a missing authorization check inside OpenClaw’s own internal scope model, where peer mutating command surfaces already distinguish `operator.write` from `operator.admin`.**Affected Component**  
Verified against the latest published GitHub release tag `v2026.3.23` (`ccfeecb6887cd97937e33a71877ad512741e82b2`), published `2026-03-23T23:15:50Z`.Exact vulnerable path on the shipped tag:`src/auto-reply/reply/commands-allowlist.ts:251-254``/allowlist` authorization uses only `rejectUnauthorizedCommand(...)`.`src/auto-reply/reply/commands-allowlist.ts:386-524`mutating config and pairing-store writes happen here, but there is no `requireGatewayClientScopeForInternalChannel(..., operator.admin, ...)`.Reachability and scope model:`src/gateway/method-scopes.ts:94-109``chat.send` is a write-scoped method.`src/gateway/server.chat.gateway-server-chat.test.ts:539-559`existing runtime coverage proves `chat.send` routes slash commands without an agent run.`src/auto-reply/command-auth.ts:574-577`internal callers become `senderIsOwner` only when `GatewayClientScopes` includes `operator.admin`.Comparable internal mutating command paths already enforce `operator.admin`:`src/auto-reply/reply/commands-config.ts:64-73``src/auto-reply/reply/commands-mcp.ts:89-96``src/auto-reply/reply/commands-plugins.ts:387-394``src/auto-reply/reply/commands-acp.ts:98-106`Version history:Introduced by commit `555b2578a8cc6e1b93f717496935ead97bfbed8b` (`feat: add /allowlist command`)Earliest released affected tag found: `v2026.1.20`Latest released affected tag verified: `v2026.3.23`**Technical Reproduction**Check out the shipped release tag `v2026.3.23`.Use an internal command context with:`Provider = "webchat"``Surface = "webchat"``GatewayClientScopes = ["operator.write"]``params.command.channel = "webchat"`Route a slash command through `chat.send`.Execute either of these mutating commands:`/allowlist add dm channel=telegram 789``/allowlist add dm --store channel=telegram 789`Confirm the command context is authorized but not owner-equivalent:`isAuthorizedSender === true``senderIsOwner === false`Observe that the commands still succeed and perform persistent writes.**Demonstrated Impact**  
The vulnerable handler performs real state mutation for a low-scope internal caller:Config-backed mutation path:`src/auto-reply/reply/commands-allowlist.ts:398-503`reads the config snapshot, applies the edit, validates, and writes the updated config to disk.Store-backed mutation path:`src/auto-reply/reply/commands-allowlist.ts:479-485``src/auto-reply/reply/commands-allowlist.ts:513-518`updates the pairing-store allowlist without any admin-scope gate.The result is successful persistence, not just a misleading success message.**Environment**Product: OpenClawVerified shipped tag: `v2026.3.23`Shipped tag commit: `ccfeecb6887cd97937e33a71877ad512741e82b2`Published GitHub release time: `2026-03-23T23:15:50Z`Verification date: `2026-03-24`**Duplicate Check**  
This is not a duplicate of:`GHSA-pjvx-rx66-r3fg`that advisory covered cross-account scoping in `/allowlist ... --store`, not missing internal `operator.admin` enforcement.`GHSA-hfpr-jhpq-x4rm`that advisory covered `/config` writes through `chat.send`, not `/allowlist`.`GHSA-3w6x-gv34-mqpf`same authorization class, but different command path (`/acp`, not `/allowlist`).**In Scope Check**  
This report is in scope under `SECURITY.md` because:it does **not** rely on adversarial operators sharing one gateway host or config;it does **not** target the HTTP compatibility endpoints that `SECURITY.md` explicitly treats as full operator-access surfaces;it demonstrates a real authorization mismatch inside OpenClaw’s own internal control-plane scope model (`operator.write` vs `operator.admin`);peer mutating internal chat commands already enforce `operator.admin`, so this is not a request for a new boundary but a missing check on an existing one.This is therefore a concrete authorization bug, not a trusted-operator hardening suggestion.**Remediation Advice**Add `requireGatewayClientScopeForInternalChannel(..., allowedScopes: ["operator.admin"], ...)` to the mutating internal `/allowlist` paths.Add regression coverage for both mutation modes:internal `operator.write` must be rejected;internal `operator.admin` must be allowed.Cover both config-backed and store-backed writes.Audit other mutating internal chat-command paths for the same missing-scope pattern.
CVSS v3.1: 6.5