In the fast-paced world of blockchain and meme token creation, staying on top of security threats is crucial. Yesterday, on September 8, 2025, the JavaScript community was rocked by one of the largest supply chain attacks on NPM, the Node Package Manager. Attackers compromised a contributor's account through phishing and pushed malicious versions of 18 widely used packages, injecting cryptostealer malware designed to hijack wallet transactions. This isn't just a general web dev issue—it's a direct hit on crypto enthusiasts, as the malware targets cryptocurrencies like Bitcoin, Ethereum, and Solana by rerouting funds to attacker-controlled addresses.
Understanding the Attack
The breach affected staples of the JS ecosystem, packages that power everything from colorful console logs to ANSI string handling. According to security reports from Aikido Security and Semgrep, the compromised versions included obfuscated JavaScript code that hooks into browser functions like fetch and XMLHttpRequest. It scans for wallet interactions, replaces legitimate addresses with lookalikes, and alters transaction parameters right before signing—all while keeping the user interface looking normal.
Here's a list of the affected packages and their compromised versions:
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
- [email protected]
These packages rack up billions of downloads weekly, meaning they're likely lurking in the dependency trees of countless projects. For blockchain practitioners, this is especially alarming. Meme token launches often involve quick-built frontends, DEX interfaces, or bots using tools like React or Node.js, which pull in these utilities. If your dApp or token sniping script depends on one of these, you could unknowingly expose users—or yourself—to fund drains.
The good news? The community reacted swiftly. The malicious versions were yanked from NPM before many downloads occurred, limiting the damage. But if you've installed packages recently, it's time to check.
Edgar Pavlovsky's Timely Script
Enter Edgar Pavlovsky, a convexity expert and contributor to projects like Dark Research AI and Paladin Solana. In a tweet thread that quickly gained traction, he shared a bash script to scan your package.json dependency tree for these compromised packages. It's a straightforward tool that not only checks for known bad versions but also hunts for obfuscated malware patterns in your node_modules.
Edgar updated the script shortly after, enhancing it to detect those sneaky patterns. You can grab it from his GitHub Gist. Here's the full script for easy reference:
bash
#!/usr/bin/env bash
check-deps-with-comp.sh
set -euo pipefail
[[ "${DEBUG:-0}" == "1" ]] && set -x
TOOL="${TOOL:-npm}"
Watchlist lines can be: "name" or "name<tab/space>compromised_version"
WATCHLIST="$(cat <<'EOF'
backslash 0.2.1
chalk-template 1.1.1
supports-hyperlinks 4.1.1
has-ansi 6.0.1
simple-swizzle 0.2.3
color-string 2.1.1
error-ex 1.3.3
color-name 2.0.1
is-arrayish 0.3.3
slice-ansi 7.1.1
color-convert 3.1.1
wrap-ansi 9.0.1
ansi-regex 6.2.1
supports-color 10.2.1
strip-ansi 7.1.1
chalk 5.6.1
debug 4.4.2
ansi-styles 6.2.2
EOF
)"
command -v jq >/dev/null || { echo "[x] jq not found"; exit 1; }
[[ -f package.json ]] || { echo "[x] No package.json here"; exit 1; }
TMPDIR="$(mktemp -d)"
DEPS_JSON="$TMPDIR/deps.json"
MAP_JSON="$TMPDIR/name_map.json"
echo "[] Collecting dependency tree."
if [[ "$TOOL" == "bun" ]]; then
bun pm ls --json > "$DEPS_JSON"
else
npm ls --all --json > "$DEPS_JSON" || true
fi
echo "[] Building name→{versions,roots} map…"
jq '
def walkdeps(root):
(.dependencies // {}) | to_entries[] as $e
| ($e.value | {name:$e.key, version:(.version // ""), root:(root // $e.key)})
, ($e.value | walkdeps(root // $e.key));
reduce (walkdeps(null)) as $n
({};
if ($n.version|type)=="string" and ($n.version|length)>0 then
.[$n.name] |= ( . // {versions:[], roots:[]} ) |
.[$n.name].versions += [$n.version] |
.[$n.name].roots += [$n.root]
else . end
)
| with_entries(
.value.versions |= (unique|sort) |
.value.roots |= (unique|sort)
)
' "$DEPS_JSON" > "$MAP_JSON"
if [[ "$(jq 'length' "$MAP_JSON")" -eq 0 ]]; then
echo "[!] Dependency map is empty. Did you run npm/bun install?"
fi
echo "[*] Checking watchlist (any version)…"
Collect all table data first to calculate column widths
declare -a table_data=()
declare -a col1_data=() col2_data=() col3_data=() col4_data=() col5_data=()
Add header row
col1_data+=("package")
col2_data+=("compromised version")
col3_data+=("present?")
col4_data+=("versions found")
col5_data+=("matches compromised?")
found_any=false
while IFS= read -r line; do
[[ -z "$line" ]] && continue
name = first field, compromised = second field if present
name="$(awk '{print $1}' <<<"$line")"
compromised="$(awk 'NF>1{print $2}' <<<"$line")"
[[ -z "${compromised:-}" ]] && compromised="-"
has=$(jq -r --arg n "$name" 'has($n)' "$MAP_JSON")
if [[ "$has" == "true" ]]; then
versions_csv=$(jq -r --arg n "$name" '.[$n].versions | join(", ")' "$MAP_JSON")
match="-"
if [[ "$compromised" != "-" ]]; then
exact version match?
matched=$(jq -r --arg n "$name" --arg v "$compromised" '
(.[$n].versions // []) | index($v) | if .==null then "no" else "yes" end
' "$MAP_JSON")
match="$matched"
fi
if [[ "$match" == "yes" ]]; then found_any=true; fi
else
versions_csv="-"
match="-"
fi
col1_data+=("$name")
col2_data+=("$compromised")
col3_data+=("$has")
col4_data+=("$versions_csv")
col5_data+=("$match")
done <<<"$WATCHLIST"
Calculate max widths
max_c1=0 max_c2=0 max_c3=0 max_c4=0 max_c5=0
for ((i=0; i<${#col1_data[@]}; i++)); do
(( ${#col1_data[i]} > max_c1 )) && max_c1=${#col1_data[i]}
(( ${#col2_data[i]} > max_c2 )) && max_c2=${#col2_data[i]}
(( ${#col3_data[i]} > max_c3 )) && max_c3=${#col3_data[i]}
(( ${#col4_data[i]} > max_c4 )) && max_c4=${#col4_data[i]}
(( ${#col5_data[i]} > max_c5 )) && max_c5=${#col5_data[i]}
done
Print table
for ((i=0; i<${#col1_data[@]}; i++)); do
printf "%-*s | %-*s | %-*s | %-*s | %-s\n"
$max_c1 "${col1_data[i]}"
$max_c2 "${col2_data[i]}"
$max_c3 "${col3_data[i]}"
$max_c4 "${col4_data[i]}"
$max_c5 "${col5_data[i]}"
done
echo "[] Checking for malware patterns in node_modules..."
Pattern 1: obfuscated hex string
PATTERN1='0x[0-9a-f]{2000,}'
found_p1="$(grep -rEl "$PATTERN1" node_modules 2>/dev/null || true)"
Pattern 2: base64 string with specific length
PATTERN2='(aHR0cDovLzE5Mi4xNjguNTUuMjE2Ojg4ODgvY29tbWFuZC5waHA/Y29tbWFuZD0=)'
found_p2="$(grep -rEl "$PATTERN2" node_modules 2>/dev/null || true)"
if [[ -n "$found_p1" || -n "$found_p2" ]]; then
found_any=true
echo "[!] Malware patterns found:"
[[ -n "$found_p1" ]] && echo "Pattern 1 (long hex):" && echo "$found_p1"
[[ -n "$found_p2" ]] && echo "Pattern 2 (base64 cmd):" && echo "$found_p2"
else
echo "[] No malware patterns found."
fi
rm -rf "$TMPDIR"
if [[ "$found_any" == "true" ]]; then
echo "[!] Found compromised deps or malware patterns. Remove node_modules/, reinstall, or update to safe versions."
exit 1
else
echo "[] No issues found."
fi
To use it, navigate to your project directory, save the script (say, as check-deps.sh), make it executable with chmod +x check-deps.sh
, and run ./check-deps.sh
. It requires jq to be installed and works with npm or bun. If it flags anything, nuke your node_modules and reinstall from a clean lockfile.
Why This Matters for Meme Token Creators
Meme tokens thrive on hype and speed, but that often means cobbling together code from open-source libraries. Tools like Solana's SPL token creator or Ethereum frontends frequently depend on these NPM packages for UI elements or logging. A compromised dependency could turn your fun pump into a rug pull nightmare, draining dev wallets or user funds mid-launch.
This incident underscores the risks in supply chain security—a hot topic in web3, where attacks like the Ledger Connect Kit hack have shown how one weak link can cascade. For blockchain practitioners, adopting practices like using npm ci
for consistent installs, pinning versions in package-lock.json, and scanning with tools like Snyk or this script can make all the difference.
Stay vigilant, folks. In the meme token game, knowledge is your best defense against the bears—and the hackers. If you're building something cool, drop a comment on Edgar's thread or share your security tips with the community.