[PT] CVE-2026-114509: Bypass de Autenticação no Laravel TokenGuard
JOIN
JOIN
RESEARCH ENTRY 2026.10.20
pt-br

[PT] CVE-2026-114509: Bypass de Autenticação no Laravel TokenGuard

Gabriel Rodrigues
RESEARCHER Gabriel Rodrigues, Rafael Felix
READ TIME4 MINUTES
PUBLISHED20 Oct 2026
[PT] CVE-2026-114509: Bypass de Autenticação no Laravel TokenGuard

Resumo

A equipe da Yokai Research analisou em detalhes e desenvolveu uma prova de conceito para uma vulnerabilidade crítica de desvio de autenticação no Laravel (identificada como GHSA-f9x3-7vq9-cph6). A falha ocorre no TokenGuard o mecanismo nativo responsável pela proteção de rotas auth:api. Ela foi descoberta por KIKOmanasijev e reportada via GitHub Security Advisory.

Com severidade 9.2 (Crítica) no CVSS v4, a vulnerabilidade afeta o Laravel nas versões anteriores a 13.29.0 e 12.68.0. Caso a tabela de usuários da aplicação utilize MySQL ou MariaDB, um invasor sem credenciais consegue se autenticar como qualquer usuário cadastrado sem precisar de um token válido basta enviar uma única requisição customizada para qualquer rota protegida.

Após a notificação, Taylor Otwell, criador do Laravel, lançou as correções entre 24 e 25 de agosto de 2026 commits 9b21ce0a9bb, 8dbb08bc, 5056ca53, e o alerta oficial foi publicado em 19 de outubro de 2026. Este artigo traz uma análise aprofundada da causa raiz, a comparação do código antes e depois do ajuste, além de um ambiente de teste (lab) reproduzível e o exploit funcional.

Detalhes Técnicos

A vulnerabilidade explora a falta de uma validação de tipos nas credenciais de autenticação, combinada com a forma como o MySQL e o MariaDB realizam a conversão automática de tipos (type coercion) ao comparar colunas de texto (string) com valores inteiros.

A lógica vulnerável fica no arquivo src/Illuminate/Auth/TokenGuard.php, mais especificamente nos métodos user() (linha 70) e validate() (linha 111). O código anterior à correção pode ser consultado no histórico da versão original, bem como a sua versão corrigida.

Na versão não corrigida, o método user() aceita qualquer credencial que não esteja "vazia" antes de consultar o provedor de usuários:

$token = $this->getTokenForRequest();

if (!empty($token)) {
    $user = $this->provider->retrieveByCredentials([
        $this->storageKey => $this->hash ? hash('sha256', $token) : $token,
    ]);

No PHP, a função empty() retorna false para arrays que não estejam vazios, o que faz com que uma credencial que não seja do tipo texto (como um array) passe direto pela checagem inicial. Em seguida, o provedor (EloquentUserProvider::retrieveByCredentials()) converte os valores desse array em uma cláusula whereIn():

foreach ($credentials as $key => $value) {
    if (is_array($value) || $value instanceof Arrayable) {
        $query->whereIn($key, $value);
    }

A instrução SQL resultante se torna select * from users where api_token in (?) limit 1. Como o payload vem do corpo de uma requisição JSON (onde o json_decode gera um inteiro nativo do PHP), o PDO faz o vínculo do parâmetro como PARAM_INT.

Com isso, o MySQL e o MariaDB comparam a coluna do token (que é do tipo VARCHAR) numericamente qualquer valor que não comece com um dígito é convertido para 0 um comportamento confirmado durante os testes, nos quais a consulta SELECT 'poc-token-abc' = 0 retornou 1. A linha do banco é correspondida e o sistema reconhece a requisição como autenticada.

Endpoints Afetados

Qualquer rota protegida pela proteção baseada em token do Laravel (com o middleware auth:api ou com uma proteção configurada com o driver token), que utilize o parâmetro de credencial api_token:

Caso de uso comum:

Exemplo de exploração:

O primeiro usuário cujo token armazenado não comece com um dígito é retornado pela consulta e definido pela proteção como o usuário autenticado.

Prova de Conceito

Com base na vulnerabilidade relatada por KIKOmanasijev, a equipe de pesquisa da Hakai desenvolveu um exploit em Python e um laboratório em Docker totalmente reproduzível:https://github.com/hakaioffsec/GHSA-f9x3-7vq9-cph6-PoC

O ambiente de testes executa lado a lado, sobre o mesmo banco de dados MySQL 8, o commit exatamente vulnerável (13.x#0189a60b) e o commit com a correção (13.x#9b21ce0a):

0:00
/0:18

Correção

A equipe do Laravel corrigiu a vulnerabilidade adicionando a validação is_string(), garantindo que credenciais que não sejam do tipo texto jamais cheguem ao provedor de usuários (disponibilizada no commit 9b21ce0a9bb para a versão 13.x, e retroportada como 8dbb08bc para a 12.x e 5056ca53 para a 11.x).

-        if (! empty($token)) {
+        if (is_string($token) && ! empty($token)) {

-        if (empty($credentials[$this->inputKey])) {
+        if (! is_string($credentials[$this->inputKey] ?? null) || empty($credentials[$this->inputKey])) {

Validada pelo histórico do Git, a correção foi lançada originalmente nas tags v13.27.0 (13.x), v12.68.0 (12.x) e v11.56.1 (11.x). O alerta oficial indica as versões >= 13.29.0 e >= 12.68.0 como corrigidas uma indicação conservadora, já que nenhuma alteração afetou o arquivo TokenGuard.php entre as versões v13.27.0 e v13.29.0.

Recomendações

Recomenda-se atualizar o pacote laravel/framework para a versão 13.29.0 ou superior (para a 12.x: 12.68.0 ou superior; para a 11.x: 11.56.1 ou superior) ou, no mínimo, para a primeira tag que contém a correção (v13.27.0).

Conclusão

A exploração desta vulnerabilidade permite que um atacante não autenticado se aproveite da validação flexível do empty() no PHP combinada com a conversão implícita para whereIn() e a conversão numérica do MySQL/MariaDB para se autenticar como qualquer usuário existente em uma aplicação Laravel, resultando na invasão total da conta (account takeover) em rotas protegidas por token. A solução aplicada foi uma validação de string diretamente na camada do guard.

Vamos praticar!

O Hacking Club é uma plataforma de treinamento focada no desenvolvimento de profissionais de cibersegurança. O desafio TokenGuard simula um servidor com a vulnerabilidade mencionada nesta postagem e pode ser utilizado para reforçar o conhecimento apresentado.

References