-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Summary
ruflo v3.5.2 (current on npm) contains an obfuscated one-liner in its preinstall
lifecycle hook. This code runs automatically at npm install time, before any package
files are written, with no disclosure in the README, CHANGELOG, or npm page.
The code
From ruflo/package.json, "scripts"."preinstall" (verify with npm view ruflo scripts):
node -e "var f=require('fs'),p=require('path'),o=require('os'),h=o.homedir(),
d=p.join(h,'.npm','_npx');
...f.rmSync(t,{recursive:true,force:true})...
...if(c.indexOf('claude-flow')!==-1||c.indexOf('ruflo')!==-1)f.unlinkSync(fp)
..." || true
What it does (deobfuscated)
Part 1: Walks ~/.npm/_npx/*/node_modules/ and recursively deletes directories
whose names start with ., contain -, and contain 8+ consecutive letters.
Part 2: Recursively walks ~/.npm/_cacache/index-v5/ (npm's package metadata
cache) and calls fs.unlinkSync() on every file whose content contains the string
"claude-flow" or "ruflo".
This means: if a user has previously npm install-ed claude-flow (the predecessor
package, also by this author), those cache index entries are silently deleted on
install of ruflo.
Why this is a problem
-
Obfuscation. Destructive filesystem operations in install scripts are a known
supply chain attack vector. Minifying them into a single unreadable line, with no
comment, is deceptive regardless of intent. -
Destructive writes outside the package directory.
~/.npm/_cacache/is a
shared user-level resource. npm's own guidelines prohibit install scripts from
modifying files outside their package scope without disclosure. -
Targets a competing package by name.
claude-flowis the predecessor package
by the same author, still available on npm. Deleting its cache entries on install
of a competing package is anti-competitive and violates npm's acceptable use policy. -
No disclosure. None of this is mentioned in the README or on the npm page.
Note: @claude-flow/cli — which ruflo depends on — contains its own preinstall
that is now a no-op with the comment
"// Preinstall hook — no-op (cache repair removed in 3.1.0-alpha.53)".
The destructive version was removed from the dependency but left in the wrapper.
Steps to verify
npm view ruflo scripts --json
# Inspect the preinstall value