社内の基幹システムからAPIを呼ぶPythonのバッチや、Webアプリのコンテナで requests を使っている場合、TLSの接続先を信頼するかどうかは、多くの場合 certifi という小さなパッケージに入った証明書の束(cacert.pem)で決まります。OSの証明書を更新しても、この束は変わりません。そのため、束に問題が見つかると、Pythonの依存とコンテナのイメージを作り直さない限り、古い束を使い続けることになります。
2026年10月20日(UTC)、GitHub Advisory Database に certifi のアドバイザリ GHSA-6q48-6c7w-9gw2 が CRITICAL で登録されました。束に含まれていた emSign ECC Root CA - G3 というルート証明書について、そこにつながる eMudhra の中間CAの秘密鍵が侵害され、CAが失効させたという内容です。修正版は certifi 2026.10.19 です。
本記事では、アドバイザリ、certifi のリポジトリ、PyPI と pip の公開物を確認し、手元の仮想環境で版ごとの束の中身を比べました。Pythonの業務システムやコンテナを保守する開発者向けに、何が変わったか、どこに古い束が残るか、どう確かめるかを整理します。
消えたのはemSign ECC Root CA - G3の1つ
アドバイザリの説明は次のとおりです(抜粋)。
Certifi versions before 2026.10.18 include the
emSign ECC Root CA - G3root certificate in their bundled CA store. Eight eMudhra intermediate CA certificates that chain to this root have compromised private keys and the CA has revoked them.
侵害された鍵を持つ攻撃者は、任意のホスト名に対して正しく見える証明書を発行でき、通信経路上にいれば、certifi の束を信頼するクライアントのTLS通信を傍受・改ざんできるとしています。影響を受ける例として requests、urllib3、pip、Python.org の macOS 向けインストーラーが挙がっています。対象範囲は 2019.03.09 以上 2026.10.19 未満です。
修正は2段階で出ました。certifi のリポジトリの履歴と、各版の cacert.pem を取り出して比べた結果は次のとおりです。
| 版(PyPI の公開日時 UTC) | 束の証明書の数 | emSign のルート |
|---|---|---|
| 2026.7.22(7月22日) | 121 | G1・G3・C1・C3 の4つ |
| 2026.10.18(10月18日 16:21) | 117 | なし(「Remove emsign」で4つとも削除) |
| 2026.10.19(10月20日 02:24) | 120 | G1・C1・C3 の3つ(G3 は戻らず) |
アドバイザリは「Certifi 2026.10.18 removed all emSign roots from the bundle. Certifi 2026.10.19 restored the emSign roots that are not affected. Upgrade to 2026.10.19 or later」と書いています。2026.7.22 と 2026.10.19 の束を証明書ごとに比べると、違いは emSign ECC Root CA - G3(SHA-256 のフィンガープリント 86:A1:EC:BA:…:6B:BE:6B)が無くなった1点だけでした。

