CVE-2026-6478: timing channel em senhas MD5 no PostgreSQL


Em 14 de maio de 2026, o PostgreSQL publicou correções de segurança para as versões 18.4, 17.10, 16.14, 15.18 e 14.23. Entre as vulnerabilidades corrigidas está a CVE-2026-6478, descrita pelo projeto como um canal lateral de tempo na comparação de senhas MD5 durante a autenticação.

O ponto central é simples: senhas armazenadas no formato antigo MD5 podem vazar informação por pequenas diferenças no tempo de resposta da autenticação. Com medições repetidas, um atacante poderia recuperar credenciais suficientes para autenticar. O problema não afeta senhas armazenadas no formato scram-sha-256.

Fontes oficiais:


O problema em uma frase


Migrar a configuração do PostgreSQL para SCRAM não significa, automaticamente, que todas as roles deixaram de ter senhas MD5 armazenadas.

Esse é o erro operacional mais comum.

Um ambiente pode estar com:

password_encryption = scram-sha-256

e ainda assim possuir usuários antigos com rolpassword começando com:

md5...

Isso acontece porque password_encryption só define como novas senhas serão gravadas. Ele não reescreve automaticamente senhas antigas já existentes no catálogo do PostgreSQL.


Onde a senha fica armazenada


As roles do PostgreSQL ficam no catálogo pg_authid. A coluna rolpassword guarda o verificador de senha, não a senha em texto puro.

Para senhas MD5, o formato é:

md5<32 caracteres hexadecimais>

Segundo a documentação do PostgreSQL, esse hash é derivado da senha concatenada ao nome do usuário:

md5(senha + nome_do_usuario)

Exemplo conceitual:

usuario: joao
senha:   exemplo123
base:    exemplo123joao
hash:    md5(base)

O valor gravado em pg_authid.rolpassword ficaria no formato:

md5...

Para SCRAM-SHA-256, o formato é diferente:

SCRAM-SHA-256$<parametros>$<chaves>

Esse formato é mais moderno e não é afetado por essa CVE.


Por que clusters atualizados podem continuar vulneráveis


O cenário típico é:

  1. A empresa usava PostgreSQL 13 ou anterior.
  2. Existiam roles com senha gravada em MD5.
  3. O cluster foi atualizado para PostgreSQL 14, 15, 16, 17 ou 18.
  4. A configuração foi alterada para usar SCRAM.
  5. As senhas antigas não foram resetadas.

Resultado: a configuração atual parece correta, mas ainda existem credenciais antigas no formato MD5.

Esse detalhe importa porque a CVE-2026-6478 mira justamente a autenticação envolvendo senhas MD5.


O que é um timing channel


Um timing channel é um vazamento indireto por tempo.

O sistema não retorna explicitamente:

esse caractere está correto

Mas pode responder um pouco mais rápido ou um pouco mais devagar dependendo do caminho interno que o código executou.

Imagine uma comparação ingênua entre dois valores:

segredo real: abcd
tentativa:    x000

Se o primeiro caractere já está errado, o programa pode parar imediatamente.

Agora compare:

segredo real: abcd
tentativa:    a000

Nesse caso, o primeiro caractere bate. O programa avança para o segundo antes de falhar. Isso pode levar um pouco mais de tempo.

Agora:

segredo real: abcd
tentativa:    ab00

O programa compara dois caracteres corretos antes de falhar. Pode demorar mais ainda.

Individualmente, essas diferenças são minúsculas. Em uma rede real, ruído de CPU, cache, latência, concorrência e variação de sistema podem esconder tudo. O risco aparece quando alguém faz muitas tentativas e consolida medições.


Como esse tipo de ataque funciona em alto nível


O atacante não precisa necessariamente saber a senha original. Ele precisa transformar o servidor em um oráculo de tempo.

Um oráculo, nesse contexto, é um sistema que não revela a resposta diretamente, mas fornece pistas observáveis. A pista é o tempo de resposta.

