Skip to content

fix(plugins): require owner for plugin writes#93353

Merged
eleqtrizit merged 1 commit into
openclaw:mainfrom
eleqtrizit:746
Jun 15, 2026
Merged

fix(plugins): require owner for plugin writes#93353
eleqtrizit merged 1 commit into
openclaw:mainfrom
eleqtrizit:746

Conversation

@eleqtrizit

@eleqtrizit eleqtrizit commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Require owner identity or Gateway operator.admin before /plugins install, /plugins enable, or /plugins disable can mutate trusted plugin state.

Changes

  • Add an owner/admin guard to plugin write commands after the existing Gateway scope check.
  • Preserve read-only /plugins list and /plugins inspect behavior for authorized senders.
  • Preserve Gateway clients with operator.admin for plugin install and toggle commands.
  • Add regression coverage for channel-originated non-owner plugin install/toggle attempts stopping before installer, persistence, or config mutation side effects.

Validation

  • corepack pnpm exec oxfmt --write src/auto-reply/reply/commands-plugins.ts src/auto-reply/reply/commands-plugins.install.test.ts src/auto-reply/reply/commands-plugins.test.ts
  • node scripts/run-vitest.mjs run --config test/vitest/vitest.auto-reply-reply.config.ts src/auto-reply/reply/commands-plugins.install.test.ts src/auto-reply/reply/commands-plugins.test.ts --reporter=dot passed: 2 files, 17 tests.
  • git diff --check
  • .agents/skills/autoreview/scripts/autoreview --mode local returned clean: no accepted/actionable findings.

Notes

  • Compatibility impact: authorized channel users who are not owners can no longer install, enable, or disable plugins; owner identity or Gateway operator.admin is required for plugin writes.
  • CHANGELOG.md was not updated.
  • Shipped-state check: npm openclaw latest is 2026.6.6, and local v2026.6.6 still has the prior write-command gate.

@openclaw-barnacle openclaw-barnacle Bot added size: S maintainer Maintainer-authored PR labels Jun 15, 2026
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 15, 2026, 12:47 PM ET / 16:47 UTC.

Summary
The PR adds an owner-or-Gateway-operator.admin guard before /plugins install, /plugins enable, and /plugins disable, plus regression coverage for blocked channel-originated non-owner writes and allowed Gateway admin writes.

PR surface: Source +11, Tests +118. Total +129 across 3 files.

Reproducibility: Do we have a high-confidence way to reproduce the issue? Yes from source path inspection and the contributor's terminal proof: current main lacks an owner guard before plugin write mutation, while PR head blocks a Telegram-shaped authorized non-owner before persistence.

Review metrics: 1 noteworthy metric.

  • Plugin write authorization surfaces: 3 commands tightened. install, enable, and disable mutate trusted plugin state, so maintainers should notice the changed authorization boundary before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Have a maintainer explicitly accept or reject the fail-closed owner/admin policy for existing channel-authorized plugin write users.

Mantis proof suggestion
A live Telegram transcript would add useful maintainer proof for the visible non-owner rejection and owner/admin allow paths. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

telegram live: verify that a non-owner Telegram sender cannot run /plugins install, enable, or disable, while owner and Gateway operator.admin paths still work.

Risk before merge

  • [P1] Existing non-owner channel users with /plugins enabled and allowlist authorization can lose install, enable, and disable ability after this PR unless they are in the owner allowlist or use a Gateway client with operator.admin.

Maintainer options:

  1. Accept the tighter plugin-write gate (recommended)
    A maintainer can land the PR as a deliberate security hardening change after acknowledging that some existing authorized channel users lose plugin write access.
  2. Stage the compatibility change
    Require a compatibility plan, migration note, or explicit strict-mode path before enforcing owner-only plugin writes for existing channel users.
  3. Pause if delegated plugin admin is intended
    Pause or close the PR if non-owner channel delegation for plugin writes is an intentional product capability.

Next step before merge

  • [P2] The remaining action is maintainer acceptance of a protected-label, compatibility-sensitive permission hardening change, not an automated code repair.

Security
Cleared: No concrete security or supply-chain regression was found; the diff tightens a plugin write authorization boundary and does not add dependencies, workflows, package scripts, or secret handling.

Review details

Best possible solution:

Land this only after a maintainer explicitly accepts the fail-closed plugin write policy and confirms the owner/admin boundary is the desired upgrade behavior for existing channel users.

Do we have a high-confidence way to reproduce the issue?

Do we have a high-confidence way to reproduce the issue? Yes from source path inspection and the contributor's terminal proof: current main lacks an owner guard before plugin write mutation, while PR head blocks a Telegram-shaped authorized non-owner before persistence.

Is this the best way to solve the issue?

Is this the best way to solve the issue? Yes for the plugin write boundary: the guard is placed before side effects, keeps read-only plugin commands available, and preserves Gateway operator.admin; the open question is maintainer acceptance of the compatibility tradeoff.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f00de6b06a32.

