はじめに
この記事では、pnpm を使っている開発者向けに、5分でできる簡単な対策を8つ紹介します。
※本格的な対策ではないです
対策1: Aikido Safe Chain で install をラップする
Aikido Safe Chain は、pnpm install などをラップし、既知の悪性パッケージをインストール前に止める OSS ツールです。
pnpm add -g @aikidosec/safe-chain
safe-chain setup
# ターミナルを再起動
対策2: pnpm で公開から一定時間経過するまでインストールしない
minimumReleaseAge を設定すると、最新版のパッケージが公開から一定時間経過していない場合にインストールできなくなります。
pnpm-workspace.yaml に以下を追記します。
minimumReleaseAge: 4320 # 72時間(分)
minimumReleaseAgeStrict: true
minimumReleaseAgeIgnoreMissingTime: false
minimumReleaseAgeStrict は最新版しかないパッケージをインストール失敗にできます。 false の場合、最新版がインストールされます。
minimumReleaseAgeIgnoreMissingTime は、リポジトリのメタデータから公開日時が取得できないパッケージもチェック対象となり、該当する場合はインストールを失敗させます。
例外が必要な場合は、minimumReleaseAgeExclude で指定します。
minimumReleaseAgeExclude:
- webpack
- react
パッケージのアップデート直後に脆弱性が発覚した場合はこの設定で被害を免れることができますが、具体的にどれくらい遅延時間をとるのかはお任せします。
対策3: trustPolicy: no-downgrade で publish の信頼低下を検知する
パッケージには publish の信頼性を示す情報(trust evidence)が付くことがあります。pnpm では trusted publisher > provenance > なし の順で信頼の強さが決まります。
pnpm の trustPolicy: no-downgrade は、インストールしようとしているバージョンの信頼性が、それより前に publish されたバージョンのいずれかで得られていた最高の信頼より低い場合にインストールを失敗させる設定です。
pnpm-workspace.yaml に以下を追記します。
trustPolicy: no-downgrade
例外が必要な場合は、trustPolicyExclude で指定します。
trustPolicyExclude:
- 'chokidar@4.0.3'
- 'webpack@4.47.0 || 5.102.1'
- '@babel/core@7.28.5'
すべてのパッケージが provenance や trusted publisher に対応しているわけではないため、初回導入時は例外設定が必要になることがあります。
対策4: allowBuilds で install script を許可制にする
依存パッケージは、インストール時に preinstall / install / postinstall などのスクリプトを実行できます。正当な用途もありますが、悪意あるパッケージに仕込まれると、pnpm install しただけでトークン窃取や任意コード実行につながることがあります。
そこで allowBuilds を使い、install script の実行を必要なパッケージだけ許可します。
pnpm-workspace.yaml に追記します。
allowBuilds:
esbuild: true
core-js: false
nx@21.6.4 || 21.6.5: true
nx@21.6.0: false
対策5: pnpm audit で既知の脆弱性を確認する
pnpm audit で、すでに知られている脆弱性を見つけられます。
しかし、既にマルウェアがインストールされていた場合は、被害に遭っている可能性があるので効果は低いです。
CI/CDなどに組み込むのがお勧めです。
以下で実行します。
pnpm audit --audit-level=high
Medium まで含めると既存プロジェクトでは不便さが体感上回ります。
対策6: devEngines.packageManager で npm install を防ぐ
pnpm 11 以降は devEngines.packageManager で、使うパッケージマネージャとバージョンを宣言できます。
これにより、生成AIや新メンバーが誤って npm install を実行することを防げます。npm は devEngines を解釈するため、name が pnpm だと install 前に EBADDEVENGINES で止まります。
package.json:
{
"devEngines": {
"packageManager": {
"name": "pnpm",
"version": ">=11.0.0 <12.0.0",
"onFail": "download"
}
}
}
onFail: "download" は pnpm install 時に、範囲内の pnpm を自動取得します。取得せず止めたい場合は "error" にします。yarn や bun は対象外です。
対策7: AI エージェントに依存の install / add を行わせない hooks を作る
AI エージェントは、依存が足りないと判断すると pnpm install や npm ci、npx pnpm add などをそのまま実行しようとすることがあります。人間の確認なしに install が走ると、ここまでの対策をすり抜ける入口になります。
そこで エージェントには npm / pnpm / npx 経由の依存変更コマンドを実行させず、必要なら作業を止めてユーザーに報告させる運用にします。
今回は私がCursorを使っているので,その前提だと、Hooks の beforeShellExecution が使えます。
その他のツールでも同じことができると思うので,それぞれに対応させてください.
スクリプトは jq を使います。未インストールだと failClosed: true のため、フック失敗時にシェルコマンドごと止まります。先に入れておいてください。
brew install jq
.cursor/hooks.json を作成します。
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": ".cursor/hooks/block-package-install.sh",
"failClosed": true
}
]
}
}
.cursor/hooks/block-package-install.sh の例です。
#!/bin/bash
set -euo pipefail
input=$(cat)
command=$(echo "$input" | jq -r '.command // empty')
should_block() {
local cmd="$1"
[[ -z "$cmd" ]] && return 1
local ops='install|add|i|ci|update|remove|uninstall|link|unlink|dedupe|fetch'
local sep='(^|[[:space:];|&])'
local flags='([[:space:]]+(-[a-zA-Z]+|--[a-zA-Z-]+(=[^[:space:]]+)?))*'
[[ "$cmd" =~ ${sep}(pnpm|npm)[[:space:]]+(${ops})([[:space:]]|$|--) ]] && return 0
[[ "$cmd" =~ ${sep}npx${flags}[[:space:]]+(pnpm|npm)([[:space:]]+(${ops}))?([[:space:]]|$|--) ]] && return 0
[[ "$cmd" =~ ${sep}corepack${flags}[[:space:]]+(pnpm|npm)([[:space:]]+(${ops}))?([[:space:]]|$|--) ]] && return 0
return 1
}
if should_block "$command"; then
jq -n \
--arg user_msg 'AI は依存の install / add を実行できません。必要なパッケージと理由を確認したうえで、手元で実行してください。' \
--arg agent_msg 'npm / pnpm / npx による依存の変更はユーザーの承認なしに実行しないでください。ここで作業を止め、追加したいパッケージ名・理由・想定コマンドをユーザーに報告してください。' \
'{permission: "deny", user_message: $user_msg, agent_message: $agent_msg}'
exit 0
fi
jq -n '{permission: "allow"}'
ブロック対象の例: pnpm install、npm ci、pnpm update、npx pnpm add、npx -y npm install、corepack pnpm install など。
スクリプトに実行権限を付けます。
chmod +x .cursor/hooks/block-package-install.sh
対策8: GitHub の Dependabot alerts を有効にする
Dependabot alerts を有効にすると、リポジトリの依存関係に既知の脆弱性が見つかったときに GitHub 上で通知してくれます。
GitHub のリポジトリ設定から、Code security and analysis に進み、Dependabot alerts を有効化します。自動で修正 PR も出したい場合は、あわせて Dependabot security updates も有効にします。
おわりに
他にも手軽にできる対策があれば、教えてください。