本文へ移動
技術を、自社の仕事に。
判断と実行を助けるメディア

記事を検索

certifiのemSign削除 requestsとpipの束を確認

目次 · 6項目

社内の基幹システムから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 - G3 root 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日)121G1・G3・C1・C3 の4つ
2026.10.18(10月18日 16:21)117なし(「Remove emsign」で4つとも削除)
2026.10.19(10月20日 02:24)120G1・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点だけでした。

certifiの版ごとのemSignのルート証明書の扱いを示す図。2026.7.22にはemSign Root CA - G1、emSign ECC Root CA - G3、emSign Root CA - C1、emSign ECC Root CA - C3の4つがある。2026.10.18では4つとも削除。2026.10.19ではG1、C1、C3が戻り、侵害された中間CAにつながるG3だけが削除されたまま。移行先は2026.10.19以上

2026.10.18 は、影響のない3つのルートも消していました。編集部の整理では、2026.10.18 に上げた環境で、この3つのルートにつながる証明書を使う接続先がある場合は、検証に失敗する可能性があります。今から上げるなら 2026.10.18 で止めず、2026.10.19 以上にします。

どのライブラリがどの束を信頼しているか

更新の対象を見極めるには、使っているライブラリが certifi の束を読むのか、OSの証明書ストアを読むのかを分けて考えます。ソースで確かめた範囲は次のとおりです。

使い方信頼する証明書確かめた根拠
requests で verify を指定しないcertifi の cacert.pemrequests/certs.py が from certifi import where、adapters.py が DEFAULT_CA_BUNDLE_PATH を使う
pip(Python 3.10 以上)OS のストア + pip に同梱した certifiindex_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か所に残り得ます。

  1. ロックファイルを検索する。 requirements*.txt、poetry.lock、uv.lock、Pipfile.lock で certifi の版を確かめます。直接の依存でなくても、requests などの依存として入っています。
  2. 動いている環境で版を見る。 イメージやサーバーで python -c "import certifi; print(certifi.__version__, certifi.where())" を実行し、2026.10.19 以上かを確かめます。仮想環境が複数あるサーバーでは、アプリが実際に使う Python で実行します。
  3. 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 で確かめます。
  4. イメージを作り直す。 アドバイザリは「rebuild container images that vendor certifi」と求めています。ロックファイルで certifi を固定している場合は、版を上げてからビルドします。ベースイメージのキャッシュで古い層が使われていないかも確かめます。
  5. 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・自動化のご相談からお問い合わせください。

参考資料

この記事を共有XFacebook
鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

この記事のテーマを、自社の次の一歩へ

自社での進め方を、具体的に。

つくりたい仕組み、既存システム、運用の条件を整理し、実現に向けた次の一歩を考えます。

  • 実現したい仕組み
  • 既存環境との接続
  • 運用の条件
開発・運用の構想を相談する

構想段階からご相談いただけます。この記事の情報を相談フォームに引き継ぎます。

最新記事をメールで受け取る