はじめに
2026年10月、インドの認証局 eMudhra が発行した中間CA証明書8件について、秘密鍵が公開証明書から計算できる状態だったことが明らかになりました。この問題には CVE-2026-111943 が採番されており、OkHttp の作者である Jesse Wilson 氏も同じ番号で対応方法を公開しています。
OkHttp では 2026年10月22日に 4.12.1 と 5.5.1 が公開され、該当する証明書をブロックリストで拒否するようになりました。
本記事では、次の順番で整理します(情報は2026年10月28日時点のものです)。
- 脆弱性の原因 - 何が起きたのか
- 危険性 - 攻撃されると何が起きるのか、Androidではどこまで守られているのか
- 対応1: OkHttp を 4.12.1 / 5.5.1 以上に更新する
- 対応2: 更新できない場合の回避策 -
hostnameVerifierにForbiddenCertificatesHostnameVerifierを追加する - 動作確認の方法
先に結論: これは OkHttp のコードのバグではありません。「OSが信頼している認証局の鍵が、実は誰でも復元できた」という問題で、OkHttp はライブラリ側で該当証明書を拒否することで対応しています。基本は OkHttp を更新するだけです。
1. 脆弱性の原因: 何が起きたのか
認証局の「秘密鍵」が、極端に小さな数値だった
HTTPS では、サーバー証明書が信頼できる認証局(CA)から発行されたものかどうかを確認します。今回問題になったのは、eMudhra の中間CA証明書8件(TLS用6件、コード署名用2件)です。これらはブラウザやOSが信頼するルート証明書につながっていました。
通常、秘密鍵は十分に大きな乱数でなければなりません。P-384 の秘密鍵なら、約384ビットのランダムな値です。ところが、この8件の秘密鍵は 4、56、66、115、155、156、230、237 といった、256未満の小さな整数でした(出典: Keytos)。
秘密鍵が小さな整数なら、公開されている証明書の公開鍵から、秘密鍵を総当たりで1秒足らずで復元できます。つまり、誰でも eMudhra の中間CAになりすませる状態でした。
なぜこんな鍵ができたのか
eMudhra の説明によると、2025年4月30日の鍵生成作業(キーセレモニー)に原因があります(出典: Help Net Security、Keytos)。
- 鍵のラップ/アンラップをテストする手順に含まれていたスクリプトに不具合があり、正規の強い鍵の隣に、弱い鍵のペアが別に生成された
- 2組の鍵のラベルが似ていたため、弱い鍵のほうで証明書が作られ、ルートが署名してしまった
- 2025年5月にも、署名の検証が通らない兆候があったが、原因を調べずに弱い鍵で再署名して済ませていた
つまり、暗号アルゴリズムが破られたのではなく、鍵の生成・運用の人為的ミスです。
発覚から OkHttp の修正までの流れ
| 日付 | 出来事 |
|---|---|
| 2025年4月30日 | 問題の鍵が生成される |
| 2026年10月17日 | 独立研究者の「Wayne」氏が発見し、Apple・Google・Microsoft・Mozilla・eMudhra に報告。Chrome と Firefox は当日中にブロック |
| 10月19日ごろ | Google が Google Play services 経由で Android 端末向けにブロックを配信 |
| 10月20日 | Mozilla と Google が公表。OkHttp の作者が ブログで回避策を公開 |
| 10月22日 | OkHttp 4.12.1 / 5.5.1 を公開 |
2. 危険性: 攻撃されると何が起きるのか
任意のドメインの「有効な」証明書を作れる
中間CAの秘密鍵を持つ者は、OSやブラウザが受け入れる任意のドメインの証明書を発行できます。つまり、api.example.com のような正規のサーバーになりすましたサーバーを、警告なしでクライアントに信頼させることができます。
アプリにとっての影響
通信経路上に攻撃者がいる場合(公衆Wi-Fiや悪意のあるネットワークなど)、**中間者攻撃(MITM)**が成立します。アプリの通信では、次のような被害が考えられます。
- API 通信に含まれる認証トークン、セッション情報、個人情報の盗聴
- 通信内容の改ざん(偽のAPIレスポンスの注入、アップデート情報のすり替えなど)
- 銀行、メール、ソフトウェア更新サーバーなどへのなりすまし
Thunderbird for Android のセキュリティ対応 Issue(#11789)でも、IMAP/POP3/SMTP の認証情報や OAuth トークンの窃取が想定される影響として挙げられています。
悪用されやすい状況だった
- 鍵が誰でも復元できるため、攻撃のハードルは非常に低い
- 公開後に、中間者攻撃ツールの mitmproxy に、この鍵で証明書を偽造するためのフラグ(
--emudhra)が追加された(出典: DEV Community、Thunderbird の Issue) - 公開後、Certificate Transparency(CT)ログには10万件を超える証明書が記録され、そのほとんどが
google.com向けだった。多くは研究や検証目的とみられる(出典: Keytos)
なお、実際に悪用されたかどうかは不明です。eMudhra は、8件のうち本番で使われたのは1件のみで、エンドユーザー向けの証明書は発行していないと説明しています。ただし、鍵が弱い状態のまま約17か月経過していたため、その間の状況は確認できていません。
Androidではどこまで守られているのか
| 環境 | 状況 |
|---|---|
| Google Play services のある Android 端末 | Google が Play services 経由でブロックを配信済み。大半の端末は受信済みで、すぐ反映したい場合は再起動で取得できる(出典: Google) |
| Play services のない端末(Fire OS、キオスク端末、一部のOEM端末、サイドロード配布、AOSP系のカスタムROMなど) | OSの信頼ストアが更新されるまで、該当CAを信頼したまま |
| JVM アプリ(サーバー、デスクトップ) | OpenJDK の cacerts は自動更新されない(出典: 研究者のまとめページ) |
| OkHttp 4.12.1 / 5.5.1 以上を使うアプリ | OSの状況に関係なく、ライブラリ側で拒否(出典: PostHog の通知) |
Play Store 経由のみで、Play services のある端末にだけ配布しているアプリであれば、OSが保護しているため緊急性は下がります。一方、配布先が不特定の場合(サイドロード、Fire OS、法人向けのキオスク端末など)や、JVM アプリでは、アプリ側の対応が必要です。
3. 対応1: OkHttp を 4.12.1 / 5.5.1 以上に更新する(推奨)
修正バージョン
| 系列 | 修正バージョン |
|---|---|
| 4.x | 4.12.1 以上 |
| 5.x | 5.5.1 以上(2026年10月22日公開) |
修正版では、問題の証明書がブロックリストで拒否されます。OkHttp の作者によると、これらのバージョン以降であれば、後述の回避策は不要です。changelog は 4.12.1 と 5.5.1 を参照してください。
更新方法
バージョンカタログを使っている場合の例です。
# gradle/libs.versions.toml
[versions]
okhttp = "5.5.1" # 4.x 系を使い続ける場合は "4.12.1"
[libraries]
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
// app/build.gradle.kts
dependencies {
implementation(libs.okhttp)
}
他のライブラリが古い OkHttp を引き込んでいないか確認する
直接の依存を更新しても、他のライブラリが古い OkHttp を要求している場合があります。実際に解決されているバージョンを確認してください。
./gradlew :app:dependencyInsight --dependency okhttp --configuration releaseRuntimeClasspath
古いバージョンが選ばれている場合は、constraints で下限をそろえられます。
dependencies {
constraints {
implementation("com.squareup.okhttp3:okhttp:5.5.1") {
because("CVE-2026-111943: eMudhra の中間CA 8件のブロックリストを含む")
}
}
}
PostHog も、自社 SDK が OkHttp の下限バージョン(4.12.1)を指定する新リリースを公開したうえで、利用者に対して自分のアプリで解決されているバージョンの確認を促しています。
更新しても守られないケース
- OkHttp を再パッケージして同梱しているライブラリ: 依存解決では更新されません。ライブラリの提供元が対応版を出しているか確認してください
-
OkHttp を使っていない通信:
HttpURLConnectionや別のHTTPクライアントによる通信は、OkHttp の更新では守られません。Sentry の Java SDK の Issue(#6335)でも、OkHttp 以外の独自クライアントの確認が必要な項目として挙がっています
5.x への更新で注意したい点
Hermes というプロジェクトの Issue(#287)では、OkHttp 5.x の Android 向けバリアント(okhttp-android)が、より新しい compileSdk を要求するため、compileSdk が古いプロジェクトでは依存解決に失敗した、と報告されています。これは個別プロジェクトの報告であり、私は確認していません。5.x に上げられない事情がある場合は、同じ脆弱性への対応がある 4.12.1 に上げる選択肢があります。
4. 対応2: 更新できない場合の回避策 - hostnameVerifier で拒否する
依存関係の都合などで、すぐに OkHttp を更新できないことがあります。その場合の暫定措置として、OkHttp の作者が ForbiddenCertificatesHostnameVerifier を Gist で公開しています。この方法は、サポートされているすべての OkHttp バージョンで使えると案内されています。
使い方
Gist のクラスをプロジェクトに取り込み、OkHttpClient に設定します。
val safeClient = client.newBuilder()
.hostnameVerifier(ForbiddenCertificatesHostnameVerifier())
.build()
Gist は更新される可能性があります(後述の通り、実際に一度書き換えられています)。本番に入れる場合は、必ずリンク先の最新版を取り込んでください。この記事の後半に載せているコードは、仕組みを理解するための自作の実装例です。
仕組み
この HostnameVerifier は、通常のホスト名の検証に加えて、接続先から受け取った証明書チェーンの中に、漏洩した8件の中間CAのいずれかが含まれていないかを調べます。含まれていれば接続を拒否します。
Gist の方式を取り入れた実装例(yschimke/compose-ai-tools の PR #6171)の説明によると、判定には各証明書の公開鍵(SPKI)の SHA-256 ハッシュを使い、8件分のハッシュ(32バイト×8)をリストとして持っています。チェーンのどの位置にあっても(葉証明書でも中間証明書でも)、一致すれば拒否されます。
中身を見てみる: 実装例
Gist には、初期版の ForbiddenCertificatesInterceptor が置かれていました(筆者が記事執筆時に取得できたのはこの版です)。中身は次の2つです。
- 禁止する証明書の SPKI の SHA-256 ハッシュ(8件) の
Set - ピア証明書のそれぞれについて
CertificatePinnerと同じ方法で SHA-256 を計算し、Setに含まれていればSSLPeerUnverifiedExceptionを投げる処理
この判定ロジックを HostnameVerifier に載せ替えたものが、次の実装例です。これは筆者が書いた実装例であり、OkHttp 作者の現行の Gist コードではありません。またコンパイル・実機での動作確認は行っていません。 実際に使う場合は、Gist の最新版を使ってください(作者版はコンストラクタに引数がなく、前掲のスニペットの形で使えます)。
import java.security.cert.X509Certificate
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSession
import okhttp3.CertificatePinner.Companion.sha256Hash
import okio.ByteString
import okio.ByteString.Companion.decodeHex
/**
* 通常のホスト名検証(delegate)に加えて、
* 証明書チェーンに禁止リストの証明書が含まれていたら拒否する。
*/
class ForbiddenCertificatesHostnameVerifier(
private val delegate: HostnameVerifier,
private val forbiddenSpkiSha256s: Set<ByteString> = CVE_2026_111943,
) : HostnameVerifier {
override fun verify(hostname: String, session: SSLSession): Boolean {
// 1. まず通常のホスト名検証。失敗ならそのまま拒否する
if (!delegate.verify(hostname, session)) return false
// 2. チェーン内のどの証明書(葉・中間)でも、禁止リストに一致したら拒否する
val certificates = try {
session.peerCertificates
} catch (e: Exception) {
return false
}
return certificates.none { certificate ->
val spkiSha256 = (certificate as X509Certificate).sha256Hash()
spkiSha256 in forbiddenSpkiSha256s
}
}
companion object {
// 出典: Mozilla dev-security-policy の投稿(Gist 内のコメントで参照されているもの)
val CVE_2026_111943: Set<ByteString> = setOf(
"43bffa19d6ef651451f6841e019931e96f6f2eaeff28ab4b6f1ce4576de2717b",
"49dd353dc2b919a3770645117d0e60c16115e7d1bc259eefe734b00ea434fe5f",
"5c0660a2b164910d8ff589c18e14552e9e0ec237dcefe2cb736d41a4811f81a0",
"63ecefee431d49523bc1136c4e72d0206a477086caf606cd5cf025686c109cf8",
"92c063d67e8f14db71d288e11266ffdaf69cbf115f7bab14f3bc2f68d25e0e30",
"e0254c7fcdc265e2f0f8a428dabb75ab4ae039b4872d62f5ee57f0877d5a8a41",
"ebed6475c2c2d80fcb199f3fe8dd6e6b3ce60b77eb15d4e42c3dec0c6f5b5105",
"ec4ffa1ad0ac88081314b7aaffef6a91f97cd57291bb5ba686c5415f5eb4f6b6",
).map { it.decodeHex() }.toSet()
}
}
実装例の使い方は、既存の検証を delegate に渡します。client.hostnameVerifier は OkHttp が標準で使っているホスト名検証なので、それを渡せば標準の検証が維持されます。
val safeClient = client.newBuilder()
.hostnameVerifier(ForbiddenCertificatesHostnameVerifier(client.hostnameVerifier))
.build()
ポイントは次の3つです。
-
delegateを先に呼ぶ: 標準のホスト名検証を外さないため。HttpsURLConnection.getDefaultHostnameVerifier()をdelegateに使うのは避けてください。JVM の既定実装は常にfalseを返すため、すべての接続が失敗します - チェーン全体を調べる: 今回禁止されているのは中間CAなので、葉証明書だけを調べても検出できません
- SPKI のハッシュで比較する: 証明書全体ではなく公開鍵情報(SPKI)のハッシュなので、同じ鍵で別の証明書が発行されても検出できます
ハッシュ値について: 上の8件は、Gist の取得結果をそのまま写したものです。セキュリティ用の値なので、使う前に、Gist 内のコメントで参照されている Mozilla dev-security-policy の投稿 の値と必ず突き合わせてください(筆者は投稿本文を取得できていません)。
Interceptor ではなく HostnameVerifier を使う理由
この回避策は、当初は Interceptor として公開されていました。しかし、Suresh 氏の指摘を受けて、2026年10月21日に HostnameVerifier に差し替えられています。
-
Interceptorが証明書を受け取るタイミングは遅く、秘密情報がすでに攻撃者に送信された後になってしまう -
HostnameVerifierは接続の確立時に呼ばれるため、この問題を避けられる
初期版(Interceptor 版)を取り込んでいる場合は、必ず最新の HostnameVerifier 版に差し替えてください。
注意点
① 通常のホスト名検証が維持されていることを確認する
hostnameVerifier を差し替えると、OkHttp 標準のホスト名検証が置き換わります。取り込んだ実装が標準の検証を呼び出した上で追加チェックをしていることを、必ず確認してください。ここを誤ると、ホスト名の検証が無効になる別の脆弱性を作り込みます。上記の PR では、「ホスト名検証が引き続き有効であること」をテストで確認しています。
② すべての OkHttpClient に適用する
hostnameVerifier は OkHttpClient ごとの設定です。Retrofit、画像読み込みライブラリ、各種SDKの内部で別に作られたクライアントには適用されません。クライアントの生成箇所が散らばっていると、適用漏れが起きやすくなります。
生成箇所が1か所に集約されていれば、そこに追加するだけで済みます。
object SecureHttpClientFactory {
fun create(): OkHttpClient = OkHttpClient.Builder()
// TODO: OkHttp を 4.12.1 / 5.5.1 以上に更新したら削除する
.hostnameVerifier(ForbiddenCertificatesHostnameVerifier())
.build()
}
③ 更新後は外す
OkHttp を修正版に更新したら、この回避策は不要です。Thunderbird for Android の Issue では、5.5.1 の SPKI チェックは、カスタムの hostnameVerifier の有無にかかわらず、ホスト名検証の後に実行される、と整理されています(OkHttp の公式文書ではなく、同プロジェクトの調査による記述です)。上の例のように、削除し忘れないよう TODO を残しておくのがおすすめです。
5. 動作確認の方法
研究者グループが、確認用のテストホストを公開しています(まとめページ)。
| ホスト名 | 接続できた場合の意味 |
|---|---|
dv-g3b-emudhra.we-have-a-problem.com |
侵害された中間CAを信頼している(脆弱) |
dv-g3b-noct-emudhra.we-have-a-problem.com |
侵害された中間CAを信頼し、かつ CT を強制していない |
OkHttp で接続を試す最小の例です(メインスレッド以外で実行してください)。
fun probe(client: OkHttpClient, host: String): String = try {
val request = Request.Builder().url("https://$host/").build()
client.newCall(request).execute().use { "接続成功(脆弱): HTTP ${it.code}" }
} catch (e: IOException) {
"接続失敗(保護されている可能性あり): ${e.javaClass.simpleName}"
}
確認するときに、2点注意してください。
- 接続失敗は、ネットワークエラーでも起こります。「失敗 = 安全」と即断せず、証明書に関するエラーかどうか、例外の内容を確認してください
- Play services のある端末では、OS側のブロックで失敗している可能性があります。OkHttp 側の対策が効いているかを確かめるには、Play services のない環境が必要です。Thunderbird の Issue でも、Google API なしの AOSP エミュレータで修正前後の挙動を確認する方針が示されています
おまけ: 開発用 Mac での対策
OkHttp とは別に、開発に使っている Mac 自身の状態も気になるところです。Apple の公式ページ(About the compromised eMudhra intermediate CAs)と、Apple Developer Forums のスレッド(#852912)の内容を整理します。
Safari やアプリは自動でブロックされる
Apple は、ソフトウェアアップデートではなく、証明書設定データの自動更新でブロックしています。2026年10月19日にブロックが始まり、10月23日には emSign ECC Root CA - G3 も追加されました。Safari、Mail、Apple のネットワーク/セキュリティフレームワークを使うアプリは、何もしなくても保護されます。
なお、Apple Community の日本語スレッド(eMudhra中間CAの秘密鍵漏洩に関するSafariの証明書検証について)では、10月22日〜23日ごろ、端末やブラウザによってテストサイトの結果が緑になったり赤のままだったりと、反映のばらつきが報告されていました。反映までに数日かかることがある、という前提で確認してください。
ターミナルのコマンドは別扱い
macOS に付属する、または Xcode Command Line Tools に含まれる curl、git、python3、ruby、perl、openssl などは、証明書を /etc/ssl/cert.pem で検証します。このファイルには Apple のブロックや失効確認が適用されません。Apple Developer Forums では、macOS 27.0.1 上で /usr/bin/curl がテストホストに接続できてしまった、という報告があります。
自分の Mac で確認するには、次のようにします(SSL_CERT_FILE と CURL_CA_BUNDLE が設定されていない状態で実行してください)。
# 接続できた(終了コード 0)なら、侵害された中間CAを信頼している
/usr/bin/curl -sS -o /dev/null -w '%{exitcode}\n' https://dv-g3b-emudhra.we-have-a-problem.com/
# 該当するルート証明書が含まれているかを確認する
grep -E 'emSign ECC Root CA - G3|AAA Certificate Services' /etc/ssl/cert.pem
対策の選択肢
-
何もしない(Apple の案内の既定): Apple は「ほとんどのユーザーは
/etc/ssl/cert.pemを編集する必要はない」としており、将来の macOS アップデートでこのファイルを変更する、と案内しています -
早く止めたい場合: ターミナルを使う人や管理者向けに、Apple が
/etc/ssl/cert.pemから該当ルート(emSign ECC Root CA - G3、必要ならAAA Certificate Servicesも)を取り除く手順を公開しています。バックアップ、削除、opensslでの確認、復元の順です。コマンドは Apple のページにある公式のものを使ってください(この記事には転載しません)- macOS のアップデートでファイルが元に戻ることがあるため、更新後に再確認が必要です
- 取り除くと、このファイルだけを頼りにしているツールが、一部のサイトの証明書を検証できなくなる可能性があります
- 管理者権限、またはデバイス管理(MDM)が必要です
まとめて実行するコマンド例
Apple の手順を、まとめて実行できる形にした例です。これは筆者の実装例であり、Apple 公式のコマンドではありません。また macOS の実機では検証していません。 公式の手順は、前述の Apple のページを正としてください。実行は自己責任でお願いします。
① 先に、見出しの形式が一致するかを確認する
このコマンドは、/etc/ssl/cert.pem の見出し行(=== /C=... の形式)と完全一致する行を探して、その証明書を取り除きます。見出しが少しでも違うと、何も消えず、エラーも出ません。そのため、先に実機の見出しを確認します。
grep -E '^(===|###) ' /etc/ssl/cert.pem | grep -E 'emSign ECC Root CA - G3|AAA Certificate Services'
次の2行が表示されれば、コマンドの s= の値と一致します。違う場合は、表示された行に合わせて書き換えてください。
=== /C=IN/OU=emSign PKI/O=eMudhra Technologies Limited/CN=emSign ECC Root CA - G3
=== /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services
② バックアップ、削除、確認を1回で実行する
次の全体を、ターミナルにひとまとめで貼り付けて実行します(バックアップ、2件の削除、残りの確認までを行います)。AAA Certificate Services も外すと、Sectigo のクロス署名経由の証明書も受け入れなくなります。外さない場合は、for の2行目を削除してください。
( set -u
f=/etc/ssl/cert.pem
# バックアップ(すでにある場合は上書きしない)
[ -e "$f.orig" ] || sudo cp -p "$f" "$f.orig" || exit 1
for s in \
'=== /C=IN/OU=emSign PKI/O=eMudhra Technologies Limited/CN=emSign ECC Root CA - G3' \
'=== /C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services'
do
t=$(mktemp) || exit 1
awk -v s="$s" '/^(===|###) /{skip=0} $0==s{skip=1} !skip' "$f" > "$t" \
&& [ -s "$t" ] \
&& sudo install -m 0644 -o root -g wheel "$t" "$f"
rm -f "$t"
done
# 確認: 何も表示されなければ、削除できている
echo "--- 残っている該当ルート ---"
grep -E 'emSign ECC Root CA - G3|AAA Certificate Services' "$f" || echo "なし(削除できています)"
)
[ -s "$t" ] で、出力が空のときは上書きしないようにしています。削除できていれば なし(削除できています) と表示され、見出しが一致しなかった場合は、その下にルート名が表示されます(その場合は①に戻ってください)。
③ 接続できなくなったことを確認する
# 接続できなくなっていることを確認する(終了コードが 0 以外になる)
/usr/bin/curl -sS -o /dev/null -w '%{exitcode}\n' https://dv-g3b-emudhra.we-have-a-problem.com/
④ 問題が出たら元に戻す
sudo cp -p /etc/ssl/cert.pem.orig /etc/ssl/cert.pem
macOS のアップデートでファイルが元に戻ることがあるため、更新後は③を再実行してください。元に戻った場合は、古いバックアップを消してから②をやり直します。
開発者として押さえておきたい点
- Apple の保護は Apple の API を使う通信(
URLSessionなど)に効きます。Apple の開発者サポートも、Apple の API を使う場合はURLSessionや Network framework を推奨しています - OkHttp など、自前で信頼ストアを扱うライブラリには Apple のブロックは効きません。macOS 上の JVM アプリ(Android Studio や Gradle の実行など)がどの信頼ストアを使っているかは、この記事では確認していません。JVM 側は、本編のとおり OkHttp を更新するか、JDK を更新してください
- Apple の開発者サポートは、
/etc/ssl/cert.pemの更新予定について、フォーラム上では回答していません。更新時期は公表されていない、と考えておくのが安全です
補足: 証明書ピンニングを使っていた場合
OkHttp の CertificatePinner で自社サーバーの公開鍵にピンニングしている接続は、攻撃者の偽の証明書の公開鍵がピンと一致しないため、この種の攻撃に対して有効です(ピンニングしているホストに限ります)。ただし、ピンニングは証明書のローテーションなどの運用負荷が大きいため、全面的な採用はおすすめしません。
今回のように「信頼している認証局そのものが危殆化する」ケースに備える手段として、ライブラリのブロックリスト、ピンニング、OSの信頼ストアの更新がそれぞれ別の層で効くことは、覚えておく価値があります。
まとめ
- 原因は、eMudhra の中間CA 8件の秘密鍵が極端に小さな数値で、誰でも復元できたこと。OkHttp のバグではなく、信頼している認証局側の問題
- 危険性は、任意のドメインの有効な証明書を偽造され、中間者攻撃でトークンや個人情報を盗まれること。Play services のある Android 端末は Google が保護しているが、Play services のない端末や JVM アプリは、アプリ側の対応が必要
- 対応は OkHttp を 4.12.1(4.x系)/ 5.5.1(5.x系)以上に更新する。他のライブラリが古い OkHttp を引き込んでいないか、
dependencyInsightで確認する - 更新できない場合は、
hostnameVerifierにForbiddenCertificatesHostnameVerifierを追加する暫定措置がある。Interceptor 版は不十分だったため、最新の HostnameVerifier 版を使い、標準のホスト名検証が維持されていることを確認し、すべてのOkHttpClientに適用する - 更新後は回避策を外し、テストホストで動作を確認する
参考
- Mitigating CVE-2026-111943 in OkHttp - Jesse Wilson
- ForbiddenCertificatesHostnameVerifier (Gist)
- OkHttp changelog: 5.5.1 / 4.12.1
- Protecting Chrome and Android Users from Compromised eMudhra Intermediate CA Certificates - Google
- eMudhra security blunder left trusted CA signing keys exposed to anyone - Help Net Security
- Eight eMudhra CA Keys Compromised - The Hacker News
- eMudhra CA Key Compromise Explained - Keytos
- eMudhra Intermediate CA Compromise(研究者のまとめページ)
- OkHttp eMudhra CA certificate notice for JVM SDK users - PostHog
- Thunderbird for Android の対応 Issue #11789
- About the compromised eMudhra intermediate CAs - Apple
- macOS /etc/ssl/cert.pem still trusts the eMudhra roots - Apple Developer Forums
- eMudhra中間CAの秘密鍵漏洩に関するSafariの証明書検証について - Apple Community