From 9f450dcf066fe99163544cdba1787523974c28de Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 27 Apr 2026 10:07:27 +0100 Subject: [PATCH] fix: reject malformed clawhub plugin specs --- CHANGELOG.md | 1 + src/infra/clawhub-spec.ts | 14 +++++++++++--- src/infra/clawhub.test.ts | 9 +++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 402aff74222..808c6e772ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Docs: https://docs.openclaw.ai - Agents/Claude CLI: force live-session launches to include `--output-format stream-json` whenever OpenClaw adds `--input-format stream-json`, so new Claude CLI sessions no longer fail immediately while reusable sessions keep working. Fixes #72206. Thanks @kwangwonkoh and @Xivi08. - CLI/plugins: accept ClawHub plugin API wildcard ranges such as `*` without rejecting compatible plugin installs, while still requiring a valid runtime API version. Fixes #56446; supersedes #56466. Thanks @darconada and @claygeo. - CLI/plugins: let config-gated bundled plugins install without persisting invalid placeholder config entries, so install/uninstall sweeps can cover plugins such as memory-lancedb before the user configures credentials. Thanks @vincentkoc. +- CLI/plugins: reject malformed ClawHub plugin specs with trailing `@` before registry lookup, so empty-version typos report as invalid specs instead of package-not-found errors. Fixes #56579; supersedes #56582. Thanks @Kansodata. - Agents/sessions: acquire the session write lock only after cold bootstrap, plugin, and tool setup so fallback runs are not blocked by stalled pre-model startup work. Thanks @codex. - Browser/plugins: auto-start the bundled browser plugin when root `browser` config is present, including restrictive plugin allowlists, and ignore stale persisted plugin registries whose package paths no longer exist. Thanks @codex. - Browser: circuit-break repeated managed Chrome launch failures per profile so browser requests stop spawning Chromium indefinitely when CDP cannot start. Fixes #64271. Thanks @TheophilusChinomona. diff --git a/src/infra/clawhub-spec.ts b/src/infra/clawhub-spec.ts index 6e7ac3defbb..0f5f0421491 100644 --- a/src/infra/clawhub-spec.ts +++ b/src/infra/clawhub-spec.ts @@ -14,11 +14,19 @@ export function parseClawHubPluginSpec(raw: string): { return null; } const atIndex = spec.lastIndexOf("@"); - if (atIndex <= 0 || atIndex >= spec.length - 1) { + if (atIndex <= 0) { return { name: spec }; } + if (atIndex >= spec.length - 1) { + return null; + } + const name = spec.slice(0, atIndex).trim(); + const version = spec.slice(atIndex + 1).trim(); + if (!name || !version) { + return null; + } return { - name: spec.slice(0, atIndex).trim(), - version: spec.slice(atIndex + 1).trim() || undefined, + name, + version, }; } diff --git a/src/infra/clawhub.test.ts b/src/infra/clawhub.test.ts index a8ff4ef33cb..b464a031b63 100644 --- a/src/infra/clawhub.test.ts +++ b/src/infra/clawhub.test.ts @@ -42,6 +42,15 @@ describe("clawhub helpers", () => { name: "demo", version: "1.2.3", }); + expect(parseClawHubPluginSpec("clawhub:@scope/pkg")).toEqual({ + name: "@scope/pkg", + }); + expect(parseClawHubPluginSpec("clawhub:@scope/pkg@1.2.3")).toEqual({ + name: "@scope/pkg", + version: "1.2.3", + }); + expect(parseClawHubPluginSpec("clawhub:demo@")).toBeNull(); + expect(parseClawHubPluginSpec("clawhub:@scope/pkg@")).toBeNull(); expect(parseClawHubPluginSpec("@scope/pkg")).toBeNull(); });