Search for vulnerabilities
| Vulnerability ID | VCID-qx6n-dk9c-8yd3 |
| Aliases |
GHSA-vqvg-86cc-cg83
|
| Summary | 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. |
| Status | Published |
| Exploitability | 0.5 |
| Weighted Severity | 6.2 |
| Risk | 3.1 |
| Affected and Fixed Packages | Package Details |
| System | Score | Found at |
|---|---|---|
| cvssv3.1_qr | MODERATE | https://github.com/advisories/GHSA-vqvg-86cc-cg83 |
| cvssv3.1 | 6.5 | https://github.com/openclaw/openclaw |
| generic_textual | MODERATE | https://github.com/openclaw/openclaw |
| cvssv3.1 | 6.5 | https://github.com/openclaw/openclaw/security/advisories/GHSA-vqvg-86cc-cg83 |
| cvssv3.1_qr | MODERATE | https://github.com/openclaw/openclaw/security/advisories/GHSA-vqvg-86cc-cg83 |
| generic_textual | MODERATE | https://github.com/openclaw/openclaw/security/advisories/GHSA-vqvg-86cc-cg83 |
| Reference id | Reference type | URL |
|---|---|---|
| https://github.com/openclaw/openclaw | ||
| GHSA-vqvg-86cc-cg83 | https://github.com/advisories/GHSA-vqvg-86cc-cg83 | |
| GHSA-vqvg-86cc-cg83 | https://github.com/openclaw/openclaw/security/advisories/GHSA-vqvg-86cc-cg83 |
| Attack Vector (AV) | Attack Complexity (AC) | Privileges Required (PR) | User Interaction (UI) | Scope (S) | Confidentiality Impact (C) | Integrity Impact (I) | Availability Impact (A) |
|---|---|---|---|---|---|---|---|
network adjacent_network local physical |
low high |
none low high |
none required |
unchanged changed |
high low none |
high low none |
high low none |
| Attack Vector (AV) | Attack Complexity (AC) | Privileges Required (PR) | User Interaction (UI) | Scope (S) | Confidentiality Impact (C) | Integrity Impact (I) | Availability Impact (A) |
|---|---|---|---|---|---|---|---|
network adjacent_network local physical |
low high |
none low high |
none required |
unchanged changed |
high low none |
high low none |
high low none |
No EPSS data available for this vulnerability.
| Date | Actor | Action | Source | VulnerableCode Version |
|---|---|---|---|---|
| 2026-06-12T07:50:27.176779+00:00 | GithubOSV Importer | Import | https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-vqvg-86cc-cg83/GHSA-vqvg-86cc-cg83.json | 38.6.0 |