axios-security-check

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Axios Supply Chain Attack — Security Check

Axios 供应链攻击 — 安全检查

Attack summary: On March 31, 2026, axios versions
1.14.1
and
0.30.4
were published via a compromised maintainer account. They silently injected
plain-crypto-js@4.2.1
as a dependency, which ran a postinstall script deploying a cross-platform Remote Access Trojan (RAT). Both versions were removed by 03:29 UTC but may remain in local caches or lockfiles.
Run all four phases below and produce the report at the end.

攻击概要: 2026年3月31日,攻击者通过被入侵的维护者账号发布了
1.14.1
0.30.4
版本的axios。这两个版本会静默注入
plain-crypto-js@4.2.1
作为依赖,该依赖会运行postinstall脚本部署跨平台远程访问木马(RAT)。两个恶意版本均在UTC时间03:29被下架,但可能仍残留在本地缓存或锁文件中。
请依次执行以下四个阶段的操作,并在最后生成报告。

Phase 1: Vulnerability Scan

阶段1:漏洞扫描

Search for malicious axios versions in package manifests, lockfiles, and global caches.
Malicious versions:
1.14.1
and
0.30.4
在包清单文件、锁文件和全局缓存中搜索恶意axios版本。
恶意版本号:
1.14.1
0.30.4

1a. Project files under
~

1a. 用户目录下的项目文件

Search for lockfiles and
package.json
files (limit depth to avoid excessive crawling):
bash
undefined
搜索锁文件和
package.json
文件(限制搜索深度避免过度遍历):
bash
undefined

Find package.json files containing axios (depth ≤ 8, skip .git and common noise)

Find package.json files containing axios (depth ≤ 8, skip .git and common noise)

find ~ -maxdepth 8
-not ( -path '/.git/' -o -path '/node_modules//node_modules/*' )
-name "package.json"
-exec grep -l '"axios"' {} ;

For each match, check if `axios` is pinned to `1.14.1` or `0.30.4`:
```bash
grep -E '"axios":\s*"[^"]*1\.14\.1|[^"]*0\.30\.4"' <path>/package.json
Search lockfiles for the malicious versions:
bash
undefined
find ~ -maxdepth 8
-not ( -path '/.git/' -o -path '/node_modules//node_modules/*' )
-name "package.json"
-exec grep -l '"axios"' {} ;

对每个匹配的文件,检查axios是否固定为`1.14.1`或`0.30.4`版本:
```bash
grep -E '"axios":\s*"[^"]*1\.14\.1|[^"]*0\.30\.4"' <path>/package.json
在锁文件中搜索恶意版本:
bash
undefined

package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lock

package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lock

grep -r --include="package-lock.json" --include="yarn.lock"
--include="pnpm-lock.yaml" --include="bun.lock"
-l "axios" ~ 2>/dev/null | head -50

For each lockfile found:
```bash
grep -A2 '"axios"' <lockfile> | grep -E "1\.14\.1|0\.30\.4"
grep -r --include="package-lock.json" --include="yarn.lock"
--include="pnpm-lock.yaml" --include="bun.lock"
-l "axios" ~ 2>/dev/null | head -50

对每个找到的锁文件执行:
```bash
grep -A2 '"axios"' <lockfile> | grep -E "1\.14\.1|0\.30\.4"

1b. Global caches

1b. 全局缓存

Check global package manager caches for cached malicious tarballs:
bash
undefined
检查全局包管理器缓存中是否存在缓存的恶意安装包:
bash
undefined

npm cache

npm cache

find ~/.npm/_cacache -name "*.json" 2>/dev/null | xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null
find ~/.npm/_cacache -name "*.json" 2>/dev/null | xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null

pnpm store (macOS)

pnpm store (macOS)

find ~/Library/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null
find ~/Library/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null

pnpm store (Linux)

pnpm store (Linux)

find ~/.local/share/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null
find ~/.local/share/pnpm/store -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null

bun cache

bun cache

find ~/.bun/install/cache -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null

