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:
- PostgreSQL Security: CVE-2026-6478
- PostgreSQL Release: 18.4, 17.10, 16.14, 15.18 e 14.23
- Documentação: Password Authentication
- Documentação: pg_authid
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 é:
- A empresa usava PostgreSQL 13 ou anterior.
- Existiam roles com senha gravada em MD5.
- O cluster foi atualizado para PostgreSQL 14, 15, 16, 17 ou 18.
- A configuração foi alterada para usar SCRAM.
- 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:
- Escolher uma role alvo que possa tentar autenticar.
- Enviar tentativas de autenticação cuidadosamente controladas.
- Medir o tempo de resposta de cada tentativa.
- Repetir muitas vezes para reduzir ruído.
- Comparar distribuições de tempo entre candidatos.
- Inferir qual candidato parece provocar uma comparação mais longa.
- 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:
- A versão do PostgreSQL é anterior à versão corrigida.
- Existem roles com
rolpasswordcomeçando commd5. - 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 é:
- Atualizar o PostgreSQL para a versão corrigida.
- Auditar roles com senha MD5.
- Resetar essas senhas com
password_encryption = 'scram-sha-256'. - Ajustar
pg_hba.confpara SCRAM quando possível. - 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:
- Inventariar clusters PostgreSQL 14 a 18.
- Identificar a versão minor de cada cluster.
- Priorizar atualização dos clusters abaixo das versões corrigidas.
- Auditar
pg_authidem cada cluster. - Gerar lista de roles com
rolpassword LIKE 'md5%'. - Validar impacto com aplicações e bibliotecas clientes.
- Garantir suporte a SCRAM nos clientes.
- Definir janela de troca de senhas para roles afetadas.
- Resetar senhas sob
password_encryption = 'scram-sha-256'. - Alterar
pg_hba.confparascram-sha-256, quando aplicável. - Recarregar configuração.
- Validar que não restaram verifiers MD5.
- 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.