VDB
EN
MEDIUM 6.5

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** 1. Check out the shipped release tag `v2026.3.23`. 2. Use an internal command context with: - `Provider = "webchat"` - `Surface = "webchat"` - `GatewayClientScopes = ["operator.write"]` - `params.command.channel = "webchat"` 3. Route a slash command through `chat.send`. 4. Execute either of these mutating commands: - `/allowlist add dm channel=telegram 789` - `/allowlist add dm --store channel=telegram 789` 5. Confirm the command context is authorized but not owner-equivalent: - `isAuthorizedSender === true` - `senderIsOwner === false` 6. 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: OpenClaw - Verified 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** 1. Add `requireGatewayClientScopeForInternalChannel(..., allowedScopes: ["operator.admin"], ...)` to the mutating internal `/allowlist` paths. 2. Add regression coverage for both mutation modes: - internal `operator.write` must be rejected; - internal `operator.admin` must be allowed. 3. Cover both config-backed and store-backed writes. 4. Audit other mutating internal chat-command paths for the same missing-scope pattern.

이 버전이 영향받나요?

사용 중인 패키지 버전을 입력하면 즉시 평가합니다.

영향 패키지

npm / openclaw
최초 영향 버전: 0 수정 버전: 2026.3.24
수정 npm install openclaw@2026.3.24

참고