---
find ~/.bun/install/cache -maxdepth 6 -name "package.json" 2>/dev/null |
xargs grep -l '"axios"' 2>/dev/null |
xargs grep -l '"1.14.1"|"0.30.4"' 2>/dev/null

---

Phase 2: Malware Artifact Check

阶段2:恶意软件残留检查

2a.
plain-crypto-js
presence

2a. 排查
plain-crypto-js
是否存在

The malicious dependency used as the attack vector:
bash
find ~ -maxdepth 10 -type d -name "plain-crypto-js" 2>/dev/null
Any result here means
plain-crypto-js
was installed — the install-time RAT dropper ran.
这是攻击载体使用的恶意依赖:
bash
find ~ -maxdepth 10 -type d -name "plain-crypto-js" 2>/dev/null
任何返回结果都说明
plain-crypto-js
已被安装,安装时的RAT投放脚本已执行。

2b. Platform-specific RAT artifacts

2b. 各平台专属RAT残留文件

Check for files dropped by the RAT dropper. These are fixed paths.
macOS:
bash
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"
Linux:
bash
ls -la /tmp/ld.py 2>/dev/null && echo "FOUND — potential RAT script" || echo "Not found"
Windows (if running in WSL or checking a Windows path):
bash
ls -la /mnt/c/ProgramData/wt.exe 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"
检查RAT投放脚本释放的文件,这些文件的路径是固定的。
macOS:
bash
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"
Linux:
bash
ls -la /tmp/ld.py 2>/dev/null && echo "FOUND — potential RAT script" || echo "Not found"
Windows(如果运行在WSL或检查Windows路径):
bash
ls -la /mnt/c/ProgramData/wt.exe 2>/dev/null && echo "FOUND — potential RAT binary" || echo "Not found"

2c. Active C2 connections

2c. 活跃C2连接

Check for live connections to the attacker's command-and-control server:
bash
undefined
检查是否存在与攻击者命令与控制(C2)服务器的活跃连接:
bash
undefined

By IP

By IP

lsof -i @142.11.206.73 2>/dev/null || echo "No connections to C2 IP"
lsof -i @142.11.206.73 2>/dev/null || echo "No connections to C2 IP"

By domain (if DNS resolves)

By domain (if DNS resolves)

lsof -i 2>/dev/null | grep -i sfrclak || echo "No connections to sfrclak.com"
lsof -i 2>/dev/null | grep -i sfrclak || echo "No connections to sfrclak.com"

By port 8000 (C2 port used)

By port 8000 (C2 port used)

lsof -i :8000 2>/dev/null | grep -v "localhost|127.0.0" || echo "No suspicious :8000 connections"

---
lsof -i :8000 2>/dev/null | grep -v "localhost|127.0.0" || echo "No suspicious :8000 connections"

---

Phase 3: Package Manager Security Audit

阶段3:包管理器安全审计

Detect which package managers are installed and check their security-relevant configuration. Read global config files and project-level config/manifest files in the current directory.
检测已安装的包管理器,检查其与安全相关的配置。读取全局配置文件,以及当前目录下的项目级配置/清单文件。

3a. Detect installed package managers

3a. 检测已安装的包管理器

bash
which npm && npm --version
which pnpm && pnpm --version
which bun && bun --version
which yarn && yarn --version
bash
which npm && npm --version
which pnpm && pnpm --version
which bun && bun --version
which yarn && yarn --version

3b. npm

3b. npm

Config files to read:
  • Global:
    ~/.npmrc
  • Project:
    .npmrc
    in current directory
bash
npm config get ignore-scripts
npm config get min-release-age
npm config get audit
SettingSecure valueDefaultEffect
ignore-scripts
true
false
Disables all lifecycle scripts for all packages
min-release-age
e.g.
259200
(3 days in seconds)
unsetRefuses to install package versions published more recently than the threshold — blocks day-zero malicious publishes
audit
true
true
Checks installed packages against known vulnerability advisories
Note: npm has no per-package script allowlist —
ignore-scripts
is all-or-nothing.
需要读取的配置文件:
  • 全局:
    ~/.npmrc
  • 项目:当前目录下的
    .npmrc
