
pac4j-check v0.2.0
Scanner offline para CVE-2026-29000 (CVSS 10.0) em org.pac4j:pac4j-jwt. Inspeciona jars/fat-jars diretamente, por isso funciona onde mvn dependency:tree não consegue. Jar único, zero dependências, Java 8+.
pac4j-check
Verificação offline da CVE-2026-29000 (CVSS 10.0) — incluindo os pacotes que o advisory oficial não lista.
English | 中文
Um único jar, cerca de 24KB, zero dependências em tempo de execução, disponível a partir do Java 8, totalmente offline, não envia nenhum dado para fora.
O que é esta vulnerabilidade
O JwtAuthenticator do org.pac4j:pac4j-jwt não força a validação de assinatura ao processar JWT criptografado (JWE).
Basta que o atacante obtenha a chave pública RSA do servidor (a chave pública é, por natureza, pública),
para construir um PlainJWT encapsulado em JWE, escrever qualquer valor em subject e role,
e autenticar-se como qualquer usuário, incluindo administrador. Sem necessidade de qualquer credencial.
| Item | Valor |
|---|---|
| CVE | CVE-2026-29000 |
| GitHub advisory | GHSA-pm7g-w2cf-q238 |
| CVSS | 10.0 (pontuação máxima) |
| Data de publicação | 2026-03-05 |
O pac4j é amplamente integrado com Spring Security, Apereo CAS, JEE, Vert.x, Play, Dropwizard, entre outros.
🔴 Correção da v0.2.0: a alegação central da v0.1.0 estava errada
A v0.1.0 afirmava que "a base oficial de vulnerabilidades lista apenas 1 pacote, quando na verdade são 5", e por isso reportava como vulneráveis
pac4j-oidc / javalin-pac4j / lagom-pac4j / ratpack-pac4j.
Isso era um falso positivo. O advisory oficial listar apenas pac4j-jwt está correto.
Base da revisão (duas evidências independentes, ambas reproduzíveis por conta própria):
| Artefato | Sua dependência de pac4j-jwt | É repassada ao consumidor |
|---|---|---|
pac4j-oidc | escopo test (verificado versão a versão em 3.0.0 / 4.0.0 / 4.5.0 / 5.0.0 / 5.7.0 / 6.0.0 / 6.3.0) | ❌ |
javalin-pac4j | escopo test | ❌ |
lagom-pac4j-parent | escopo provided | ❌ |
ratpack-pac4j:1.4.6 | todo o bloco de dependência está envolvido por um comentário XML, simplesmente não existe | ❌ |
- O escopo não é transitivo — no Maven, dependências de escopo
test/providednão são repassadas para downstream, o pac4j-jwt não aparece no runtime classpath do consumidor. - Reinspeção do artefato real — o
pac4j-oidc-6.0.0.jartem 78 entradas no total, todas soborg/pac4j/oidc/, sem nenhuma classe pac4j-jwt embutida via shade. Nem é repassado, nem é carregado.
Onde estava o erro: a v0.1.0 analisou cada pom individualmente, mas olhou apenas "quem escreveu a coordenada pac4j-jwt",
sem olhar o scope — tratando "está escrito no pom" como "o consumidor vai receber".
Se você atualizou o pac4j por causa do relatório da v0.1.0, essa atualização não era necessária (a atualização em si é inofensiva). Só é necessário agir quando existe de fato um
pac4j-jwtde versão afetada na sua aplicação.
Por que ainda é necessária uma ferramenta dedicada
Para determinar se há ou não um pac4j-jwt afetado em uma determinada máquina, o mvn dependency:tree falha em dois casos —
na máquina de produção só existe um fat-jar já empacotado (sem código-fonte e sem pom); ou ele foi embutido via shade dentro de algum SDK,
e nem aparece na árvore de dependências. Esta ferramenta escaneia diretamente o próprio artefato, sem depender do ambiente de build.
| Artefato | Número de versões afetadas | Advisory oficial |
|---|---|---|
org.pac4j:pac4j-jwt | 114 | ✅ o único listado, e isso está correto |
Uso
java -jar pac4j-check.jar ./myapp.jar # escaneia um jar/war
java -jar pac4j-check.jar /opt/apps # escaneia um diretório (recursivo)
java -jar pac4j-check.jar /opt/apps --json # saída JSON, para encadear em pipes
java -jar pac4j-check.jar ./app.jar --gbk # use quando o console do Windows exibir caracteres chineses corrompidos
Códigos de saída: 0 = não encontrado afetado · 1 = em dúvida/não determinável · 2 = encontrado afetado. Pode ser plugado diretamente no CI.
Exemplo de saída
[CRITICAL] pac4j-jwt 5.4.3
位置 :demo-app.jar!/BOOT-INF/lib/pac4j-jwt-5.4.3.jar
版本来源:pom.properties(可靠)
部署形态:Spring Boot fat-JAR
结论 :命中 CVE-2026-29000 —— JWE 处理路径未强制校验签名,
拿到服务器 RSA 公钥即可伪造任意身份(含管理员)登录
处置 :升级 pac4j-jwt 至 5.7.9
A v0.1.0 ainda reportaria aqui uma linha extra
[CRITICAL] pac4j-oidc— isso era um falso positivo, removido na v0.2.0, o motivo está na correção no início do documento.
O que ele faz
- Expande recursivamente fat-JARs do Spring Boot (em memória, sem descompactar em disco), rastreando até o caminho aninhado específico
- Identifica casos embutidos via shade no jar hospedeiro — exatamente o tipo que o
mvn dependency:treenão consegue detectar - Rastreia a cadeia de introdução — informa qual artefato arrastou o pac4j-jwt para dentro
- Fornece o veredito e o alvo de atualização concreto conforme os intervalos oficiais
Regras de veredito e limites (leia até o fim antes de usar)
O veredito segue sempre o advisory oficial GHSA-pm7g-w2cf-q238:
pac4j-jwt < 4.5.9 -> atualizar para 4.5.9
pac4j-jwt >= 5.0.0-RC1 e < 5.7.9 -> atualizar para 5.7.9
pac4j-jwt >= 6.0.4.1 e < 6.3.3 -> atualizar para 6.3.3
Autoverificação: esta ferramenta executa o veredito sobre todas as 147 versões do pac4j-jwt no Maven Central,
o número de acertos é 114, coincidindo exatamente com a soma das versões dos três intervalos do advisory oficial (13+33+68).
Essa asserção está escrita nos testes (OfficialRangeCrossCheckTest); se não bater, o build falha.
⚠️ Mas é preciso ter clareza sobre o que isso valida: valida que o algoritmo de intervalo de versões está correto, não valida "quais artefatos devem entrar na tabela de veredito" — o falso positivo da v0.1.0 ocorreu justamente neste último ponto, e na época essa autoverificação estava verde. O escopo em que a verificação passa ≠ o escopo em que a conclusão é válida.
Duas limitações que precisam ser esclarecidas
-
Cobre apenas o groupId
org.pac4j. Há pesquisas de terceiros afirmando que são 19 artefatos afetados, 1.020 versões, mas a lista completa não foi divulgada. O que esta ferramenta reconstrói de forma independente é a parte dentro do escopo org.pac4j, sem alegar cobertura total. Outros groupIds (comoorg.apereo.casdo Apereo CAS) não foram incluídos. -
pac4j-jwt6.0.0 ~ 6.0.4 é marcado como "em dúvida" e não como "afetado". O oficial afirma que a série 6.x é afetada a partir de6.0.4.1; já a pesquisa de terceiros afirma que a vulnerabilidade foi introduzida já em1.9.2— se isso for verdade, essas 5 versões também deveriam contar. Não verificamos de forma independente a conclusão de terceiros, por isso as marcamos separadamente e recomendamos atualização conservadora, em vez de classificá-las diretamente como críticas.
Por que ser tão conservador: uma regra de veredito errada não é um "falso positivo", é fazer o usuário tomar a ação errada. Preferimos marcar como em dúvida a fixar como conclusão um escopo não verificado.
Build
mvn package # artefato: target/pac4j-check.jar
mvn test # 31 testes
Feedback
Se encontrar erro de veredito, omissão ou falso positivo, abra uma Issue. Se você puder fornecer coordenadas reproduzíveis do artefato (groupId:artifactId:version), a correção será muito mais rápida.
License
Apache License 2.0
pac4j-check (English)
Offline scanner for CVE-2026-29000 (CVSS 10.0) — including the packages the official advisory does not list.
Single jar, ~24KB, zero runtime dependencies, Java 8+, fully offline, sends nothing anywhere.
The vulnerability
JwtAuthenticator in org.pac4j:pac4j-jwt fails to enforce signature validation on certain
encrypted JWT (JWE) processing paths. An attacker holding the server's RSA public key
(which is public by design) can craft a JWE-wrapped PlainJWT with arbitrary subject and role
claims and authenticate as any user, including administrators — with no credentials.
| CVE | CVE-2026-29000 |
| GitHub advisory | GHSA-pm7g-w2cf-q238 |
| CVSS | 10.0 |
| Published | 2026-03-05 |
🔴 v0.2.0 correction: v0.1.0's central claim was wrong
v0.1.0 claimed the official advisory "lists only one package while there are five", and
flagged pac4j-oidc / javalin-pac4j / lagom-pac4j / ratpack-pac4j as affected.
Those were false positives. The advisory listing only pac4j-jwt is correct.
| Artifact | How it declares pac4j-jwt | Reaches consumers? |
|---|---|---|
pac4j-oidc | test scope (verified on 3.0.0 / 4.0.0 / 4.5.0 / 5.0.0 / 5.7.0 / 6.0.0 / 6.3.0) | ❌ |
javalin-pac4j | test scope | ❌ |
lagom-pac4j-parent | provided scope | ❌ |
ratpack-pac4j:1.4.6 | the whole block is inside an XML comment — it does not exist | ❌ |
Two independent lines of evidence, both reproducible:
- Scope does not propagate — Maven does not pass
test/provideddependencies to downstream consumers, so pac4j-jwt never reaches their runtime classpath. - Artifact inspection —
pac4j-oidc-6.0.0.jarhas 78 entries, all underorg/pac4j/oidc/, with no shaded pac4j-jwt classes.
Root cause: v0.1.0 did parse every pom, but only looked at who names the coordinate,
never at scope — mistaking "declared in a pom" for "reaches the consumer".
If you upgraded pac4j because of a v0.1.0 report, that upgrade was not required (though harmless). Action is only needed when an affected
pac4j-jwtis actually present.
Why a dedicated tool
Deciding whether an affected pac4j-jwt is actually on a given machine defeats
mvn dependency:tree in two common cases: a production box with only a packaged fat-jar
(no sources, no pom), or a copy shaded inside some vendor SDK, invisible to the dependency
tree. This tool inspects the artifacts themselves.
| Artifact | Affected versions | In official advisory |
|---|---|---|
org.pac4j:pac4j-jwt | 114 | ✅ the only one listed — and that is correct |
Usage
java -jar pac4j-check.jar ./myapp.jar
java -jar pac4j-check.jar /opt/apps
java -jar pac4j-check.jar /opt/apps --json
Exit codes: 0 clean · 1 disputed/undetermined · 2 affected.
What it does
- Recursively unpacks Spring Boot fat-JARs in memory (nothing written to disk)
- Detects pac4j-jwt shaded into a host jar — the case
mvn dependency:treecannot see - Traces the introduction chain, so you know which artifact pulled it in
- Reports a concrete upgrade target
Rules and limitations
Verdicts follow the official advisory GHSA-pm7g-w2cf-q238 exactly:
pac4j-jwt < 4.5.9 -> 4.5.9
pac4j-jwt >= 5.0.0-RC1 and < 5.7.9 -> 5.7.9
pac4j-jwt >= 6.0.4.1 and < 6.3.3 -> 6.3.3
Cross-check: running the rules over all 147 published pac4j-jwt versions yields 114
affected — exactly matching the advisory's three ranges (13+33+68). This is asserted in
OfficialRangeCrossCheckTest; a mismatch fails the build.
Two limitations, stated plainly:
- Only the
org.pac4jgroupId is covered. Third-party research reports 19 affected packages across 1,020 versions but has not published the full list. This tool independently reconstructs the org.pac4j portion and does not claim full coverage. - pac4j-jwt 6.0.0–6.0.4 are reported as DISPUTED, not AFFECTED. The advisory starts the
6.x range at
6.0.4.1; third-party research states the flaw was introduced as early as1.9.2. We have not independently verified the latter, so these versions are flagged for human review with a conservative upgrade recommendation rather than asserted as vulnerable.
A wrong verdict is not a "false positive" — it makes people take the wrong action.
License
Apache License 2.0
Precisa de uma investigação mais aprofundada?
Esta ferramenta responde à pergunta "eu fui afetado ou não". As questões abaixo ela não consegue responder, mas posso ajudar:
- Dependências que passaram por shade / relocate, ou cujo artefato de build simplesmente não está disponível
- Determinar se "esta CVE na nossa cadeia de chamadas realmente dispara", e não apenas se a versão foi atingida
- Personalização conforme o seu próprio processo de build ou ambiente de rede interna, integração ao pipeline existente
- Você tem um problema semelhante com outro componente e ainda não existe ferramenta pronta
📮 [email protected] — descreva a situação e em até 24 horas envio uma resposta por escrito de uma página: se é possível fazer, onde está a dificuldade, quanto tempo levaria. Esta etapa é gratuita e você não precisa se comprometer com nada antecipadamente.