O fluxo conceitual seria:

  1. Escolher uma role alvo que possa tentar autenticar.
  2. Enviar tentativas de autenticação cuidadosamente controladas.
  3. Medir o tempo de resposta de cada tentativa.
  4. Repetir muitas vezes para reduzir ruído.
  5. Comparar distribuições de tempo entre candidatos.
  6. Inferir qual candidato parece provocar uma comparação mais longa.
  7. Repetir o processo até recuperar material suficiente para autenticar.

Esse processo não é uma leitura direta da senha. É uma inferência estatística.

Também não é simplesmente testar palavras de uma lista como em um ataque de força bruta tradicional. Em vulnerabilidades de comparação por tempo, o atacante tenta observar se determinado candidato faz o servidor avançar mais profundamente na comparação interna.

Como valores MD5 são representados em hexadecimal, o espaço visual de caracteres de um hash costuma envolver:

0 1 2 3 4 5 6 7 8 9 a b c d e f

Mas o detalhe prático de como transformar isso em recuperação de credencial depende do protocolo, da implementação, do ponto exato da comparação vulnerável e da capacidade de medir tempo com precisão. Para fins defensivos, o importante é entender que o tempo de resposta pode funcionar como um sinal probabilístico.


Por que uma tentativa só não prova nada


Uma única medição não é confiável.

Exemplo:

candidato A: 10,3 ms
candidato B: 10,7 ms

Essa diferença pode ser causada por qualquer coisa: latência de rede, escalonamento do sistema operacional, cache, carga do servidor ou concorrência.

O ataque depende de repetição:

candidato A: centenas ou milhares de medições
candidato B: centenas ou milhares de medições
candidato C: centenas ou milhares de medições

Depois disso, o atacante compararia médias, medianas, dispersão e outliers para inferir qual candidato tem comportamento consistentemente diferente.

Portanto, o risco da CVE não é o servidor “entregar a senha” em uma resposta. O risco é o servidor permitir que uma diferença mínima seja amplificada estatisticamente.


Quem está vulnerável


Um ambiente deve ser considerado exposto quando estas condições se combinam:

  1. A versão do PostgreSQL é anterior à versão corrigida.
  2. Existem roles com rolpassword começando com md5.
  3. Um atacante consegue tentar autenticação contra o servidor.

As versões corrigidas são:

PostgreSQL 18.4
PostgreSQL 17.10
PostgreSQL 16.14
PostgreSQL 15.18
PostgreSQL 14.23

Versões anteriores dentro dessas majors são afetadas.


Como auditar o ambiente


Conecte como superuser ou com um usuário autorizado a consultar pg_authid.

Verifique a versão:

SELECT version();

Verifique a configuração atual:

SHOW password_encryption;

Liste os tipos de senha armazenados:

SELECT
  rolname,
  rolcanlogin,
  CASE
    WHEN rolpassword IS NULL THEN 'sem senha'
    WHEN rolpassword LIKE 'md5%' THEN 'MD5'
    WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'SCRAM'
    ELSE 'outro'
  END AS password_type
FROM pg_authid
ORDER BY password_type, rolname;

Liste apenas roles ainda em MD5:

SELECT rolname, rolcanlogin
FROM pg_authid
WHERE rolpassword LIKE 'md5%'
ORDER BY rolname;

Se essa consulta retornar linhas, ainda existem verifiers MD5 no cluster.


Como corrigir


A ordem correta é:

  1. Atualizar o PostgreSQL para a versão corrigida.
  2. Auditar roles com senha MD5.
  3. Resetar essas senhas com password_encryption = 'scram-sha-256'.
  4. Ajustar pg_hba.conf para SCRAM quando possível.
  5. Validar que não restaram hashes MD5.

1. Aplicar o minor release corrigido


Atualize para uma destas versões ou superior dentro da mesma major:

