在快速发展的区块链和 meme token 创建领域,保持对安全威胁的警惕至关重要。昨天,即 2025 年 9 月 8 日,JavaScript 社区遭遇了 NPM(Node Package Manager)史上最大规模的供应链攻击之一。攻击者通过钓鱼入侵了某个贡献者账号,并推送了 18 个广泛使用包的恶意版本,注入了旨在劫持钱包交易的加密窃取恶意软件。这不仅是一般的 Web 开发问题——对加密圈来说更是直接威胁,因为此类恶意软件会针对 Bitcoin、Ethereum 和 Solana 等加密货币,将资金重定向到攻击者控制的地址。
了解此次攻击
此次泄露影响了 JS 生态中的基础包,这些包支撑着从彩色控制台日志到 ANSI 字符串处理的各种功能。根据 Aikido Security 和 Semgrep 的安全报告,被篡改的版本包含了混淆的 JavaScript 代码,这些代码会挂钩到浏览器函数(如 fetch 和 XMLHttpRequest),扫描钱包交互,在签名前将合法地址替换为仿冒地址,并修改交易参数——这一切都在用户界面看起来正常的情况下进行。
以下是受影响的包及其被篡改的版本:
- [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]
这些包每周合计拥有数十亿次下载,意味着它们很可能出现在无数项目的依赖树中。对于区块链从业者来说,这尤其令人震惊。meme token 的发布通常追求速度,经常会匆忙组装前端、DEX 界面或使用 React 或 Node.js 的机器人,这些都会引入上述工具。如果您的 dApp 或抢币脚本依赖其中任意一个被篡改的包,您可能在不知情的情况下暴露出用户或自己的资金风险。
好消息是社区反应迅速。恶意版本在被大量下载前就已从 NPM 上撤下,限制了损害范围。但如果您最近安装过包,现在是检查的时候了。
Edgar Pavlovsky 的及时脚本
凸性(convexity)专家、Dark Research AI 和 Paladin Solana 等项目的贡献者 Edgar Pavlovsky 在一个很快走红的 推文线程 中分享了一个 bash 脚本,用来扫描您 package.json 的依赖树,查找这些被篡改的包。这个工具直接明了,不仅会检查已知的恶意版本,还会在 node_modules 中搜索混淆恶意软件的模式。
Edgar 随后更新了脚本,增强了对这些隐蔽模式的检测。您可以从他的 GitHub Gist 获取。下面是完整脚本,便于参考:
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
要使用它,请进入您的项目目录,将脚本保存为文件(例如 save 为 check-deps.sh),用 chmod +x check-deps.sh
赋予可执行权限,然后运行 ./check-deps.sh
。该脚本需要已安装 jq,并兼容 npm 或 bun。如果脚本发现任何问题,建议删除 node_modules 并从干净的 lockfile 重新安装依赖。
这对 Meme Token 创作者为何重要
Meme token 依赖炒作与速度,但这通常意味着从开源库快速拼装代码。像 Solana 的 SPL token 创建器或 Ethereum 前端之类的工具,经常依赖这些 NPM 包来实现 UI 元素或日志记录。被篡改的依赖可能把你们的有趣空投/拉盘变成 rug pull 噩梦,在发布过程中掏空开发者钱包或用户资金。
此事件凸显了供应链安全的风险——在 web3 中这是个热门话题,像 Ledger Connect Kit 攻击 等事件已展示出一环薄弱就能造成连锁反应。对于区块链从业者而言,采用诸如使用 npm ci
以保证一致安装、在 package-lock.json 中固定版本、并用 Snyk 或像这个脚本一样的工具进行扫描等实践,能显著降低风险。
保持警惕,朋友们。在 meme token 的世界里,知识是你对抗熊市和黑客的最佳防线。如果你正在做有趣的项目,去 Edgar 的线程下留言或把你的安全建议分享给社区。