DevContainer でエコシステムのサプライチェーン攻撃からマシンを守る
2026年 09月 03日 木曜日
昨今 Node.js を始めとしたエコシステムのパッケージ依存関係を狙ったサプライチェーン攻撃が多発しています.
postmanやzapierが攻撃されていた。bunをインストールして悪意のあるスクリプトが動くっぽい / Shai Hulud Strikes Again (v2) - Socket https://t.co/q0xsBHYyhh
— hiroppy | iiba (@about_hiroppy) November 24, 2025
なんとかならないのか
Node.js は長い年月により枯れたエコシステムです.それに伴い規模は非常に大きいもので,全世界に数百万のパッケージが存在している上に,それらのパッケージは全世界のプロダクトに利用されています.
私個人としては Node.js のエコシステムに関しては 呆れ と 諦念 の感情が強く,この脆弱なシステムはもはやどうしようもないと考えています.
どうにかなってたら恐らく Deno は産まれていませんし,こんなサプライチェーン攻撃が頻繁には行われないでしょう.
(Deno も Node.js / npm を強烈に皮肉っています)
DevContainer とは
エコシステムが脆弱なら,ローカルを最後の砦として守っていかなければなりません.そこで DevContainer を使うことにしました.
- コンテナを完全な開発環境として利用する仕組みおよびそれらを定義するためのオープンな仕様のこと
- 単なるツールと思われがちだが,今は任意の開発ツールがコンテナを完全な開発環境して使うための標準を定める仕様として整備されています.
- もともと VSCode の機能として Microsoft が導入したもの
- 今のところ VSCode や Visual Studio, JetBrains IDE,Emacs などが対応しています.
- 最近流行ってる Zed も対応はしている… まだ発展途上なので使うときは注意が必要
何が嬉しいのか
- 環境をコードとしてリポジトリにコミットできるため,README に手順書を書かなくても,同じ環境を誰でも再現することができます.
- ローカルにある Docker はもちろん, GitHub Codespaces のようなクラウド環境でも同じ定義が使えます.
- Codespace 上で作業しているときも,実態としては DevContainer が使用されている.
- CI 上でも同じ定義を使って,ビルド・テストを回せるため,「ローカルでは動くのに CI では動かない」という問題を減らせるます.
イメージの定義
- プロジェクトルートに
.devcontainer/devcontainer.jsonを置き,ここに開発環境の定義を書きます. - VSCode などの対応ツールがこの JSON を読み,コンテナをビルド・起動し,エディタや拡張機能などを動かしてくれます..
{
"name": "lightweight-alpine-devcontainer",
"image": "mcr.microsoft.com/devcontainers/base:alpine",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": false,
"configureZshAsDefaultShell": false
}
},
"postCreateCommand": "echo '=== Dev Container Ready ===' && cat /etc/os-release && du -sh /",
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker"
]
}
},
"forwardPorts": []
}実際に動かしてみる
実際にこの DevContainer を Zed で開いてみたいと思います.
プロジェクトルートに以下の内容の .devcontainer/devcontainer.json を設置します.
{
"name": "lt-demo-node20-alpine",
"image": "node:20-alpine",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": false,
"configureZshAsDefaultShell": false,
"username": "node"
}
},
"remoteUser": "node",
"postCreateCommand": "echo '=== Dev Container Ready ===' && cat /etc/os-release && node -v && { du -shx / 2>/dev/null || true; }",
"customizations": {
"zed": {
"extensions": [
"cspell"
]
},
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker"
]
}
}
}
コマンドパレットを開き Projects: open remote を実行すると Connect DevContainer が表示されるので,そのまま Enter.
そうするとコンテナがビルド・起動され,Zed がそのコンテナに対して接続を行います.
先ほどの devcontainer.json では Node.js v20 をイメージにコンテナを作成しました.そのため,ローカルとコンテナ間の Node.js が完全に分離された状態で稼働しています.
"image": "node:20-alpine",
万が一サプライチェーン攻撃の疑いがあるパッケージが混入してもパッケージが攻撃できるのは DevContainer で稼働しているコンテナのみのため,ローカルは無傷で済むわけです.
おわりに
DevContainer におけるローカル防御を紹介しました.AI によるハードル低下によって Node.js を狙ったサプライチェーン攻撃は今後増えると考えています.
エコシステムの防御を鵜呑みにせず,自分のマシンは自分で守ることが大切だと思います.