Authlib に、CVSS 9.1(Critical) の署名検証バイパスの脆弱性 CVE-2026-96760(GHSA-6v38-4h7w-rj9h)が公表されました。影響は 1.8.0 以下、修正は 1.9.0。さらに同日公開の 1.9.1 が別の署名偽造も塞ぐため、上げる先は 1.9.1 以上です。Authlib は Python で OAuth・OIDC・JWT を扱う広く使われたライブラリで、直接入れていなくても認証基盤やフレームワーク経由で入っていることが多いものです。依存ライブラリ1つの欠陥が認証そのものを破るという構図の全体像は、サプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説に整理しています。認証ライブラリの不備が乗っ取りに直結した例はBetter Auth の SCIM 実装で起きたアカウント乗っ取りに、盗まれたトークンを多層で防ぐ考え方はトークン窃取を多層で防ぐ設計にあります。

WHAT HAPPENED時系列

Authlib の JWS 署名検証バイパス(CVE-2026-96760)が公になるまで

  1. 〜1.8.0

    deserialize_json() が無検証で「検証済み」を返す状態

    is_valid が True で初期化され、False になるのはループの中だけ。signatures が空配列だとループが回らず、鍵が無くても payload を検証済みとして返していた

  2. 1.9.0 (10/14)

    空・欠落の signatures を拒否する修正

    deserialize_json() が空/欠落の signatures を BadSignatureError で弾くようになった。これが CVE-2026-96760 の修正

  3. 1.9.1 (10/14)

    別の署名偽造も修正

    空の HMAC 鍵を ValueError で拒否。HS256/HS384/HS512 を誰でも偽造できた欠陥(GHSA-8m4g-j4wp-wgcg)を同時に塞いだ

  4. 10/27

    GitHub Advisory DB に掲載・レビュー済みに

    CVE-2026-96760(GHSA-6v38-4h7w-rj9h)として公開。CVSS 9.1 Critical・CWE-347(署名検証の不備)

出典: GitHub Advisory GHSA-6v38-4h7w-rj9h、Authlib 公式 changelog(1.9.0/1.9.1)、GHSA-8m4g-j4wp-wgcg(2026-10-28 確認)

30秒でわかる

  • ・何が起きたか:Authlib の JWS JSON 署名検証バイパス(CVE-2026-96760・CVSS 9.1)。signatures が空だと無検証で「検証済み」を返していた
  • ・原因:is_valid が True で初期化され、False になるのは検証ループの中だけ。空配列だとループが回らない
  • ・影響:1.8.0 以下。このメソッドに外部由来の JWS JSON を渡して結果を信頼しているアプリが対象
  • ・対応:1.9.1 以上へ更新(1.9.0 で今回の修正、1.9.1 で別の署名偽造も修正)して再デプロイ

まず手元が対象かを確かめます。ターミナルで次を実行し、authlib の版が 1.9.1 未満なら上げます。

pip show authlib

いつ、何が起きたのか

発端は、Authlib の JsonWebSignature.deserialize_json()(JWS の JSON Serialization を扱うメソッド)が、署名を検証せずに payload を「検証済み」として返す状態だったことです。GitHub Advisory の原因説明によれば、検証結果を表す is_valid が True で初期化され、False になるのは署名を1つずつ確かめるループの中だけでした。そのため signatures が空配列だとループが一度も回らず、フラグが True のまま payload が返っていました。鍵を渡していても素通りします。

JWS(JSON Web Signature) は、データに署名を付けて改ざんを検知する仕組みで、JWT の土台です。表現は2種類あり、ドットでつなぐ Compact(xxx.yyy.zzz)と、署名を配列で持つ JSON Serialization です。今回の欠陥は後者の処理に固有で、signatures の配列が空(または欠落)のときに検証を素通りしていました。

主な時点は次の通りです。1.9.0・1.9.1 はいずれも 2026年10月14日の公開で、GitHub Advisory Database への掲載(レビュー済み)が 10月27日です。

・1.8.0 以下:deserialize_json() が空の signatures を無検証で通す(CVE-2026-96760 の対象)
・1.9.0:空・欠落の signatures を BadSignatureError で拒否する修正
・1.9.1:空の HMAC 鍵を ValueError で拒否。HS256/HS384/HS512 を誰でも偽造できた別勧告 GHSA-8m4g-j4wp-wgcg も修正
・10/27:GitHub Advisory DB に CVE-2026-96760(CVSS 9.1・Critical・CWE-347)として掲載

なぜ空の署名配列が「検証済み」になったのか

HTTPS やトークンの正しさは、「署名を鍵で検証して、通ったものだけ信頼する」という前提で成り立ちます。今回はその検証が、ある入力の形のときだけ実行されないまま成功扱いになっていました。

BEFORE AND AFTER修正前と修正後

空の署名配列が、なぜ「検証済み」になっていたか

修正前(〜1.8.0)

修正後(1.9.0〜)

修正前(〜1.8.0): signatures が空配列 [] の JWS JSON を受け取る

修正後(1.9.0〜): ループの前に signatures の有無を検査する

修正前(〜1.8.0): is_valid は True のまま(ループが一度も回らない)

修正後(1.9.0〜): 空・欠落なら is_valid を False にする

修正前(〜1.8.0): 鍵が無くても payload を「検証済み」として返す

修正後(1.9.0〜): 検証できなければ必ず BadSignatureError を投げる

出典: GHSA-6v38-4h7w-rj9h の原因説明と、Authlib の authlib/jose/rfc7515/jws.py(1.9.1)の実装(2026-10-28 確認)

