CONNECT por HTTP/2 ou HTTP/3 devolve conexão contaminada ao pool compartilhado
O proxy HTTP padrão do Traefik encaminha um CONNECT recebido por HTTP/2 ou HTTP/3 como uma requisição comum, com o corpo ainda em fluxo. O corpo é escrito na conexão do backend depois do cabeçalho do CONNECT, sem Content-Length e sem Transfer-Encoding. Quando o backend responde com um código de erro que mantém a conexão viva e não consome esses bytes, o net/http considera a requisição encerrada, devolve o socket ao pool compartilhado e deixa a resposta da requisição embutida pendente. Outro cliente que reutilize o mesmo socket recebe essa resposta alheia, que pode conter conteúdo autenticado ou privado de outro usuário, ou uma resposta escolhida pelo atacante.
Casos de uso afetados
- Você aceita HTTP/2 ou HTTP/3 em um entrypoint e encaminha as requisições para um backend HTTP/1.1 com keep-alive, como um serviço Go net/http ou gunicorn com Flask. O backend responde ao CONNECT com 405 e mantém a conexão aberta, o que deixa o socket disponível para outro cliente.
- Você mantém o pool padrão do Traefik com MaxIdleConnsPerHost em 200. Com um endpoint lento escolhido pelo atacante, a resposta embutida chega depois de o socket voltar ao pool e o próximo cliente lê o conteúdo no lugar da própria resposta.
- Você opera uma API com áreas autenticadas atrás do mesmo backend. Um cliente sem credenciais pode receber a resposta de uma sessão alheia sem credencial própria.
Confira na sua instância
Confira a versão do Traefik nos entrypoints que aceitam HTTP/2 ou HTTP/3 com TLS. Identifique os backends HTTP/1.1 que mantêm a conexão viva depois de um erro em CONNECT: servidores Go net/http e gunicorn com Flask respondem com erro e preservam o socket, enquanto Apache e nginx fecham a conexão nesse caminho. Examine nos logs do backend requisições CONNECT seguidos de requisições encadeadas na mesma conexão. Após atualizar para 2.11.53, 3.6.24 ou 3.7.9 conforme a linha, repita um CONNECT em ambiente de teste e confirme que a conexão não retorna ao pool. Desative a reutilização de conexões do backend durante a preparação da atualização.
Versões afetadas e correções
| Linha | Afetadas | Corrigidas |
|---|---|---|
| 2.x | <= v2.11.52 | v2.11.53 |
| 3.0 a 3.6 | >= v3.0.0, <= v3.6.23 | v3.6.24 |
| 3.7.x | >= v3.7.0, <= v3.7.8 | v3.7.9 |
A opção sanitizePath reescreve o alvo do CONNECT para /, mas o resultado depende do backend. Apache e nginx fecham a conexão nesse formato e evitam o encadeamento; servidores Go net/http e gunicorn com Flask respondem com erro e mantêm o socket, o que preserva a falha. O FastProxy experimental envia o corpo em chunks e não é afetado. A falha também alcança o ForwardAuth com forwardBody e preserveRequestMethod ativados, que reenvia o corpo ao servidor de autenticação pelo mesmo caminho.
