In this article
CVE-2026-29000 : comment une clé publique contourne l’authentification dans pac4j-jwt
Une vulnérabilité critique permettant de contourner l’authentification dans la bibliothèque de sécurité Java pac4j-jwt permet aux attaquants d’usurper l’identité de n’importe quel utilisateur, y compris celle des administrateurs, avec pour seul élément la clé publique RSA d’un serveur. Suivie sous l’identifiant CVE-2026-29000, cette vulnérabilité affiche un score CVSS de 10.0 et affecte toutes les versions de org.pac4j:pac4j-jwt antérieures aux versions 4.5.9, 5.7.9 et 6.3.3.
Cette faille est facile à exploiter. Une preuve de concept publique est disponible et des versions corrigées sont déjà publiées. Si votre application Java utilise pac4j pour l’authentification basée sur JWT, poursuivez votre lecture.
En bref
Détail | Valeur |
|---|---|
CVE | |
CVSS 3.1 | 10.0 Critique ( |
CVSS 4.0 | 10.0 Critique ( |
CWE | CWE-347 : vérification incorrecte de la signature cryptographique |
Artefact Maven |
|
Affectées | 4.x \< 4.5.9, 5.0.0-RC1 \< 5.7.9, 6.0.4.1 \< 6.3.3 |
Corrigées | 4.5.9, 5.7.9, 6.3.3 |
État de l’exploitation | Preuve de concept publique disponible |
Découverte par | CodeAnt AI Security Research |
Qu’est-ce que pac4j ?
pac4j est un framework de sécurité pour Java qui fournit des fonctionnalités d’authentification et d’autorisation pour plusieurs protocoles : OAuth, SAML, CAS, OpenID Connect et JWT. Le module pac4j-jwt gère spécifiquement la création et la validation des JSON Web Tokens au moyen de sa classe JwtAuthenticator.
pac4j peut servir de moteur d’authentification sous-jacent dans des frameworks comme Spring Security, JEE, Play et Vert.x, entre autres. Il est également largement utilisé dans les environnements CAS (Central Authentication Service), courants dans les universités et les institutions gouvernementales. Si votre application utilise une authentification basée sur pac4j et des JWT, elle peut être concernée.
Fonctionnement de la vulnérabilité
Pour comprendre cette vulnérabilité, vous devez connaître la différence entre deux types de JWT :
JWS (JSON Web Signature) : un jeton signé. La signature prouve que le jeton n’a pas été modifié et qu’il a été créé par une personne disposant de la clé de signature.
JWE (JSON Web Encryption) : un jeton chiffré. Le chiffrement protège le contenu du jeton contre la lecture pendant son transit. Un JWE peut encapsuler un JWS afin d’assurer à la fois la confidentialité et l’intégrité.
Lorsque le JwtAuthenticator de pac4j reçoit un JWT chiffré (JWE), il suit ce processus :
Déchiffrer l’enveloppe JWE externe
Analyser la charge utile interne
Vérifier la signature du jeton interne
La vulnérabilité se situe à l’étape 3. Après avoir déchiffré le JWE, la bibliothèque appelle la fonction toSignedJWT() de com.nimbusds:nimbus-jose-jwt sur la charge utile interne pour extraire le jeton signé à vérifier. Si le jeton interne est un PlainJWT (un JWT avec alg: none, ce qui signifie qu’il n’a aucune signature), cette méthode renvoie null.
Dans le code vulnérable, cette valeur nulle entraînait l’omission de tout le bloc de vérification de la signature. En pratique, la bibliothèque disait : « Je ne trouve pas de signature à vérifier, je vais donc simplement continuer. »
Voici une représentation simplifiée de la logique vulnérable :
// (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);Le correctif ajoute un rejet explicite lorsqu’un jeton non signé est trouvé dans une enveloppe chiffrée :
if (!signatureConfigurations.isEmpty()) {
if (signedJWT == null) {
throw new CredentialsException(
"A non-signed JWT cannot be accepted...");
}
// Proceed with normal signature verification
}L’attaque en pratique
Un attaquant n’a besoin que d’un seul élément : la clé publique RSA du serveur. Par définition, les clés publiques sont… publiques. Elles sont souvent intégrées à des points de terminaison JWKS, des certificats ou des fichiers de configuration.
Étapes de l’attaque :
Obtenir la clé publique RSA du serveur (à partir d’un point de terminaison JWKS, d’un certificat TLS ou de toute autre source publique)
Créer un PlainJWT avec des revendications arbitraires :
{
"sub": "admin",
"role": "ADMIN",
"exp": 1772611200
}L’encapsuler dans un JWE chiffré avec la clé publique RSA du serveur
Envoyer le jeton forgé à l’application
L’application déchiffre le JWE (le chiffrement avec la clé publique est valide), ne trouve aucune signature à vérifier, ignore la vérification et accepte les revendications forgées comme authentiques
L’attaquant n’a jamais besoin de la clé privée, d’un secret partagé ni d’identifiants. La clé publique censée protéger le système est le seul élément nécessaire.
Qui est concerné ?
Vous êtes potentiellement concerné si :
Vous utilisez le chiffrement RSA. Le projet permet de le détecter avec RSAEncryptionConfiguration.
Votre application utilise
org.pac4j:pac4j-jwtpour l’authentification JWTVous utilisez à la fois le chiffrement (JWE) et la vérification de signature (JWS) dans les configurations de votre
JwtAuthenticatorVous exécutez une version antérieure à 4.5.9, 5.7.9 ou 6.3.3
Les applications qui utilisent uniquement des JWT signés (JWS), sans chiffrement, ne sont pas vulnérables à cette attaque particulière, car l’astuce du PlainJWT dans un JWE nécessite que le chiffrement soit configuré.
Vérifier avec Snyk
Vous pouvez vérifier si votre projet est concerné à l’aide de Snyk CLI :
# For Maven projects
snyk test --maven
# For Gradle projects
snyk test --gradleSnyk suit cette vulnérabilité sous l’identifiant SNYK-JAVA-ORGPAC4J-15428218. Si le package vulnérable figure dans votre arborescence de dépendances, Snyk le signalera et vous recommandera une mise à niveau.
Si vous utilisez Maven, le plugin Snyk pour Maven peut également détecter cette vulnérabilité pendant le cycle de compilation, sans étape distincte avec la CLI. Pour les projets Gradle, le plugin Snyk pour Gradle offre les mêmes capacités d’analyse intégrée.
Vous pouvez également rechercher directement dans vos dépendances :
# Check if pac4j-jwt is in your dependency tree
mvn dependency:tree | grep pac4j-jwt
# Or with Gradle
gradle dependencies | grep pac4j-jwtCorrection
Mettez à niveau org.pac4j:pac4j-jwt vers la version corrigée correspondant à votre branche majeure :
Version actuelle | Mettre à niveau vers |
|---|---|
4.x | 4.5.9 ou une version ultérieure |
5.x | 5.7.9 ou une version ultérieure |
6.x | 6.3.3 ou une version ultérieure |
Avec Maven, mettez à jour votre pom.xml :
<!-- For pac4j 6.x -->
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-jwt</artifactId>
<version>6.3.3</version>
</dependency>Avec Gradle :
// For pac4j 6.x
implementation 'org.pac4j:pac4j-jwt:6.3.3'Si vous ne pouvez pas effectuer la mise à niveau immédiatement
Bien qu’une mise à niveau soit fortement recommandée, vous pouvez réduire votre exposition en prenant les mesures suivantes :
Vérifiant votre configuration JWT : si votre application utilise uniquement des JWT signés (JWS), sans chiffrement, vous n’êtes pas exposé à cette attaque particulière. Cependant, la mise à niveau reste la solution la plus sûre.
Auditez le code qui gère les JWT : assurez-vous que votre application exige explicitement des jetons signés et rejette les jetons non signés au niveau applicatif.
Il n’existe aucune solution de contournement au niveau de la configuration dans pac4j pour les versions vulnérables.
Pourquoi cette vulnérabilité dépasse le cadre de pac4j
Cette vulnérabilité illustre parfaitement une catégorie plus large de failles d’implémentation des JWT. Le problème fondamental — traiter l’absence d’une propriété de sécurité (une signature) comme un élément à ignorer plutôt qu’à rejeter — se manifeste depuis des années dans des bibliothèques JWT écrites dans différents langages.
La leçon est toujours la même : la vérification cryptographique doit être obligatoire, et non facultative. Lorsqu’une bibliothèque reçoit un jeton non signé alors qu’un jeton signé est attendu, la seule réponse sûre est de le rejeter. Une poursuite silencieuse du traitement est une vulnérabilité en puissance. Pour approfondir la manière dont se manifestent les failles d’authentification comme celle-ci, consultez la leçon sur les failles d’authentification sur Snyk Learn.
Pour les équipes Java, c’est l’occasion de rappeler qu’il faut :
Configurer explicitement les algorithmes acceptés lors de la validation des JWT. N’autorisez jamais
none.Traiter le chiffrement et la signature comme deux sujets distincts. Le déchiffrement garantit la confidentialité, pas l’authenticité. La signature d’un jeton encapsulé dans un JWE doit toujours être vérifiée.
Auditer régulièrement les dépendances transitives. pac4j-jwt peut être ajouté par une intégration de framework que vous ne gérez pas directement. Consultez les bonnes pratiques de gestion des dépendances Java pour savoir comment auditer votre arborescence de dépendances.
Pour en savoir plus sur les bonnes pratiques de gestion sécurisée des JWT, consultez les articles 3 bonnes pratiques de sécurité pour gérer les JWT et Snyk peut-il détecter les problèmes de sécurité liés aux JWT ? sur le blog de Snyk.
Chronologie
Date | Événement |
|---|---|
2 mars 2026 | le responsable du projet pac4j-jwt a publié des correctifs |
3 mars 2026 | le responsable du projet pac4j-jwt a publié un avis de sécurité et un article de blog |
4 mars 2026 | Publication des détails de la CVE sur MITRE |
LIVRE BLANC
La crise de la sécurité de l’IA dans votre environnement Python
Avec l’accélération fulgurante du développement, savez-vous vraiment à quoi votre environnement d’IA peut accéder ?