bash
npm config get ignore-scripts
npm config get min-release-age
npm config get audit
配置项安全值默认值作用
ignore-scripts
true
false
禁用所有包的所有生命周期脚本
min-release-age
例如
259200
(3天,单位秒)
未设置拒绝安装发布时间短于阈值的包版本,可拦截零日恶意发布
audit
true
true
对照已知漏洞通告检查已安装的包
注意:npm没有包粒度的脚本允许列表,
ignore-scripts
是全有或全无的配置。

3c. pnpm

3c. pnpm

Config files to read:
  • Global:
    ~/.npmrc
    (pnpm reads this too) and
    pnpm config list
  • Project:
    .npmrc
    ,
    pnpm-workspace.yaml
  • package.json
    pnpm
    field
bash
pnpm config get ignore-scripts 2>/dev/null
pnpm config get ignoreDepScripts 2>/dev/null
pnpm config get minimumReleaseAge 2>/dev/null
pnpm config get blockExoticSubdeps 2>/dev/null
pnpm config get onlyBuiltDependencies 2>/dev/null
pnpm config get neverBuiltDependencies 2>/dev/null
pnpm config get strictDepBuilds 2>/dev/null
pnpm config get dangerouslyAllowAllBuilds 2>/dev/null
Also read project-level files:
bash
cat pnpm-workspace.yaml 2>/dev/null | grep -E "minimumReleaseAge|blockExoticSubdeps|onlyBuiltDependencies|allowBuilds|neverBuiltDependencies|strictDepBuilds|ignoreDepScripts|dangerouslyAllowAllBuilds"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('pnpm',{}), indent=2))" 2>/dev/null
SettingSecure valueDefaultEffect
minimumReleaseAge
e.g.
1440
(1 day, in minutes)
0
Refuses packages published more recently than the threshold — blocks day-zero attacks like this one
minimumReleaseAgeExclude
scoped listunsetPackages exempt from the age check
blockExoticSubdeps
true
false
Transitive deps must come from a registry; blocks git/tarball URL subdependencies injected by attackers
ignoreDepScripts
true
false
Skips lifecycle scripts in dependencies only; project scripts still run
ignoreScripts
true
false
Skips all lifecycle scripts (dependencies and project)
onlyBuiltDependencies
Explicit allowlistunsetOnly listed packages may run install scripts — all others blocked
allowBuilds
Per-package mapunsetNewer alternative to
onlyBuiltDependencies
; supports version constraints and explicit
false
entries
neverBuiltDependencies
Blocklist of known-bad packagesunsetExplicitly prevents listed packages from running scripts
strictDepBuilds
true
false
Install fails if any dependency has unreviewed build scripts — forces explicit approval
dangerouslyAllowAllBuilds
false
false
Flag if this is
true
— it bypasses all script controls
需要读取的配置文件:
  • 全局:
    ~/.npmrc
    (pnpm也会读取该文件)和
    pnpm config list
    的输出
  • 项目:
    .npmrc
    pnpm-workspace.yaml
  • package.json
    pnpm
    字段
