In this article
CVE-2026-29000:公開鍵によってpac4j-jwtの認証が突破される仕組み
Javaセキュリティライブラリpac4j-jwtに重大な認証バイパス脆弱性があり、攻撃者はサーバーのRSA公開鍵だけで管理者を含む任意のユーザーになりすますことができます。CVE-2026-29000として追跡されているこの脆弱性のCVSSスコアは10.0で、org.pac4j:pac4j-jwtの4.5.9、5.7.9、6.3.3より前のすべてのバージョンに影響します。
この脆弱性は簡単に悪用できます。公開された概念実証(PoC)があり、修正済みバージョンもすでに提供されています。JavaアプリケーションでJWT認証にpac4jを使用している場合は、ぜひ読み進めてください。
概要
詳細 | 値 |
|---|---|
CVE | |
CVSS 3.1 | 10.0 クリティカル ( |
CVSS 4.0 | 10.0 クリティカル ( |
CWE | CWE-347:暗号署名の不適切な検証 |
Mavenアーティファクト |
|
影響を受けるバージョン | 4.x \< 4.5.9, 5.0.0-RC1 \< 5.7.9, 6.0.4.1 \< 6.3.3 |
修正済み | 4.5.9, 5.7.9, 6.3.3 |
悪用状況 | 公開PoCあり |
発見者 | CodeAnt AI Security Research |
pac4jとは?
pac4jは、OAuth、SAML、CAS、OpenID Connect、JWTなど、複数のプロトコルに対応した認証と認可を提供するJava向けセキュリティフレームワークです。pac4j-jwtモジュールは、JwtAuthenticatorクラスを通じてJSON Web Tokenの生成と検証を担います。
pac4jは、Spring Security、JEE、Play、Vert.xなどのフレームワークで、基盤となる認証エンジンとして利用できます。また、大学や政府機関で広く使われるCAS(中央認証サービス)環境にも広く導入されています。JWTを使ったpac4jベースの認証を利用しているアプリケーションは、影響を受ける可能性があります。
脆弱性の仕組み
この脆弱性を理解するには、JWTの2つの種類の違いを知っておく必要があります。
JWS(JSON Web Signature):署名付きトークンです。署名によって、トークンが改ざんされておらず、署名鍵を持つ者が作成したことを証明します。
JWE(JSON Web Encryption):暗号化されたトークンです。暗号化によって、転送中にトークンの内容を読み取られるのを防ぎます。JWEの中にJWSを含めることで、機密性と完全性の両方を確保できます。
pac4jのJwtAuthenticatorが暗号化されたJWT(JWE)を受け取ると、次の処理を行います。
外側のJWEエンベロープを復号する
内側のペイロードを解析する
内側のトークンの署名を検証する
脆弱性があるのはステップ3です。JWEを復号した後、ライブラリは内側のペイロードから署名付きトークンを取り出して検証するため、com.nimbusds:nimbus-jose-jwtのtoSignedJWT()関数を呼び出します。内側のトークンがalg: none(署名なし)を示すPlainJWTの場合、このメソッドはnullを返します。
脆弱なコードでは、このnull値によって署名検証の処理全体がスキップされていました。実質的に、ライブラリは「検証する署名が見つからないので、そのまま処理を続けよう」と判断していました。
脆弱なロジックを簡略化すると、次のようになります。
// (after JWE decryption succeeds above)
SignedJWT signedJWT = encryptedJWT.getPayload().toSignedJWT();
// If inner token is PlainJWT, signedJWT is null
if (signedJWT != null) {
jwt = signedJWT;
}
// Signature verification only runs if signedJWT is not null
if (signedJWT != null && !signatureConfigurations.isEmpty()) {
// Verify signature... but this block is NEVER entered
// for a PlainJWT wrapped in JWE
}
// Claims are extracted regardless — attacker is now "authenticated"
createJwtProfile(ctx, credentials, jwt);修正では、暗号化されたエンベロープ内に署名なしトークンが見つかった場合に、明示的に拒否する処理が追加されました。
if (!signatureConfigurations.isEmpty()) {
if (signedJWT == null) {
throw new CredentialsException(
"A non-signed JWT cannot be accepted...");
}
// Proceed with normal signature verification
}実際の攻撃方法
攻撃者に必要なのは、サーバーのRSA公開鍵だけです。公開鍵はその名のとおり公開されており、JWKSエンドポイントや証明書、設定ファイルなどに含まれていることがよくあります。
攻撃の手順:
サーバーのRSA公開鍵を入手する(JWKSエンドポイント、TLS証明書、その他の公開情報から)
任意のクレームを含むPlainJWTを作成する:
{
"sub": "admin",
"role": "ADMIN",
"exp": 1772611200
}サーバーのRSA公開鍵で暗号化したJWEでラップする
偽造したトークンをアプリケーションに送信する
アプリケーションはJWEを復号します(公開鍵による暗号化は有効です)が、検証する署名が見つからないため検証をスキップし、偽造されたクレームを正規のものとして受け入れます
攻撃者は秘密鍵や共有秘密、認証情報を用意する必要はありません。システムを守るはずの公開鍵だけで攻撃が成立します。
影響を受ける対象
次の条件に当てはまる場合、影響を受けている可能性があります。
RSA暗号化を使用している。この場合、プロジェクト内のRSAEncryptionConfigurationで確認できます。
JWT認証に
org.pac4j:pac4j-jwtを使用している両方の設定(暗号化(JWE)と署名検証(JWS))を
JwtAuthenticatorで使用している4.5.9、5.7.9、6.3.3より前のバージョンを使用している
暗号化を使わず、署名付きJWT(JWS)のみを使用するアプリケーションは、PlainJWTをJWE内に入れる手法に暗号化設定が必要なため、この特定の攻撃に対して脆弱ではありません。
Snykで確認する
Snyk CLIを使って、プロジェクトが影響を受けているか確認できます。
# For Maven projects
snyk test --maven
# For Gradle projects
snyk test --gradleSnykではこの脆弱性をSNYK-JAVA-ORGPAC4J-15428218として追跡しています。脆弱なパッケージが依存関係ツリーに含まれている場合、Snykが検出してアップグレード方法を提示します。
Mavenを使用している場合は、Snyk Maven pluginをビルドプロセスに組み込むことで、CLIを別途実行せずにこの脆弱性を検出できます。Gradleプロジェクトでは、Snyk Gradle pluginで同様の統合スキャンを利用できます。
依存関係を直接検索することもできます。
# Check if pac4j-jwt is in your dependency tree
mvn dependency:tree | grep pac4j-jwt
# Or with Gradle
gradle dependencies | grep pac4j-jwt修正方法
org.pac4j:pac4j-jwtを、メジャーバージョン系列に対応する修正済みバージョンにアップグレードしてください。
現在のバージョン | アップグレード先 |
|---|---|
4.x | 4.5.9以降 |
5.x | 5.7.9以降 |
6.x | 6.3.3以降 |
Mavenの場合は、pom.xmlを更新します。
<!-- For pac4j 6.x -->
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-jwt</artifactId>
<version>6.3.3</version>
</dependency>Gradleの場合:
// For pac4j 6.x
implementation 'org.pac4j:pac4j-jwt:6.3.3'すぐにアップグレードできない場合
アップグレードを強く推奨しますが、次の対策でリスクを軽減できます。
JWTの設定を確認する:アプリケーションが暗号化なしで署名付きJWT(JWS)のみを使用している場合、この特定の攻撃経路に対して脆弱ではありません。ただし、アップグレードが最も安全な対応策です。
JWT処理コードを監査する:アプリケーション層で署名付きトークンを明示的に必須とし、署名なしトークンを拒否するようにしてください。
脆弱なバージョンのpac4jには、設定レベルで利用できる回避策はありません。
pac4j以外にも重要な理由
この脆弱性は、JWT実装における広範な問題の典型例です。セキュリティ特性(署名)がない場合、それを拒否せずにスキップしてしまうという根本的な問題は、長年にわたりさまざまなプログラミング言語のJWTライブラリで発生しています。
教訓は明確です。暗号学的な検証は必須にし、任意にしてはなりません。署名付きトークンを想定しているときに署名なしトークンを受け取った場合、安全な対応は拒否することだけです。何も通知せず処理を続けると、脆弱性につながります。このような認証の不備がどのように発生するのか、詳しくはSnyk LearnのBroken Authenticationレッスンをご覧ください。
Javaチームは、次の点に留意してください。
JWTの検証で、許可するアルゴリズムを明示的に設定する。
noneは決して許可しないでください。暗号化と署名は別のものとして扱う。復号によって証明されるのは機密性であり、真正性ではありません。JWEでラップされたトークンでも、署名の検証が必要です。
推移的依存関係を定期的に監査する。pac4j-jwtは、直接管理していないフレームワーク連携機能によって取り込まれている可能性があります。依存関係ツリーを監査する方法については、Javaの依存関係を管理するためのベストプラクティスをご覧ください。
JWTを安全に扱う方法について詳しくは、SnykブログのJWTを扱う際のセキュリティベストプラクティス3選とSnykはJWTのセキュリティ問題を検出できるのか?をご覧ください。
タイムライン
日付 | イベント |
|---|---|
2026年3月2日 | pac4j-jwtプロジェクトのメンテナーが修正をリリース |
2026年3月3日 | pac4j-jwtプロジェクトのメンテナーがアドバイザリとブログ記事を公開 |
2026年3月4日 | MITREでCVEの詳細が公開 |