In this article
CVE-2026-29000: como uma chave pública compromete a autenticação no pac4j-jwt
Uma falha crítica de bypass de autenticação na biblioteca de segurança Java pac4j-jwt permite que invasores se passem por qualquer usuário, inclusive administradores, usando apenas a chave pública RSA de um servidor. A vulnerabilidade, identificada como CVE-2026-29000, tem pontuação CVSS 10.0 e afeta todas as versões de org.pac4j:pac4j-jwt anteriores à 4.5.9, 5.7.9 e 6.3.3.
A falha é fácil de explorar. Já existe uma prova de conceito pública, e as versões corrigidas estão disponíveis. Se sua aplicação Java usa pac4j para autenticação baseada em JWT, continue lendo.
Resumo
Detalhe | Valor |
|---|---|
CVE | |
CVSS 3.1 | 10.0 Crítica ( |
CVSS 4.0 | 10.0 Crítica ( |
CWE | CWE-347: Verificação inadequada de assinatura criptográfica |
Artefato Maven |
|
Afetadas | 4.x \< 4.5.9, 5.0.0-RC1 \< 5.7.9, 6.0.4.1 \< 6.3.3 |
Corrigidas | 4.5.9, 5.7.9, 6.3.3 |
Status da exploração | PoC pública disponível |
Descoberta por | CodeAnt AI Security Research |
O que é pac4j?
pac4j é um framework de segurança para Java que oferece autenticação e autorização em vários protocolos: OAuth, SAML, CAS, OpenID Connect e JWT. O módulo pac4j-jwt é responsável especificamente pela criação e validação de JSON Web Tokens por meio da classe JwtAuthenticator.
O pac4j pode ser usado como mecanismo de autenticação subjacente em frameworks como Spring Security, JEE, Play, Vert.x e outros. Também é amplamente utilizado em ambientes CAS (Central Authentication Service), comuns em universidades e órgãos governamentais. Se sua aplicação usa autenticação baseada em pac4j com JWTs, ela pode estar vulnerável.
Como a vulnerabilidade funciona
Para entender essa vulnerabilidade, você precisa conhecer a diferença entre dois tipos de JWT:
JWS (JSON Web Signature): um token assinado. A assinatura comprova que o token não foi adulterado e que foi criado por alguém com a chave de assinatura.
JWE (JSON Web Encryption): um token criptografado. A criptografia protege o conteúdo do token contra leitura durante a transmissão. Um JWE pode encapsular um JWS, garantindo confidencialidade e integridade.
Quando o JwtAuthenticator do pac4j recebe um JWT criptografado (JWE), ele segue este processo:
Descriptografar o envelope JWE externo
Analisar o payload interno
Verificar a assinatura do token interno
A vulnerabilidade está na etapa 3. Depois de descriptografar o JWE, a biblioteca chama a função toSignedJWT() de com.nimbusds:nimbus-jose-jwt no payload interno para extrair o token assinado e verificá-lo. Se o token interno for um PlainJWT (um JWT com alg: none, ou seja, sem assinatura), esse método retorna null.
No código vulnerável, esse valor null fazia com que todo o bloco de verificação da assinatura fosse ignorado. Na prática, a biblioteca dizia: "Não encontrei uma assinatura para verificar, então vou continuar."
Veja uma versão simplificada da lógica vulnerável:
// (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);A correção rejeita explicitamente tokens sem assinatura encontrados dentro de um envelope criptografado:
if (!signatureConfigurations.isEmpty()) {
if (signedJWT == null) {
throw new CredentialsException(
"A non-signed JWT cannot be accepted...");
}
// Proceed with normal signature verification
}Como o ataque funciona na prática
O invasor precisa de apenas uma coisa: a chave pública RSA do servidor. Por definição, chaves públicas são... públicas. Elas costumam estar disponíveis em endpoints JWKS, certificados ou arquivos de configuração.
Etapas do ataque:
Obter a chave pública RSA do servidor (em um endpoint JWKS, certificado TLS ou outra fonte pública)
Criar um PlainJWT com declarações arbitrárias:
{
"sub": "admin",
"role": "ADMIN",
"exp": 1772611200
}Encapsulá-lo em um JWE criptografado com a chave pública RSA do servidor
Enviar o token forjado à aplicação
A aplicação descriptografa o JWE (a criptografia com a chave pública é válida), não encontra nenhuma assinatura para verificar, ignora a verificação e aceita as declarações forjadas como autênticas
O invasor não precisa da chave privada, de um segredo compartilhado nem de credenciais. O único ingrediente necessário é a chave pública que deveria proteger o sistema.
Quem é afetado
Você pode estar vulnerável se:
Usa criptografia RSA. Isso pode ser identificado pela classe RSAEncryptionConfiguration no projeto.
Sua aplicação usa
org.pac4j:pac4j-jwtpara autenticação JWTVocê usa tanto configurações de criptografia (JWE) quanto de verificação de assinatura (JWS) no
JwtAuthenticatorVocê está usando uma versão anterior à 4.5.9, 5.7.9 ou 6.3.3
Aplicações que usam apenas JWTs assinados (JWS), sem criptografia, não estão vulneráveis a esse ataque específico, pois o truque de inserir um PlainJWT em um JWE depende da configuração de criptografia.
Verifique com o Snyk
Você pode verificar se seu projeto foi afetado usando a Snyk CLI:
# For Maven projects
snyk test --maven
# For Gradle projects
snyk test --gradleO Snyk identifica essa vulnerabilidade como SNYK-JAVA-ORGPAC4J-15428218. Se o pacote vulnerável estiver na árvore de dependências, o Snyk vai sinalizá-lo e recomendar o caminho de atualização.
Se você usa Maven, o plugin Snyk Maven também pode detectar essa vulnerabilidade durante o processo de build, sem exigir uma etapa separada com a CLI. Para projetos Gradle, o plugin Snyk Gradle oferece a mesma capacidade de análise integrada.
Você também pode pesquisar suas dependências diretamente:
# Check if pac4j-jwt is in your dependency tree
mvn dependency:tree | grep pac4j-jwt
# Or with Gradle
gradle dependencies | grep pac4j-jwtCorreção
Atualize org.pac4j:pac4j-jwt para a versão corrigida da sua linha de versão principal:
Versão atual | Atualizar para |
|---|---|
4.x | 4.5.9 ou posterior |
5.x | 5.7.9 ou posterior |
6.x | 6.3.3 ou posterior |
Para Maven, atualize seu pom.xml:
<!-- For pac4j 6.x -->
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-jwt</artifactId>
<version>6.3.3</version>
</dependency>Para Gradle:
// For pac4j 6.x
implementation 'org.pac4j:pac4j-jwt:6.3.3'Se você não puder atualizar imediatamente
Embora seja altamente recomendável atualizar, você pode reduzir sua exposição:
Revise sua configuração de JWT: se sua aplicação usa apenas JWTs assinados (JWS), sem criptografia, ela não está vulnerável a esse ataque específico. Ainda assim, atualizar é a opção mais segura.
Audite o código que processa JWTs: confirme que sua aplicação exige explicitamente tokens assinados e rejeita tokens sem assinatura na camada da aplicação.
Não há uma solução alternativa nas configurações do próprio pac4j para as versões vulneráveis.
Por que isso importa além do pac4j
Essa vulnerabilidade é um exemplo clássico de uma categoria mais ampla de falhas de implementação de JWT. O problema central — tratar a ausência de uma propriedade de segurança (uma assinatura) como algo a ser ignorado, em vez de rejeitado — aparece há anos em bibliotecas JWT de várias linguagens.
A lição é clara: a verificação criptográfica precisa ser obrigatória, não opcional. Quando uma biblioteca encontra um token sem assinatura onde deveria haver um assinado, a única resposta segura é rejeitá-lo. Ignorar o problema silenciosamente é abrir caminho para uma vulnerabilidade. Para entender melhor como falhas de autenticação como essa acontecem, confira a lição sobre autenticação quebrada no Snyk Learn.
Para equipes Java, fica o lembrete:
Configure explicitamente os algoritmos aceitos na validação de JWT. Nunca permita
none.Trate criptografia e assinatura como questões independentes. A descriptografia comprova confidencialidade, não autenticidade. Mesmo um token encapsulado em JWE precisa ter a assinatura verificada.
Audite regularmente as dependências transitivas. O pac4j-jwt pode ser incluído por uma integração de framework que você não gerencia diretamente. Consulte Práticas recomendadas para gerenciar dependências Java para saber como auditar sua árvore de dependências.
Para saber mais sobre práticas seguras de uso de JWT, confira no blog da Snyk: As 3 principais práticas de segurança para lidar com JWTs e O Snyk consegue detectar problemas de segurança em JWTs?.
Cronologia
Data | Evento |
|---|---|
2 de março de 2026 | O responsável pelo projeto pac4j-jwt publicou as correções |
3 de março de 2026 | O responsável pelo projeto pac4j-jwt publicou um comunicado e uma postagem no blog |
4 de março de 2026 | Detalhes da CVE publicados no MITRE |
WHITE PAPER
A crise de segurança da IA no seu ambiente Python
Com o ritmo de desenvolvimento acelerando cada vez mais, você sabe o que o seu ambiente de IA pode acessar?