bash
pnpm config get ignore-scripts 2>/dev/null
pnpm config get ignoreDepScripts 2>/dev/null
pnpm config get minimumReleaseAge 2>/dev/null
pnpm config get blockExoticSubdeps 2>/dev/null
pnpm config get onlyBuiltDependencies 2>/dev/null
pnpm config get neverBuiltDependencies 2>/dev/null
pnpm config get strictDepBuilds 2>/dev/null
pnpm config get dangerouslyAllowAllBuilds 2>/dev/null
同时读取项目级文件:
bash
cat pnpm-workspace.yaml 2>/dev/null | grep -E "minimumReleaseAge|blockExoticSubdeps|onlyBuiltDependencies|allowBuilds|neverBuiltDependencies|strictDepBuilds|ignoreDepScripts|dangerouslyAllowAllBuilds"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('pnpm',{}), indent=2))" 2>/dev/null
配置项安全值默认值作用
minimumReleaseAge
例如
1440
(1天,单位分钟)
0
拒绝发布时间短于阈值的包,可拦截本次这类零日攻击
minimumReleaseAgeExclude
限定范围的列表未设置不受年龄检查限制的包列表
blockExoticSubdeps
true
false
传递依赖必须来自注册表,拦截攻击者注入的git/压缩包URL形式的依赖
ignoreDepScripts
true
false
仅跳过依赖的生命周期脚本,项目脚本仍可运行
ignoreScripts
true
false
跳过所有生命周期脚本(包括依赖和项目)
onlyBuiltDependencies
显式允许列表未设置仅列表中的包可以运行安装脚本,其余全部拦截
allowBuilds
包粒度映射未设置
onlyBuiltDependencies
的新版替代方案,支持版本约束和显式
false
条目
neverBuiltDependencies
已知风险包的拦截列表未设置显式禁止列表中的包运行脚本
strictDepBuilds
true
false
如果任何依赖存在未审核的构建脚本,安装就会失败,强制显式审批
dangerouslyAllowAllBuilds
false
false
如果该值为
true
需要标记,它会绕过所有脚本控制

3d. bun

3d. bun

Config files to read:
  • Global:
    ~/.bunfig.toml
  • Project:
    bunfig.toml
  • Project
    package.json
    trustedDependencies
    field
bash
cat ~/.bunfig.toml 2>/dev/null || echo "No global bunfig.toml"
cat bunfig.toml 2>/dev/null || echo "No project bunfig.toml"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('trustedDependencies','not set'), indent=2))" 2>/dev/null
SettingLocationSecure valueDefaultEffect
trustedDependencies
package.json
Explicit allowlistTop-500 npm packages auto-trustedOnly listed packages may run lifecycle scripts; any package not on this list is blocked
[install].minimumReleaseAge
bunfig.toml
e.g.
259200
(seconds)
unsetRefuses packages newer than the threshold
[install].lifecycle-scripts
bunfig.toml
Scoped allowlistunsetAlternative/additional script execution control
Note: Bun's default is more secure than npm — scripts are blocked for packages not in the built-in top-500 allowlist. An explicit
trustedDependencies
field in
package.json
overrides this and should be reviewed carefully.
需要读取的配置文件:
  • 全局:
    ~/.bunfig.toml
  • 项目:
    bunfig.toml
  • 项目
    package.json
    trustedDependencies
    字段
bash
cat ~/.bunfig.toml 2>/dev/null || echo "No global bunfig.toml"
cat bunfig.toml 2>/dev/null || echo "No project bunfig.toml"
cat package.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d.get('trustedDependencies','not set'), indent=2))" 2>/dev/null
配置项位置安全值默认值作用
trustedDependencies
package.json
显式允许列表自动信任npm前500热门包仅列表中的包可以运行生命周期脚本,不在列表中的包全部被拦截
[install].minimumReleaseAge
bunfig.toml
例如
259200
(单位秒)
未设置拒绝发布时间短于阈值的包
[install].lifecycle-scripts
bunfig.toml
范围限定的允许列表未设置替代/补充的脚本执行控制机制
注意:Bun的默认配置比npm更安全,不在内置前500允许列表中的包的脚本会被拦截。
package.json
中显式的
trustedDependencies
字段会覆盖默认配置,需要仔细审核。

3e. Yarn (Berry)

3e. Yarn (Berry)

Config files to read:
  • Global:
    ~/.yarnrc.yml
  • Project:
    .yarnrc.yml
bash
cat ~/.yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No global .yarnrc.yml"
cat .yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No project .yarnrc.yml"
SettingSecure valueDefaultEffect
enableScripts
false
true
Disables all lifecycle scripts globally; re-enable per-package via
dependenciesMeta
需要读取的配置文件:
  • 全局:
    ~/.yarnrc.yml
  • 项目:
    .yarnrc.yml