Label changes

Label justifications:

  • P2: The PR is a bounded security-relevant plugin command hardening change without evidence of an active incident or outage.
  • merge-risk: 🚨 compatibility: Merging blocks existing authorized channel senders who are not owners from plugin install, enable, and disable mutations.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR includes after-fix terminal proof from a disposable command-handling scenario with Telegram metadata, temporary config, and plugin persistence checks showing the blocked and allowed paths.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR includes after-fix terminal proof from a disposable command-handling scenario with Telegram metadata, temporary config, and plugin persistence checks showing the blocked and allowed paths.
  • mantis: telegram-visible-proof: Mantis should capture Telegram visible proof. The PR changes visible Telegram-originated /plugins rejection behavior that can be demonstrated in a short Telegram proof.
Evidence reviewed

PR surface:

Source +11, Tests +118. Total +129 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 11 0 +11
Tests 2 123 5 +118
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 134 5 +129

What I checked:

  • Repository policy read: Read the full root policy and applied its compatibility, security-boundary, proof, and scoped-guide review requirements to this plugin command authorization change. (AGENTS.md:1, f00de6b06a32)
  • Maintainer note read: Read the Telegram maintainer note because the PR affects Telegram-shaped native command authorization proof expectations. (.agents/maintainer-notes/telegram.md:1, f00de6b06a32)
  • Live PR state: Live GitHub shows the PR is open, not draft, mergeable, author eleqtrizit, head e978fc9d1568f160909c2dae6ef8bd145b006a59, and labeled maintainer, proof: sufficient, P2, and merge-risk: 🚨 compatibility. (e978fc9d1568)
  • Current main behavior: Current main gates /plugins writes with requireGatewayClientScope and then proceeds to Nix, install, config, and registry mutation paths without an owner check for non-Gateway channel-originated commands. (src/auto-reply/reply/commands-plugins.ts:435, f00de6b06a32)
  • Shared command gate behavior: rejectNonOwnerCommand returns the native unauthorized reply for non-owner command turns, while requireGatewayClientScope intentionally returns null when no Gateway scopes array is present. (src/auto-reply/reply/command-gates.ts:32, f00de6b06a32)
  • Proposed guard: At PR head, the new hasGatewayAdminScope helper and owner/admin guard run before Nix, install, config, and registry mutation work. (src/auto-reply/reply/commands-plugins.ts:146, e978fc9d1568)

