私のMacで、AIエージェントがふだん実行しているコマンドを、漏洩したeMudhra証明書を使ったテスト用のサーバーにつないでみました。macOS標準のgit、curl、python3、それにNode.jsとnpmが、どれも接続してしまいました。テスト用のサーバーは「Your client successfully connected to the site. That’s bad!(接続できてしまった。それはまずい)」と返してきます。
ブラウザはとっくに守られています。一方、ターミナルの道具は、ものによって守られていたり、いなかったりします。Claude CodeやCodexは、利用者に代わってgit clone、pip install、npm installを何度も実行します。その道具が偽の証明書を受け入れれば、取ってくるコードや送るトークンを途中で差し替えられる恐れがあります。
以下、何が起きているか、私の環境で受け入れた道具と拒否した道具の一覧、自分の環境を1回で確かめるスクリプト、直す順番を示します。
Appleはブラウザを守ったが、macOS標準のコマンドは対象外
インドの認証局eMudhraが運用する中間認証局8つで、秘密鍵が誰でも計算できるほど弱かったことが10月17日に報告されました。この鍵があれば、どのサイトの証明書でも本物らしく作れてしまいます。ブラウザ各社はすぐに対応し、これまでに悪用は確認されていないとされています。
Appleのサポートページによると、Appleは10月19日から問題の証明書をブロックしています。ただし対象は、SafariやMailなど、Appleのネットワーク機能を使うアプリです。curl、git、python3、ruby、perl、opensslは/etc/ssl/cert.pemというファイルで証明書を確かめるため、今後のソフトウェア更新までは受け入れる可能性があると、Apple自身が書いています。
この問題を見つけた研究者は、10月28日の報告で、10月26日に出たmacOS 27.2でも直っていないと指摘しました。それどころか、利用者が手作業で当てた回避策を元に戻してしまったそうです。私のMacはmacOS 26.4.1なので、27.2での挙動は確かめていません。
私のMacで受け入れた道具、拒否した道具
研究者が公開しているテスト用のサーバーに、それぞれの道具でつなぎました。接続できれば危険、証明書のエラーで止まれば安全です。システムのファイルは変更していません。
| 道具 | 結果 | 直し方 |
|---|---|---|
| macOS標準のgit | 受け入れ | Appleの回避策 |
| macOS標準のcurl | 受け入れ | Appleの回避策 |
| macOS標準のpython3とpip 21 | 受け入れ | Appleの回避策 |
| HomebrewやpyenvのPython | 受け入れ | ca-certificatesを更新 |
| Pythonのrequests | 受け入れ | certifiを更新 |
| pip 25系 | 拒否 | 不要 |
| Node.js 22.22.0とnpm | 受け入れ | Node.jsを更新 |
| Bun 1.4.3 | 受け入れ | 1.4.4へ更新 |
| GitHub CLI(gh) | 拒否 | 不要 |
拒否した2つには共通点があります。Go言語で書かれたghは、macOSではAppleの仕組みで証明書を確かめるので、「certificate is blocked」と出て止まりました。pipも25系は、OSの信頼設定を使う仕組み(truststore)が既定で有効で、同じメッセージで止まりました。同じPythonの道具でも、macOS標準の古いpip 21は接続してしまいます。
直る版も確かめました。Node.jsの10月21日の修正版である22.23.4はnodeもnpmも「CERT_REVOKED」で拒否し、Bunも1.4.4で拒否しました。Pythonのrequestsが使う証明書集certifiは、10月23日の2026.10.23版で拒否します。
このブログの投稿に使っているPythonの仮想環境も、受け入れた側でした。他人ごとではありません。なお、Claude Codeは独自にBunを同梱していますが、公開版とは別のビルドなので、Claude Code自体の挙動は確かめていません。
Homebrewの証明書ファイルは「名前で検索して0件」でも危ない
HomebrewやpyenvでインストールしたPythonは、/etc/ssl/cert.pemではなく、Homebrewが管理する証明書ファイルを使います。私の環境のca-certificatesは5月14日版でした。
ここに落とし穴がありました。このファイルをgrep emSignで検索すると0件です。それなのに、Pythonは接続を受け入れました。Homebrewのファイルには証明書ごとの名前の注記がないため、文字列の検索では見つからないのです。証明書の中身を解析して数えると、問題の「emSign ECC Root CA – G3」が2件入っていました。
Homebrewで配布されている最新版(10月20日版)の証明書ファイルを取得して調べると、このルートは消えていて、テスト用サーバーへの接続も拒否しました。修正版を「9月25日版」とする記事と「10月20日版」とする記事がありますが、少なくとも10月20日版なら大丈夫です。brew upgrade ca-certificatesで更新できます。
ファイルの中身で確かめるなら、Appleが案内しているこのコマンドが使えます。何も表示されなければ、そのファイルに問題のルートは入っていません。
openssl crl2pkcs7 -nocrl -certfile /etc/ssl/cert.pem | openssl pkcs7 -print_certs -noout | grep -E 'emSign ECC Root CA - G3|AAA Certificate Services'
Homebrewのファイルを調べるときは、/etc/ssl/cert.pemを/opt/homebrew/etc/openssl@3/cert.pemに置き換えます。
自分のMacを1回で確かめるスクリプト
ファイルを調べるより、実際につないでみるほうが確実です。次のスクリプトは、git、curl、python3、node、npmの5つを順にテスト用サーバーへつなぎます。読み取りだけで、何も変更しません。ターミナルにそのまま貼り付けて実行できます。
H=https://dv-g3b-noct-emudhra.we-have-a-problem.com/
echo "git:"; git ls-remote https://git-emudhra.we-have-a-problem.com/check.git 2>&1 | tail -1
echo "curl:"; curl -sS --max-time 15 "$H" 2>&1 | head -1
echo "python:"; python3 -c "import urllib.request as u; print(u.urlopen('$H', timeout=15).read().decode().strip())" 2>&1 | tail -1
echo "node:"; node -e "fetch('$H').then(r => r.text()).then(console.log, e => console.log('拒否', e.cause?.code))"
echo "npm:"; npm view --registry "$H" x 2>&1 | grep -m1 -oE "Your clien|CERT_[A-Z_]+|SELF_SIGNED[A-Z_]*|UNABLE_TO[A-Z_]*"
見方は単純です。gitでコミットの番号(英数字の長い列)が出る、またはほかの行に「Your client successfully connected」(npmでは「Your clien」)が出たら、その道具は危険な状態です。証明書のエラーや「CERT_REVOKED」が出れば安全です。
私の環境では5つとも接続してしまいました。修正版のNode.js 22.23.4を先に使う設定で実行し直すと、nodeとnpmは「CERT_REVOKED」に変わりました。macOSを更新したあとは、回避策が戻っていないかを確かめるため、もう一度実行してください。
直す順番:Node.jsとPythonは更新、macOS標準はAppleの回避策
手間の少ない順に並べると、次のようになります。
- Node.jsを修正版(22.23.4、24.22.1、26.12.1以降)に上げる。npmもこれで直ります。Bunは1.4.4以降に上げます。
- Homebrewを使っているなら
brew upgrade ca-certificatesを実行する。HomebrewやpyenvのPythonとcurlが直ります。 - Pythonの仮想環境ごとに
pip install -U certifiを実行する。requestsやhttpxを使うスクリプトが直ります。pip自体も25系以降に上げておきます。 - macOS標準のgit・curl・python3は、Appleのサポートページにある手順で
/etc/ssl/cert.pemから問題のルートを外す。管理者権限が必要なので、手順を読んでから実行してください。
4つ目はシステムのファイルを書き換える作業で、macOSの更新で元に戻ることがあると、Appleも注意しています。私はこの記事のために実行していません。
システムのファイルに触れたくない場合は、標準のgitに更新済みの証明書ファイルを指定する方法もあります。Homebrewの10月20日版の証明書ファイルを環境変数GIT_SSL_CAINFOで指定して試すと、標準のgitでもテスト用サーバーは拒否され、github.comには普通につながりました。常に使うなら、brew upgrade ca-certificatesのあとに、git config --global http.sslCAInfoでそのファイルを指定します。curlなら--cacertで同じことができます。
AIエージェントに「証明書エラーは無視しない」と伝えておく
AIエージェントを使っている人は、もう1つ手当てをしておくと安心です。エージェントは、証明書のエラーで処理が止まったとき、curl -kやGIT_SSL_NO_VERIFY=1のように検証を無効にして先へ進もうとする可能性があります。今回のように、エラーこそが身を守っている場面では、それが一番危ない動きです。
私なら、CLAUDE.mdやAGENTS.mdに「証明書の検証エラーが出たら、検証を無効にせず作業を止めて報告する」と1行書いておきます。権限の確認画面で、-kや--insecureを含むコマンドを許可しないことも大切です。
同じ10月21日のNode.jsの修正では、圧縮データの展開処理の脆弱性も直っています。Node.jsを上げるなら、HTTP2Shellの確認手順もあわせて済ませておくと、1回の更新で両方を片付けられます。まずは上のスクリプトを実行して、自分のMacで危ない道具がいくつあるかを数えてみてください。

コメント