bash
cat ~/.yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No global .yarnrc.yml"
cat .yarnrc.yml 2>/dev/null | grep -E "enableScripts|dependenciesMeta" || echo "No project .yarnrc.yml"
配置项安全值默认值作用
enableScripts
false
true
全局禁用所有生命周期脚本,可通过
dependenciesMeta
针对单个包重新启用

3f. CI/CD workflow check

3f. CI/CD 工作流检查

If
.github/workflows/
exists, check install commands for hardening flags:
bash
grep -r --include="*.yml" --include="*.yaml" \
  -E "npm install|npm ci|pnpm install|bun install|yarn install" \
  .github/ 2>/dev/null | head -20
Flags to look for:
--ignore-scripts
,
npm ci
(vs
npm install
),
--frozen-lockfile
.

如果存在
.github/workflows/
目录,检查安装命令的安全加固 flags:
bash
grep -r --include="*.yml" --include="*.yaml" \
  -E "npm install|npm ci|pnpm install|bun install|yarn install" \
  .github/ 2>/dev/null | head -20
需要关注的flags:
--ignore-scripts
npm ci
(对比
npm install
)、
--frozen-lockfile

Phase 4: Report

阶段4:报告

Produce a clean report with the following structure. Be explicit about each finding — "not found" is a valid and important result.
undefined
按照以下结构生成清晰的报告,每个结果都要明确说明,「未找到」是有效且重要的结果。
undefined

Axios Supply Chain Attack — Security Report

Axios 供应链攻击 — 安全报告

Generated: <date>
生成时间:<date>

Vulnerability Scan

漏洞扫描结果

  • Affected axios versions found in project files: <list paths or "None found">
  • Affected axios versions found in global caches: <list or "None found">
  • 项目文件中发现的受影响axios版本:<列出路径或「未找到」>
  • 全局缓存中发现的受影响axios版本:<列出路径或「未找到」>

Malware Artifacts

恶意软件残留结果

  • plain-crypto-js present: <Yes — <path> | No>
  • macOS RAT binary (/Library/Caches/com.apple.act.mond): <Found | Not found>
  • Linux RAT script (/tmp/ld.py): <Found | Not found>
  • Windows RAT binary (%PROGRAMDATA%\wt.exe): <Found | Not found>
  • Active C2 connections (sfrclak.com:8000 / 142.11.206.73): <Active | None detected>
  • plain-crypto-js是否存在:<是 — <路径> | 否>
  • macOS RAT二进制文件(/Library/Caches/com.apple.act.mond):<已找到 | 未找到>
  • Linux RAT脚本(/tmp/ld.py):<已找到 | 未找到>
  • Windows RAT二进制文件(%PROGRAMDATA%\wt.exe):<已找到 | 未找到>
  • 活跃C2连接(sfrclak.com:8000 / 142.11.206.73):<活跃 | 未检测到>

Package Manager Security Audit

包管理器安全审计结果

For each installed package manager, report the key settings. Use "✓ set", "✗ unset", or the actual value.
npm <version>:
  • ignore-scripts
    : <value>
  • min-release-age
    : <value or "not set">
  • audit
    : <value>
pnpm <version>:
  • minimumReleaseAge
    : <value or "not set">
  • blockExoticSubdeps
    : <value>
  • ignoreDepScripts
    : <value>
  • onlyBuiltDependencies
    /
    allowBuilds
    : <set with N packages | not set>
  • strictDepBuilds
    : <value>
  • dangerouslyAllowAllBuilds
    : <value — flag if true>
bun <version>:
  • trustedDependencies
    in package.json: <explicit list | using defaults>
  • [install].minimumReleaseAge
    in bunfig.toml: <value or "not set">
yarn <version>:
  • enableScripts
    : <value or "not set (defaults to true)">
对每个已安装的包管理器,报告关键配置。使用「✓ 已设置」、「✗ 未设置」或实际值填写。
npm <版本号>:
  • ignore-scripts
    :<值>
  • min-release-age
    :<值或「未设置」>
  • audit
    :<值>
pnpm <版本号>:
  • minimumReleaseAge
    :<值或「未设置」>
  • blockExoticSubdeps
    :<值>
  • ignoreDepScripts
    :<值>
  • onlyBuiltDependencies
    /
    allowBuilds
    :<已设置N个包 | 未设置>
  • strictDepBuilds
    :<值>
  • dangerouslyAllowAllBuilds
    :<值 — 若为true请标记>
bun <版本号>:
  • package.json中的
    trustedDependencies
    :<显式列表 | 使用默认配置>
  • bunfig.toml中的
    [install].minimumReleaseAge
    :<值或「未设置」>
yarn <版本号>:
  • enableScripts
    :<值或「未设置(默认为true)」>

Recommendations

修复建议

[Prioritized list based on findings above — see guidance below]
undefined
[根据上面的发现给出优先级排序的建议,参考下方指南]
undefined

Recommendation guidance (include relevant items only)

建议指南(仅包含相关项)

If compromised (artifacts found or C2 connections detected):
  • Treat as full system breach — isolate immediately
  • Rotate all credentials: API keys, SSH keys, cloud credentials, npm tokens, GitHub tokens
  • Rebuild from a clean snapshot if possible
  • Review logs for C2 traffic to
    sfrclak.com:8000
    /
    142.11.206.73
    between March 31 00:00–04:00 UTC 2026
If malicious axios version found (no artifacts):
  • Remove from lockfile: downgrade to
    axios@1.7.9
    (last safe 1.x) or
    axios@0.29.0
    (last safe 0.x)
  • Delete
    plain-crypto-js
    from
    node_modules
    and lockfile
  • Run fresh install:
    pnpm install
    /
    npm ci
    /
    bun install
For pnpm users:
  • Set
    minimumReleaseAge
    in
    pnpm-workspace.yaml
    — even 24h (1440 min) would have blocked this attack, which published and was removed within ~3 hours:
    yaml
    minimumReleaseAge: 1440  # 1 day in minutes
  • Enable
    blockExoticSubdeps: true
    — the injected
    plain-crypto-js
    could have been delivered via tarball URL; this blocks non-registry transitive deps:
    yaml
    blockExoticSubdeps: true
  • Use
    onlyBuiltDependencies
    or
    allowBuilds
    to allowlist only packages that legitimately need scripts. Prefer
    allowBuilds
    (pnpm 9+) as it supports version constraints:
    yaml
    # pnpm-workspace.yaml
    onlyBuiltDependencies:
      - esbuild
      - sharp
      - "@swc/core"
  • Enable
    strictDepBuilds: true
    so installs fail loudly if an unknown package tries to run scripts:
    yaml
    strictDepBuilds: true
  • Use
    ignoreDepScripts: true
    if you need to run your own project scripts but want to block all dependency scripts (more surgical than
    ignoreScripts
    )
  • Verify
    dangerouslyAllowAllBuilds
    is not set to
    true
    — if it is, remove it immediately
For npm users:
  • Set
    min-release-age
    in
    .npmrc
    — this is the single most effective preventive control for day-zero attacks:
    min-release-age=259200
    (259200 seconds = 3 days; even 3600 = 1 hour would have blocked this attack)
  • Add
    ignore-scripts=true
    to
    .npmrc
    for CI environments (may break packages with legitimate build steps — test first)
  • Use
    npm ci
    instead of
    npm install
    in CI — it respects lockfiles exactly and fails on drift
  • Run
    npm audit --audit-level=high
    in CI pipelines
For bun users:
  • Set an explicit
    trustedDependencies
    in
    package.json
    rather than relying on bun's default top-500 list. Review which packages in your dependency tree genuinely need scripts:
    json
    {
      "trustedDependencies": ["esbuild", "sharp"]
    }
  • Set
    minimumReleaseAge
    in
    bunfig.toml
    :
    toml
    [install]
    minimumReleaseAge = 259200  # 3 days in seconds