Likely related people:

  • Sash Zats: Current-main blame shows the /plugins write-gate lines and shared command-gate helper trace to commit 233b48d, which created these files in this checkout during a broad refactor. (role: introduced current file path; confidence: medium; commits: 233b48daaab4; files: src/auto-reply/reply/commands-plugins.ts, src/auto-reply/reply/command-gates.ts, docs/tools/slash-commands.md)
  • Vincent Koc: git log --follow shows recent work by Vincent Koc touching the plugin command implementation and install tests immediately before this PR. (role: recent area contributor; confidence: medium; commits: 767e8280ac7c; files: src/auto-reply/reply/commands-plugins.ts, src/auto-reply/reply/commands-plugins.install.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@eleqtrizit

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. labels Jun 15, 2026
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot temporarily deployed to qa-live-shared June 15, 2026 16:25 Inactive
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@eleqtrizit

Copy link
Copy Markdown
Contributor Author

Behavioral proof for the plugin write authorization change.

I ran a disposable terminal scenario against the PR head (e978fc9d1568f160909c2dae6ef8bd145b006a59). This was not just the unit test suite: it invoked handlePluginsCommand with Telegram native-command metadata, a real temporary openclaw.json, and real local plugin install persistence into a temporary state directory. No real user config, credentials, or external network calls were used.

Command run:

corepack pnpm exec tsx <inline disposable proof script>

Redacted output:

CASE: telegram native authorized non-owner is blocked before plugin install persistence
origin=telegram commandSource=native authorized=true owner=false gatewayScopes=null
reply="You are not authorized to use this command."
configChanged=false
installRecordBefore=false installRecordAfter=false

CASE: telegram native owner can still install
origin=telegram commandSource=native authorized=true owner=true gatewayScopes=null
reply="🔌 Installed plugin \"proof-owner-allowed\". Gateway restart will load the new plugin source."
configChanged=true
installRecordBefore=false installRecordAfter=true
installRecord={"source":"path","sourcePath":"/tmp/.../workspace/proof-owner-allowed","installPath":"/tmp/.../state/extensions/proof-owner-allowed","version":"0.0.1","installedAt":"2026-06-15T16:30:16.804Z"}

CASE: gateway operator.admin can still install without owner identity
origin=telegram commandSource=native authorized=true owner=false gatewayScopes=["operator.admin","operator.write"]
reply="🔌 Installed plugin \"proof-gateway-admin-allowed\". Gateway restart will load the new plugin source."
configChanged=true
installRecordBefore=false installRecordAfter=true
installRecord={"source":"path","sourcePath":"/tmp/.../workspace/proof-gateway-admin-allowed","installPath":"/tmp/.../state/extensions/proof-gateway-admin-allowed","version":"0.0.1","installedAt":"2026-06-15T16:30:17.500Z"}

What this proves:

  • A Telegram-shaped authorized non-owner plugin write with absent Gateway scopes now returns the visible native-command rejection and does not change config or persist an install record.
  • A Telegram-shaped owner request still installs and persists a local plugin.
  • A Gateway operator.admin request still installs and persists a local plugin without owner identity.

Focused validation also still passes:

node scripts/run-vitest.mjs run --config test/vitest/vitest.auto-reply-reply.config.ts src/auto-reply/reply/commands-plugins.install.test.ts src/auto-reply/reply/commands-plugins.test.ts --reporter=dot

Test Files  2 passed (2)
Tests       17 passed (17)
Duration    1.23s

git diff --check passed.

@eleqtrizit

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

1 similar comment
@eleqtrizit

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 15, 2026
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@eleqtrizit

Copy link
Copy Markdown
Contributor Author

Summary of All Checks Completed

Relevance

Three independent checks confirmed the vulnerability is in scope (CWE-862/CWE-269 — Missing Authorization / Improper Privilege Management, CVSS 8.8 High), still present on current main and all shipped releases from v2026.5.20 through v2026.6.6, and has a compatible fix path. Plugin installation modifies the trusted computing base per SECURITY.md, so the authorization bypass is a legitimate security boundary violation.

Compatibility

A dedicated compatibility assessment found no supported user contract break. The PR does not change exported APIs, config schemas, CLI flags, Gateway protocol messages, plugin SDK types, storage formats, or docs contracts. The only newly blocked behavior is the vulnerability itself — a channel-authorized non-owner sender mutating trusted plugin state. Owner senders and Gateway operator.admin clients remain unaffected. Read-only /plugins list|inspect stays open to all authorized senders.

ClawSweeper

ClawSweeper reviewed the PR twice. The first review rated patch quality as platinum hermit but blocked on missing real behavior proof. After terminal-based behavioral proof was posted showing a non-owner channel /plugins write is blocked before mutation, and owner/Gateway admin paths still work, ClawSweeper updated its verdict to platinum hermit overall, proof: sufficient, ready for maintainer look. No concrete code defects were found in either review.

Code Reviews Completed

Multiple code reviews examined the implementation: the targeted 11-line production diff, the 17 regression tests, the three-layer authorization gate (Gateway scope → owner/admin → Nix mode), the use of existing rejectNonOwnerCommand helper, and the correct placement of the gate before installer dispatch, persistence, config mutation, and registry refresh. All reviews confirmed the fix is correct, well-scoped, follows established patterns, and has no code-blocking findings.


Checks Completed

Check Result
Vulnerability confirmed on main ✅ Present in current main and shipped releases v2026.5.20v2026.6.6
Unit tests (2 test files, 17 tests) ✅ All passed
Code formatting (oxfmt --write) ✅ Passed
Import boundary checks (3 scripts) ✅ All passed
git diff --check (whitespace) ✅ Passed
Auto review (autoreview --mode local) ✅ Clean — no accepted/actionable findings
Compatibility assessment ✅ Safe — no supported user contract break
Real behavior proof (terminal-based) ✅ Non-owner blocked, owner allowed, Gateway admin allowed
ClawSweeper review ✅ Platinum hermit — no concrete code defects
CI checks (Real behavior proof, Workflow Sanity, Dependency Guard, Labeler) ✅ All completed checks passing

Abbreviations

Abbreviation Definition
CWE Common Weakness Enumeration
CVSS Common Vulnerability Scoring System
CLI Command-Line Interface
API Application Programming Interface
SDK Software Development Kit
GHSA GitHub Security Advisory
CI Continuous Integration

@eleqtrizit eleqtrizit merged commit ddb07fc into openclaw:main Jun 15, 2026
242 of 258 checks passed
@eleqtrizit eleqtrizit deleted the 746 branch June 15, 2026 17:22
@openclaw-mantis

Copy link
Copy Markdown
Contributor

Mantis Telegram Desktop Proof

Summary: Mantis captured native Telegram Desktop before/after GIF evidence for the plugin write authorization change.

Main screenshot This PR screenshot
Baseline native Telegram Desktop screenshot Candidate native Telegram Desktop screenshot
Main This PR
Baseline native Telegram Desktop proof GIF Candidate native Telegram Desktop proof GIF

Motion-trimmed clips:

Raw QA files: https://artifacts.openclaw.ai/mantis/telegram-desktop/pr-93353/run-27560292964-1/index.json

badgerbees pushed a commit to badgerbees/openclaw that referenced this pull request Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant