security: require pinned spec + integrity for official npm plugin trust#76455
security: require pinned spec + integrity for official npm plugin trust#76455fede-kamel wants to merge 3 commits into
Conversation
…n trust The isTrustedOfficialNpmPluginInstall helper bypassed the install security scan whenever the requested npm spec name matched the @openclaw/codex allowlist entry, regardless of version selector or expectedIntegrity. This contradicted the policy enforced by provider-install-catalog.ts (da44d2d), which requires selectorKind === "exact-version" plus a non-empty expectedIntegrity for trusted installs. Tighten the helper to mirror that policy and plumb expectedIntegrity through PackageInstallCommonParams, validatePackagePluginInstallSource, and the installPluginFromNpmSpec -> installPluginFromInstalledPackageDir path so the helper sees the integrity value at the call site. Adds five integration tests covering unpinned spec, dist-tag spec, pinned-without-integrity (all blocked), pinned-with-integrity (allowed with trusted-source warning), and impostor packageName (blocked even with pinning + integrity).
|
Codex review: needs maintainer review before merge. Summary Reproducibility: yes. Source inspection on current main shows the helper trusts by request/package/plugin name only, and current npm-spec tests exercise bare official specs with dangerous launch calls that expect the scanner bypass. Next step before merge Security Review detailsBest possible solution: Land the narrowed trust gate with regression coverage after maintainer/security approval and CI, keeping catalog-backed official install paths responsible for supplying pinned integrity metadata. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection on current main shows the helper trusts by request/package/plugin name only, and current npm-spec tests exercise bare official specs with dangerous launch calls that expect the scanner bypass. Is this the best way to solve the issue? Yes. The latest PR places the exact-version plus integrity requirement at the bypass helper, plumbs the existing integrity value through the npm install path, and updates stale tests and changelog without broadening the security surface. What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against b83b2e3f1cb5. |
- Update install.npm-spec.test.ts: the existing it.each table installed bare @openclaw/* specs (with spawn payloads) and asserted ok: true via the trusted-source bypass. With the new pinning + integrity gate those fixtures must use exact-version specs and pass expectedIntegrity to keep proving the legitimate trust path. Add a companion negative it.each that asserts the scanner now blocks the bare/dist-tag/ no-integrity variants. - Replace the misleading provider-install-catalog.ts citation in the install.ts code comment; that policy is not on current main. - Add an Unreleased Fixes changelog entry under Plugins/install. Verification: - pnpm test src/plugins/install.npm-spec.test.ts src/plugins/install.test.ts -> 113/113 pass - pnpm exec oxfmt --check --threads=1 src/plugins/install.ts src/plugins/install.test.ts src/plugins/install.npm-spec.test.ts CHANGELOG.md -> clean - node scripts/run-oxlint.mjs src/plugins/install.ts src/plugins/install.test.ts src/plugins/install.npm-spec.test.ts -> 0 warnings 0 errors - pnpm tsgo:core -> clean
|
/clawsweeper re-review |
@fede-kamel this is for maintainers only. As for your changes given our release process its not straight forward to mint SHA's and link to the releases as we are shipping a ton of stuff at once, I will keep on radar of the security and CI side to have this included. I will try to add some additional enforcements within this PR and should not be merged as-is. This behaviour will also break use-cases where users are upgrading plugins independently of version or switching to beta etc. |
|
Thanks @fede-kamel. I landed the reworked version in #76501 as 2a22eb6. I kept the credit in the changelog and changed the hardening shape from npm pin/integrity-gated trust to explicit OpenClaw-owned install provenance: direct npm package names now scan normally, while catalog/onboarding/doctor paths pass the trusted-source bit deliberately. Closing this PR as superseded by #76501. |
Summary
Closes a trust-bypass gap in
isTrustedOfficialNpmPluginInstall(src/plugins/install.ts). The helper that bypasses the install security scan for official@openclaw/*packages previously matched the allowlist by name only, so:openclaw plugin install @openclaw/codex(no version) — npm resolves tolatest, scan bypassedopenclaw plugin install @openclaw/codex@latest(dist-tag) — scan bypassedopenclaw plugin install @openclaw/codex@1.2.3without an integrity hash — scan bypassedThis contradicted the policy already enforced for trusted catalog installs in
src/plugins/provider-install-catalog.ts:67-74(commitda44d2d572— "fix(security): require pinned npm specs for trusted installs"), which requiresselectorKind === "exact-version"AND a non-emptyexpectedIntegrity. If the npm@openclawscope were ever compromised, the unpinned path would have installed a malicious package without scan-level protection.The current allowlist on
maincovers four packages (@openclaw/acpx,@openclaw/codex,@openclaw/google-meet,@openclaw/voice-call); the helper iterates the map, so the fix protects all of them.Changes
isTrustedOfficialNpmPluginInstallnow requiresselectorKind === "exact-version"AND a non-emptyexpectedIntegrity, mirroring the policy inprovider-install-catalog.ts.expectedIntegrityplumbed throughPackageInstallCommonParams,pickPackageInstallCommonParams,validatePackagePluginInstallSource, and theinstallPluginFromNpmSpec → installPluginFromInstalledPackageDircall site so the helper can see the value.Test plan
pnpm test src/plugins/install.test.ts— 95/95 pass, including 5 new integration tests in a newdescribe("trusted official npm plugin install (isTrustedOfficialNpmPluginInstall)")block:SECURITY_SCAN_BLOCKED)@openclaw/codex@latest) → blockedexpectedIntegrity→ blockedexpectedIntegrity→ allowed, "allowed because it is an official OpenClaw package" warning emittedpackageName(e.g.@evil/typosquatmasquerading) → blocked even with pinning + integritypnpm test src/plugins/update.test.ts src/plugins/clawhub.test.ts— 97/97 passpnpm tsgo:corecleanpnpm exec oxfmt --check src/plugins/install.ts src/plugins/install.test.tscleannode scripts/run-oxlint.mjs src/plugins/install.ts src/plugins/install.test.ts— 0 warnings, 0 errorsspawn("google-chrome", [])payload without scan under the prior codeRelated
da44d2d572("fix(security): require pinned npm specs for trusted installs"), which patched the same trust pattern inprovider-install-catalog.tsbut did not reach this newer parallel helper.