ここ数ヶ月ほどサプライチェーン攻撃の被害が続いています。手元では各種パッケージマネージャを使いますし、AIエージェントやプラグイン機構のあるアプリケーションを使っているので、攻撃の影響を受けないとは言い切れません。サプライチェーン攻撃に対して完全な対策はおそらく不可能と思われるため、被害を受けたとしても影響を小さくするための対策をいくつか手元環境に実施しました。方針としては以下の通りです。
- 環境変数やファイルシステム上にむき出しの認証情報をなるべく残さない
- 避けようがない場合は必ず暗号化を施して残す
- 可能ならアプリケーション自体を隔離する
- 多少不便になる程度なら不便を受け入れる
- 我慢できないほど面倒ならリスクを飲む
GitHubでトークン認証をやめてSSH認証に切り替える
BlueskyでRuss Coxが言及していましたが、トークンが盗まれてしまえばそれだけで攻撃者に強い権限を与えてしまうことになります。
bsky.appOn the topic of tokens, it is very wrong that a project on GitHub or NPM can insist on 2FA for people logging in, but then those same systems allow using these short easily stolen strings as 1FA methods with equivalent power. Recent attacks demonstrate the significant lateral movement this enables.
— Russ Cox (@swtch.com) 2026-04-06T13:45:59.823Z
上の発言はCI等で使っているトークンを指しているのだろうとは思うのだけれど、それはそれとして手元のトークンであっても同じものですし、トークン自体は暗号化されていないし、意外と簡単なコマンドで取り出せたりします。トークン認証を使っている人は以下のコマンドを実行してみてください*1。
# ENDの前に空行が必要です cat <<END | git credential fill protocol=https host=github.com username=(お使いのGitHubユーザー名) END
なのでトークンは絶対に盗まれてはいけないのだけど、現状ではサプライチェーン攻撃によって任意のコード実行が行われる可能性を否定できないため確実にトークンを守れる保証がありません。反面、SSH認証ではファイルシステム上に鍵が置かれることになるけれども、パスフレーズを設定してさえいれば暗号化した状態なので、盗まれても復号の手間があるSSH認証の方が安全と判断しました。以前はSSHのポートにアクセスできない環境でもトークン認証なら使える等がありましたけれど、今はHTTPSポートを通してSSH接続が可能になっているようです。
SSH鍵をTPMで保護する
最近のハードウェア事情ではTPMを使えることが多いです。SSH鍵にパスフレーズを設定しておけばある程度は安全だと思っていますが、TPMで保護すると「保護したTPMがなければ復号できない」といえる程度に強度が上がるそうです*2。一次情報は見つけられませんでしたが「復号したデータはTPMの中だけで扱われる」と「パスフレーズよりもビット長が長いキーで暗号化する」の2点においてパスフレーズよりも強い暗号処理を実現しているとのことです。
ということで、手元の環境はTPMが利用できる状態だったのでSSH鍵をTPMで保護します。具体的には以下のコマンドで利用可能かどうかが分かります。
$ tpm2_getcap algorithms ... ecc: value: 0x23 asymmetric: 1 symmetric: 0 hash: 0 object: 1 reserved: 0x0 signing: 0 encrypting: 0 method: 0 ... $ tpm2_getcap ecc-curves TPM2_ECC_NIST_P256: 0x3 TPM2_ECC_NIST_P384: 0x4 TPM2_ECC_BN_P256: 0x10
NIST P-384に対応していることが分かったので、これで暗号化していきます。手元の環境はGPGエージェントをSSHエージェントとして使っているのでその手順を書きます。GPGエージェントを設定されていない場合は、以前書いた記事を参考にしてください。
またはSSHエージェントをそのまま使いたい場合は、fujiwaraさんがZennの記事を書いていたので、こちらが参考になるかもしれません。
TPM保護の具体例
ではGPGでSSH鍵を作っていきます。マスターキーは既にあるものとしています(以下の例では BF6A9... がマスターキーのフィンガープリントです)。
gpg --edit-key --expert BF6A9F34814124AE28BD01597C63237ED4C24B72
次に認証ロール(A)だけ持った鍵ペアをNIST P-386で作成します。
gpg> addkey ... (11) ECC (set your own capabilities) ... Your selection? 11 ... (4) NIST P-384 ... Your selection? 4
これであとはGPGの key コマンドで今回作成したサブキーを選択して keytotpm を実行すれば終わりです。
gpg> key 6FECA71FEFEF8777
...
ssb* nistp384/6FECA71FEFEF8777
created: 2026-05-25 expires: never usage: A
gpg> keytotpm
ここでパスフレーズを2回聞かれます。最初はもともと鍵に設定していたパスフレーズで、2回目は今後TPMでこの鍵を扱うためのアクセスに必要となるパスフレーズです。TPMで保護された状態になると以下のように TPM-Protected 属性が付いたり、> が付いた表示となります。この記号は「鍵がスマートカードなどの別媒体に存在している」を意味するようです。
$ gpg --edit-key
...
ssb nistp384/6FECA71FEFEF8777
created: 2026-05-25 expires: never usage: A
card-no: TPM-Protected
$ gpg -K
[keyboxd]
---------
...
ssb> nistp384 2026-05-25 [A]
keytotpm については以下の記事を参考にしました。
GitHub CLIはどうするか
GitHub CLIはSSHで認証することがおそらくできないのでトークン認証を使うことになってしまいますが、上で書いたようにトークンは使いたくありませんので手元での利用を諦めました。トークンに read 権限しか持たせないようにする方法もあるかもしれませんが、それはそれとして gh auth token で簡単に取り出せてしまうのも怖いため、多少の不便は仕方ないかなと思います。良い方法があれば教えて下さい。
クールダウン期間を設定する
この辺りはよく言われている話ですね。NPMなら min-release-age= を、Dependabotなら cooldown パラメータを設定します。
min-release-age=7
Goにはそのような仕組みがまだありませんが、proposal: cmd/go: support dependency cooldown in Go toolingで実装が進んでいるようです。これが実装されるまではDependabot等を使って更新するとか、もしくは脆弱性の修正を除いて更新しない選択肢もあるかもしれません。
上に貼ったRussのスレッドでも、そのようなことが書かれています。
bsky.appAnd speaking of NPM (which GitHub owns), postinstall.js is a decision worth reconsidering. So is "always download the latest version of all dependencies". The justification was to push the latest security fixes immediately, but more often these days it pushes the latest malware immediately instead.
— Russ Cox (@swtch.com) 2026-04-06T13:45:59.824Z
postinstallを無効にする
これは賛否あるようですが、怖いので手元では無効にしました。NPMでは ignore-scripts= パラメータを設定します。
ignore-scripts=true
これを設定するとパッケージ開発者が想定している処理を行わないことになるので、それに伴った意図しないエラーが発生する可能性はあります。あるけれども @^1.1.0 などのパッケージ自動更新と組み合わせると任意のコード実行が行われる可能性が上がるため、困ったら一時的に戻すなど考えればいいかなと今は思っています。
アプリケーションからファイルを隔離する
ここまでで、パッケージマネージャを利用する範囲では、侵害されたバージョンが公開されても直ちに影響を受けなくなりましたが、パッケージマネージャ以外では依然として最新バージョンが適用されてしまう状況があります。例えばブラウザやVS Codeの拡張がそうですし、プライベートで使っているObsidianプラグインや(最近使い始めた)Beancountプラグインなどもあります。そこを野放しにしておくと感染源となりかねないので対策をしました。
具体的には、LinuxにはFlatpakというパッケージマネージャ兼アプリケーション実行環境があって、これはアプリケーション実行前にコンテナを作成して環境を閉じ込めることができるので、アプリケーションには必要な部分だけ見せるようにするといいのではないかと考えました。例えばVS Codeならソースコードを置いたディレクトリ以外は見せなくてもいいはずですし、ObsidianなどもVaultだけで良いはずです。ということで以下のようなオプションを設定しておくと、アプリケーション必要な分部木だけを与えられるようになります。以下はVS Codeの例ですが、どのアプリケーションでもだいたい同じです。
# ~/src 以下だけアプリケーションに公開する例 flatpak --user override --nofilesystem=host --filesystem=home/src
正しくファイルシステムの分離が設定できているかは、flatpak run --command=bash でコンテナを起動すれば確認できます。詳細は以下の公式ドキュメントを参照してください(しかしあまり詳しく書かれていない...)。
OSの更新などはどうするか
Arch Linuxを使っているので pacman がそれに該当しますが、Arch Packageの習慣として新バージョンが公開される前にまずはテストリポジトリで公開する運用のようなので、そこで min-release-age= 相当の担保はされているんじゃないかと思っています。
AURに関しては、もともと自分自身の使い方ではAURからインストールしたパッケージは2つ程度なので、人間が最終更新日をみて min-release-age= と同等の運用になるよう注意すればなんとかできるかなと思っていますが、どうでしょうか。yay には該当のイシューが立っていました。
まとめ
ここまでで、なるべく侵害されないように対応できたと思いますし、仮にシークレットを盗まれても復号されるまでの時間的な猶予は得られたので多少は安心できるのではないでしょうか。GitHub CLIを使えなくなった等の不便な状況も起きてしまいますが、さすがに恒久的にこのままとは思わないので、根本対策されるまでは多少の不便は仕方ないですね。
2026年5月時点では以上ですが、この他にもなにかあるかもしれないので、より安全になるように対策をしていきます。
宣伝
所属している会社がインターン参加者を募集していますので、興味のある学生さんがいたら気軽に応募してみてください。