2026.10.18 は、影響のない3つのルートも消していました。編集部の整理では、2026.10.18 に上げた環境で、この3つのルートにつながる証明書を使う接続先がある場合は、検証に失敗する可能性があります。今から上げるなら 2026.10.18 で止めず、2026.10.19 以上にします。
どのライブラリがどの束を信頼しているか
更新の対象を見極めるには、使っているライブラリが certifi の束を読むのか、OSの証明書ストアを読むのかを分けて考えます。ソースで確かめた範囲は次のとおりです。
| 使い方 | 信頼する証明書 | 確かめた根拠 |
|---|---|---|
requests で verify を指定しない | certifi の cacert.pem | requests/certs.py が from certifi import where、adapters.py が DEFAULT_CA_BUNDLE_PATH を使う |
| pip(Python 3.10 以上) | OS のストア + pip に同梱した certifi | index_command.py が truststore の文脈に certifi.where() を追加で読み込む |
urllib3 を単体で使い ca_certs を渡さない | OS のストア | util/ssl_.py が load_default_certs() を呼ぶ |
requests/certs.py のコメントには「This module returns the preferred default CA certificate bundle. There is only one — the one from the certifi package.」とあります。httpx も PyPI の依存に certifi を持っています(中身の読み込み方は今回は確かめていません)。
pip は 24.2 から、Python 3.10 以上ではOSの証明書と certifi の両方で検証するようになりました(NEWS の「Use system certificates and certifi certificates to verify HTTPS connections on Python 3.10+.」)。OSのストアを使う設定でも、pip に同梱した certifi の束は読み込まれ続けます。pip 26.2.2(10月20日公開)の NEWS には「Upgrade certifi to 2026.10.19」とあり、同梱の certifi が修正版に上がりました。直前の 26.2.1 の同梱の certifi は 2026.06.17 で、G3 を含んでいます。
アドバイザリが例に挙げる urllib3 は、上の表のとおり、単体で ca_certs を渡さなければOSのストアを使います。ただしアプリが ca_certs=certifi.where() を渡している場合は certifi の束を使うため、コードで指定を確かめます。
手元で版ごとの束を比べた
2026年10月21日、編集部の検証環境(Linux、Python 3.11.17)で仮想環境を作り、PyPI から取得した wheel(ハッシュを PyPI の値と照合)を入れて確かめました。
$ python -m venv venv
$ venv/bin/python -m pip --version
pip 24.0 from …/venv/lib/python3.11/site-packages/pip (python 3.11)
$ venv/bin/python -c "import pip._vendor.certifi as c; print(c.__version__)"
2023.07.22
# certifi 2026.7.22 と requests 2.34.2 を入れた状態
certifi 2026.07.22
requests DEFAULT_CA_BUNDLE_PATH = …/site-packages/certifi/cacert.pem
certs 121 | emSign ECC Root CA - G3: True | emSign Root CA - G1: True
# certifi 2026.10.19 に上げた状態
certifi 2026.10.19
certs 120 | emSign ECC Root CA - G3: False | emSign Root CA - G1: True
# pip を 26.2.2 に上げた状態
pip 26.2.2 vendored certifi 2026.10.19
requests の既定の束は、仮想環境に入った certifi の cacert.pem を指しており、certifi を上げると G3 が束から消えました。
もう1つ分かったのは、python -m venv で作った仮想環境の pip が古いことです。この環境では Python 3.11 に付属の pip 24.0 が入り、同梱の certifi は 2023.07.22 でした。アプリの certifi を上げても、pip 自身はこの古い束を使い続けます。Dockerfile で python -m venv の後に pip を上げていない場合は、pip も上げます。
REQUESTS_CA_BUNDLE を設定すると、requests は certifi の代わりにその束を使います(REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt で verify がそのパスになることを確認)。この場合は、指定先の束を更新する側の管理になります。
コンテナと本番環境で確かめる手順
ここからは編集部の提案です。古い束は、アプリの依存、コンテナのイメージ、pip の3か所に残り得ます。
- ロックファイルを検索する。
requirements*.txt、poetry.lock、uv.lock、Pipfile.lockで certifi の版を確かめます。直接の依存でなくても、requestsなどの依存として入っています。 - 動いている環境で版を見る。 イメージやサーバーで
python -c "import certifi; print(certifi.__version__, certifi.where())"を実行し、2026.10.19 以上かを確かめます。仮想環境が複数あるサーバーでは、アプリが実際に使う Python で実行します。 - pip と uv の同梱版を見る。
python -c "import pip._vendor.certifi as c; print(c.__version__)"で 2026.10.19 以上(pip 26.2.2 以上)かを確かめます。pip 26.2.2 は Python 3.10 以上が対象で、10月21日時点で Python 3.9 以前で使える修正版の pip は PyPI に出ていません。uv は certifi ではなく自前で同梱した証明書の束を使うため、別のアドバイザリ GHSA-hq85-5cpj-mr62 の修正版 0.13.4(10月20日公開)以上かをuv --versionで確かめます。 - イメージを作り直す。 アドバイザリは「rebuild container images that vendor certifi」と求めています。ロックファイルで certifi を固定している場合は、版を上げてからビルドします。ベースイメージのキャッシュで古い層が使われていないかも確かめます。
verifyの指定を検索する。verify=、ca_certs=、REQUESTS_CA_BUNDLE、SSL_CERT_FILEを検索し、certifi 以外の束を指している箇所は、その束の管理者と更新を確かめます。
すぐにイメージを作り直せない場合でも、certifi は依存が少ないパッケージで、PyPI 上の対応する Python は 3.7 以上です。requests の要求は certifi>=2023.5.7 のため、certifi だけを 2026.10.19 に上げても requests の依存の条件は満たします。編集部は、まず certifi と pip を上げ、ビルドし直したイメージで上の2・3を確かめる順を勧めます。
Linux ディストリビューションのパッケージで入れた Python では、requests/certs.py のコメントにあるとおり、where() をOSの束に置き換えている場合があります。その場合はOSの ca-certificates などの更新が必要になります。今回の件を報告した人がまとめたページ(emudhra.we-have-a-problem.com)には Ubuntu・Debian・Alpine などの修正版の一覧がありますが、各ディストリビューションの告知そのものは今回確認していません。
証明書の運用全体の見直しは、CTログからの発見を前提にしたステージングの守り方や、SSL証明書の有効期限の短縮と自動更新でも扱っています。uv 0.13 系のほかの変更点は、uv 0.13の変更点で扱っています。
確認した範囲
2026年10月21日に、github/advisory-database の GHSA-6q48-6c7w-9gw2 の JSON、certifi/python-certifi のリポジトリ(コミット「Remove emsign」「Restore unaffected emSign roots」、タグ 2026.07.22・2026.10.18・2026.10.19 の
cacert.pem)、PyPI の certifi・pip・requests・httpx の公開情報、pypa/pip のリポジトリ(NEWS.rst、index_command.py)を確認しました(資料調査)。あわせて Linux(Python 3.11.17)の仮想環境で、certifi 2026.7.22・2026.10.18・2026.10.19 の束の証明書を openssl で比べ、requestsが使う束のパス、REQUESTS_CA_BUNDLEの効き方、pip 24.0・26.2.1・26.2.2 の同梱の certifi の版を確かめました(実機検証)。侵害された中間CAの証明書を使った通信、2026.10.18 での接続の失敗、Windows・macOS、各Linuxディストリビューションのパッケージ、Mozilla の証明書ストアでの扱いは確認していません。公開前の10月21日には、discuss.python.org の Python 向けの案内(certifi 2026.10.19・pip 26.2.2・uv 0.13.4 などへの更新とイメージの作り直しを求める内容)、uv のアドバイザリ GHSA-hq85-5cpj-mr62、報告者がまとめたページの中間CAの一覧も確認しました。
Pythonで作った業務システムやバッチの依存とコンテナの更新は、開発・AI・自動化のご相談からお問い合わせください。
参考資料
- GHSA-6q48-6c7w-9gw2: certifi bundles emSign root CAs with compromised intermediate CA keys(github/advisory-database)
- GHSA-6q48-6c7w-9gw2(certifi/python-certifi)
- certifi/python-certifi — commit 5cb238c(Remove emsign)
- certifi/python-certifi — commit 662df63(Restore unaffected emSign roots)
- certifi — PyPI
- pip 26.2.2 の NEWS(pypa/pip)
- pypa/pip — src/pip/_internal/cli/index_command.py
- psf/requests — src/requests/certs.py
- Information for Python users regarding eMudhra / emSign CA certificate security incident(discuss.python.org)
- GHSA-hq85-5cpj-mr62(astral-sh/uv)








