-
-
Notifications
You must be signed in to change notification settings - Fork 52.6k
Description
Description
After upgrading to v2026.2.26 via bun install -g openclaw@latest, all CLI commands fail with config validation errors for every bundled extension plugin:
Invalid config at ~/.openclaw/openclaw.json:
- plugins: plugin: unsafe plugin manifest path: ~/.bun/install/global/node_modules/openclaw/extensions/telegram/openclaw.plugin.json (validation)
- plugins: plugin: unsafe plugin manifest path: ~/.bun/install/global/node_modules/openclaw/extensions/googlechat/openclaw.plugin.json (validation)
... (37 bundled extensions, all rejected)
The gateway process itself starts but plugins fail to load, so channels (Telegram, Google Chat, etc.) don't work. Downgrading to v2026.2.23 resolves the issue.
Root Cause
This is a different variant from #28122 and #28175 (which are about pnpm's symlink layout).
Bun's package manager uses hardlinks from its content-addressable cache to the install directory. Every file in ~/.bun/install/global/node_modules/openclaw/ has nlink: 2 (one link in the bun cache, one in the install dir):
$ stat ~/.bun/install/global/node_modules/openclaw/extensions/telegram/openclaw.plugin.json
Links: 2 # hardlinked from bun cachev2026.2.26's openVerifiedFileSync (in openclaw-root-*.js) rejects files with nlink > 1:
// Line ~485 of openclaw-root-*.js
if (params.rejectHardlinks && preOpenStat.nlink > 1) return {
ok: false,
reason: "validation"
};This is called from openBoundaryFileSync with rejectHardlinks: params.rejectHardlinks ?? true (defaults to true).
Since bun hardlinks ALL files (~10,000+ files in the package), every plugin manifest AND entry file is rejected.
No symlinks are involved — readlink -f confirms all paths are direct:
$ readlink -f ~/.bun/install/global/node_modules/openclaw
/home/ubuntu/.bun/install/global/node_modules/openclaw # not a symlinkWorkaround
Break the hardlinks after every bun install -g openclaw:
PKG_DIR="$HOME/.bun/install/global/node_modules/openclaw"
find "$PKG_DIR" -type f -links +1 -exec sh -c \
'for f; do cp "$f" "$f.tmp" && mv "$f.tmp" "$f"; done' _ {} +This copies each file in-place, creating a new inode with nlink: 1.
Suggested Fix
For bundled plugins (shipped inside the openclaw package itself), the hardlink check should be relaxed. Options:
- Set
rejectHardlinks: falsewhen loading bundled plugin manifests (origin === "bundled") - Only enforce
rejectHardlinksfor user-installed/workspace plugins where TOCTOU via hardlinks is an actual attack vector - Skip the
nlinkcheck entirely for files inside the openclaw package directory
The security intent of rejectHardlinks (preventing TOCTOU attacks via hardlinked files) doesn't apply to bundled plugins — these are package manager artifacts, not attacker-controlled.
Environment
- OpenClaw version: 2026.2.26 (works on 2026.2.23)
- Package manager: bun 1.3.8
- OS: Ubuntu 24.04 LTS (amd64), GCP e2-small
- Install method:
bun install -g openclaw@latest - Node.js: v22.x
Related Issues
- v2026.2.26: bundled plugin manifests rejected as 'unsafe plugin manifest path' with pnpm global install #28122 — same symptom with pnpm (symlink layout variant)
- [Bug]: pnpm global install fails with "unsafe plugin manifest path" error #28175 — same symptom with pnpm (symlink layout variant)
This issue and the pnpm issues share the same underlying problem: v2026.2.26's path security hardening doesn't account for how package managers (bun → hardlinks, pnpm → symlinks) store files.