14.23
15.18
16.14
17.10
18.4

Segundo o anúncio do PostgreSQL, atualizações minor não exigem dump/restore nem pg_upgrade. Normalmente o procedimento envolve parar o serviço, atualizar os binários/pacotes e iniciar novamente, respeitando o método de instalação da distribuição ou fornecedor.


2. Garantir SCRAM como padrão para novas senhas


Configure:

ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
SHOW password_encryption;

Ou ajuste diretamente no postgresql.conf, conforme o padrão operacional do ambiente.


3. Resetar senhas antigas


Para cada role que ainda aparece como MD5:

ALTER ROLE nome_da_role PASSWORD 'nova_senha_forte';

Também é possível usar o comando interativo do psql:

\password nome_da_role

O ponto importante é que o reset precisa acontecer enquanto password_encryption estiver como scram-sha-256.


4. Validar a migração


Depois dos resets:

SELECT rolname, rolcanlogin
FROM pg_authid
WHERE rolpassword LIKE 'md5%'
ORDER BY rolname;

O resultado ideal é zero linhas.

Também é útil verificar roles sem senha:

SELECT rolname, rolcanlogin
FROM pg_authid
WHERE rolpassword IS NULL
ORDER BY rolname;

Roles sem senha não são alvo direto desse problema, mas devem ser revisadas para garantir que o modelo de autenticação do ambiente está intencional.


5. Revisar o pg_hba.conf


Quando todos os clientes suportarem SCRAM, prefira entradas com:

scram-sha-256

Exemplo:

host    all     all     10.0.0.0/8      scram-sha-256

Evite manter md5 como método de autenticação por compatibilidade indefinida. A própria documentação do PostgreSQL informa que suporte a senhas MD5 está depreciado e será removido em uma versão futura.


Procedimento operacional recomendado


Checklist para produção:

  1. Inventariar clusters PostgreSQL 14 a 18.
  2. Identificar a versão minor de cada cluster.
  3. Priorizar atualização dos clusters abaixo das versões corrigidas.
  4. Auditar pg_authid em cada cluster.
  5. Gerar lista de roles com rolpassword LIKE 'md5%'.
  6. Validar impacto com aplicações e bibliotecas clientes.
  7. Garantir suporte a SCRAM nos clientes.
  8. Definir janela de troca de senhas para roles afetadas.
  9. Resetar senhas sob password_encryption = 'scram-sha-256'.
  10. Alterar pg_hba.conf para scram-sha-256, quando aplicável.
  11. Recarregar configuração.
  12. Validar que não restaram verifiers MD5.
  13. Registrar evidência da mitigação.

Evidência mínima para documentação interna


Antes:

SELECT version();
SHOW password_encryption;

SELECT rolname, rolcanlogin
FROM pg_authid
WHERE rolpassword LIKE 'md5%'
ORDER BY rolname;

Depois:

SELECT version();
SHOW password_encryption;

SELECT rolname, rolcanlogin
FROM pg_authid
WHERE rolpassword LIKE 'md5%'
ORDER BY rolname;

Critério de aceite:

Versão do PostgreSQL está corrigida.
Nenhuma role com login mantém verifier MD5.
Novas senhas são gravadas como SCRAM-SHA-256.
pg_hba.conf não força MD5 onde SCRAM é suportado.

Conclusão


A CVE-2026-6478 é um bom exemplo de diferença entre configuração desejada e estado real do cluster.

Não basta dizer:

usamos SCRAM

É necessário confirmar:

nenhuma role ainda possui verifier MD5 em pg_authid

A correção efetiva tem duas partes. Primeiro, aplicar o minor release corrigido, porque é ele que fecha o canal lateral de tempo. Segundo, remover o material legado que era alvo da vulnerabilidade, resetando as senhas MD5 sob SCRAM.

Em termos práticos: patch corrige o bug; rotação de senha remove o legado.