For yarn users (Berry):
  • Add to
    .yarnrc.yml
    :
    enableScripts: false
  • Re-enable per package via
    dependenciesMeta
    for packages with legitimate build scripts
General (all users):
  • Always commit lockfiles to version control — they are the source of truth for installed versions
  • Use
    --frozen-lockfile
    /
    --ci
    flags in CI to prevent lockfile drift
  • Consider Socket.dev or Snyk for continuous supply chain monitoring that catches malicious packages before they install
如果已被入侵(发现恶意残留或C2连接):
  • 视为完整系统入侵,立即隔离
  • 轮换所有凭证:API密钥、SSH密钥、云凭证、npm令牌、GitHub令牌
  • 尽可能从干净快照重建系统
  • 排查2026年3月31日UTC 00:00–04:00期间到
    sfrclak.com:8000
    /
    142.11.206.73
    的C2流量日志
如果发现恶意axios版本(无恶意残留):
  • 从锁文件中移除恶意版本,降级到
    axios@1.7.9
    (1.x最新安全版)或
    axios@0.29.0
    (0.x最新安全版)
  • node_modules
    和锁文件中删除
    plain-crypto-js
  • 执行全新安装:
    pnpm install
    /
    npm ci
    /
    bun install
pnpm用户建议:
  • pnpm-workspace.yaml
    中设置
    minimumReleaseAge
    ,即使是24小时(1440分钟)也能拦截本次攻击,本次攻击从发布到下架仅用了约3小时:
    yaml
    minimumReleaseAge: 1440  # 1天,单位分钟
  • 启用
    blockExoticSubdeps: true
    ,注入的
    plain-crypto-js
    可能通过压缩包URL投放,该配置可拦截非注册表来源的传递依赖:
    yaml
    blockExoticSubdeps: true
  • 使用
    onlyBuiltDependencies
    allowBuilds
    仅允许确实需要运行脚本的包,优先使用
    allowBuilds
    (pnpm 9+),支持版本约束:
    yaml
    # pnpm-workspace.yaml
    onlyBuiltDependencies:
      - esbuild
      - sharp
      - "@swc/core"
  • 启用
    strictDepBuilds: true
    ,如果有未知包尝试运行脚本,安装会明确报错:
    yaml
    strictDepBuilds: true
  • 如果需要运行项目自身的脚本但要拦截所有依赖脚本,可以使用
    ignoreDepScripts: true
    ,比
    ignoreScripts
    更灵活
  • 确认
    dangerouslyAllowAllBuilds
    未设置为
    true
    ,如果已设置请立即删除
npm用户建议:
  • .npmrc
    中设置
    min-release-age
    ,这是防范零日攻击最有效的单一控制措施:
    min-release-age=259200
    (259200秒=3天,即使设置3600=1小时也能拦截本次攻击)
  • 在CI环境的
    .npmrc
    中添加
    ignore-scripts=true
    (可能会破坏有合法构建步骤的包,请先测试)
  • 在CI中使用
    npm ci
    替代
    npm install
    ,它会严格遵循锁文件,出现漂移时直接失败
  • 在CI流水线中运行
    npm audit --audit-level=high
bun用户建议:
  • package.json
    中设置显式的
    trustedDependencies
    ,不要依赖bun默认的前500热门包列表,审核依赖树中确实需要运行脚本的包:
    json
    {
      "trustedDependencies": ["esbuild", "sharp"]
    }
  • bunfig.toml
    中设置
    minimumReleaseAge
    toml
    [install]
    minimumReleaseAge = 259200  # 3天,单位秒
Yarn(Berry)用户建议:
  • .yarnrc.yml
    中添加:
    enableScripts: false
  • 对有合法构建脚本的包,通过
    dependenciesMeta
    单独启用脚本
通用建议(所有用户):
  • 始终将锁文件提交到版本控制,它们是已安装版本的唯一可信来源
  • 在CI中使用
    --frozen-lockfile
    /
    --ci
    flags防止锁文件漂移
  • 考虑使用Socket.devSnyk进行持续供应链监控,在恶意包安装前就完成拦截