JSON Serialization は、1つのデータに複数の署名を付けられる形式で、「同じトークンを複数の鍵・複数の当事者が署名する」といった用途で使われます。Compact 形式しか扱わないアプリなら今回の経路は通りませんが、OIDC のバックチャネルや独自のトークン受け渡しでこの形式を受けている場合は対象になり得ます。自分のコードがどちらの形式を、どこで受けているかを把握しておくことが、影響の切り分けの第一歩です。

修正は、ループに入る前に signatures の有無を検査し、空や欠落なら検証失敗として BadSignatureError を投げる、というものです。「何もなかったから成功」を「何もないのは失敗」に直したわけです。ここでは攻撃に使える具体的な手順(PoC)は示しません。要点は、外部から来た JWS JSON を deserialize_json() に渡し、その戻り値を信頼しているコードが危ないということです。この構図は、署名そのものの検証が抜けていた点で、鍵の管理ミスや漏洩とは別のクラスの欠陥です。

何を、どの版へ上げるか

対応は版を上げるだけで、設定変更は要りません。上げる先は 1.9.1 以上です。

版 状態
1.8.0 以下 影響あり(CVE-2026-96760・JWS JSON の署名検証バイパス)
1.9.0 今回の JWS JSON バイパスは修正。ただし空 HMAC 鍵の署名偽造(別勧告)は未修正
1.9.1 以上 両方を修正。ここへ上げる

WHAT TO DO対応の確認項目

いますぐ 1.9.1 以上へ上げ、使い方を見直す

  1. 1.authlib を 1.9.1 以上へ上げる

    1.9.0 で今回の JWS JSON バイパス、1.9.1 で空 HMAC 鍵の署名偽造を修正。両方を塞ぐ 1.9.1 以上にする

  2. 2.間接依存も見る

    自分が直接入れていなくても、OAuth/OIDC サーバやフレームワーク経由で入っていることが多い。依存ツリー全体を確認する

  3. 3.deserialize_json() の戻り値を信用しすぎない

    鍵を必ず渡し、戻り値を無条件に「検証済み」と扱わない。鍵なし呼び出しは仕様上そもそも検証しない

  4. 4.トークンを検証するサーバは再デプロイ

    更新後に再ビルド・再デプロイして初めて反映される。古いプロセスが動き続けていないか確認する

出典: Authlib 公式 changelog(1.9.0/1.9.1)、GHSA-6v38-4h7w-rj9h(2026-10-28 確認)

1.9.0 と 1.9.1 は同じ 2026年10月14日に公開されています。1.9.0 は今回の deserialize_json() の JWS JSON バイパス(CVE-2026-96760)を、1.9.1 は空の HMAC 鍵で HS256/HS384/HS512 を偽造できた別の欠陥(GHSA-8m4g-j4wp-wgcg)を直しています。両方を塞ぐため、上げる先は 1.9.1 以上にしてください。

自分の環境を確認する

手元のプロジェクトに Authlib が入っているか、版はいくつかを確かめます。いずれも「侵害されたか」ではなく、修正の入った版を使っているかの確認です。

pip show authlib
python -c "import authlib; print(authlib.__version__)"

版が 1.9.1 未満なら上げます。

pip install -U 'authlib>=1.9.1'

直接の依存に見当たらなくても、認証サーバやフレームワークの間接依存として入っていることがあります。依存ツリー全体と既知の脆弱性を pip-audit で確かめます。Poetry なら poetry show authlib で版を見て poetry add 'authlib@^1.9.1'、uv なら uv pip show authlib と uv lock --upgrade-package authlib です。いずれも requirements.txt や pyproject.toml、ロックファイル(poetry.lock・uv.lock など)の下限を 1.9.1 以上へ上げ、ロックを取り直してから再デプロイします。

これらは「いま攻撃を受けているか」を調べるコマンドではありません。問題は特定メソッドの検証ロジックなので、ファイルの有無では判定できません。確認できるのは「修正の入った版か」だけです。上げ終えたら、トークンを検証するサーバを再デプロイして、古いプロセスが残っていないかを必ず確認します。

影響範囲——誰が危ないか

危ないのは、外部から受け取った JWS JSON Serialization を deserialize_json() に渡し、戻り値を「検証済み」として信頼しているコードです。トークンや署名付きメッセージを受ける認証・認可の入口がこれに当たります。Authlib は Flask・Django・FastAPI 向けの OAuth 2.0/OpenID Connect プロバイダ実装や、requests・httpx の OAuth クライアント、JWT/JOSE のユーティリティとして使われます。自前で認可サーバやトークン検証を書いている場合は、どの形式の JWS をどこで受けているかを一度洗い出すとよいです。逆に、Compact 形式(xxx.yyy.zzz)だけを扱う一般的な JWT 検証は、今回の deserialize_json() の経路を通らないため直接の対象ではありません。ただし版が古ければ、同じライブラリに同居する 1.9.1 の署名偽造(HMAC 鍵まわり)の影響範囲に入るので、どちらにせよ 1.9.1 以上へ上げるのが確実です。

CVSS 9.1 が高いのは、評価ベクトル(AV:N/AC:L/PR:N/UI:N)が示すとおり、ネットワーク越しに・特別な権限なく・利用者の操作も介さず、攻撃者が用意した入力を送るだけで成立しうるからです。機密性と完全性への影響がいずれも高く、認証を素通りさせられる点が重く見られています。現時点で、この欠陥を使った実際の攻撃は広くは報告されていません。とはいえ、気づかないまま「検証したつもり」で通してしまう種類の欠陥で、派手な兆候は出ません。版を上げ切ることが唯一の確実な対策です。便乗した偽の注意喚起に注意し、更新は PyPI と公式のリポジトリから行ってください。

参照ソース