
Aviso de Segurança: Vazamento de Memória Não Autenticado Leva ao Esgotamento de Memória (TinyWeb)
ID CVE atribuído: CVE-2026-67183
O TinyWeb aloca vários objetos ao analisar cada solicitação e nunca os libera. As estruturas de solicitação e cabeçalho não possuem destrutores, e nada as exclui após o envio da resposta. A memória do worker cresce a cada solicitação e nunca cai, portanto um fluxo constante de solicitações comuns leva o worker a ficar sem memória.
TnyWeb/0.0.8e48f15d (2018-11-20), onde essas estruturas e o analisador foram introduzidos, até a381da2 (2023-11-22, mais recente em master).CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NUm atacante remoto não autenticado que consiga acessar a porta TCP de escuta do servidor (9090 na configuração fornecida) e enviar solicitações a uma taxa sustentada modesta. Não são necessárias credenciais nem interação do usuário. As solicitações podem ser bem formadas; nenhum payload especial é necessário.
Para cada solicitação, HttpParser::execute() aloca um Url, um HttpHeaders e um HttpHeader por linha de cabeçalho:
// src/tiny_http/http_parser.cc:1692
request->url = new Url;
// src/tiny_http/http_parser.cc:1709
request->headers = new HttpHeaders;
// src/tiny_http/http_parser.cc:1033-1040
HttpHeader* header = new HttpHeader;
return_val = parseHeader(stream, offset, len, header);
...
result->generals.push_back(header); // stored in a raw-pointer list
HttpRequest e HttpHeaders são structs simples, sem destrutor; portanto, destruir um HttpRequest não libera nenhum deles:
// src/tiny_http/http_parser.h:442
typedef struct HttpRequest {
...
Url* url;
HttpHeaders* headers;
HttpBody* body;
} HttpRequest;
// src/tiny_http/http_parser.h:279-304
typedef struct HttpHeaders {
...
std::list<HttpHeader*> generals; // raw pointers, never deleted
...
} HttpHeaders;
WebProtocol mantém a solicitação em um std::shared_ptr<HttpRequest> (src/tiny_http/http_protocol.h:49). Quando a próxima solicitação a substitui, o ~HttpRequest padrão é executado e vaza url, headers, body e todos os HttpHeader em generals. O único delete request no código está em getDataFromProxy() (src/tiny_http/http_protocol.cc:194), uma função que o caminho da solicitação nunca chama. Buffers de resposta por solicitação do pool de memória contribuem para o crescimento.
Inicie o servidor com a configuração fornecida (escutando na porta 9090). Anote o ID do processo de um worker.
Registre a memória residente do worker:
grep VmRSS /proc/<worker_pid>/status
for i in $(seq 1 2000); do
curl -s -o /dev/null http://TARGET:9090/
done
VmRSS novamente. Ele cresceu e não cai depois. Uma execução representativa:VmRSS before: 3704 kB
after 500 requests: 4788 kB
after 1000 requests: 22068 kB
after 1500 requests: 41652 kB
after 2000 requests: 59956 kB
O crescimento é monotônico, aproximadamente 20 a 28 kB por solicitação, sem platô. Repetir o lote continua a subida até que o worker seja morto por falta de memória.
Um atacante não autenticado pode esgotar a memória de um worker com um fluxo sustentado de solicitações e forçar uma condição de falta de memória, negando o serviço. O tráfego comum também vaza memória ao longo do tempo, portanto a condição pode ocorrer sem um atacante.
Forneça destrutores a HttpRequest e HttpHeaders que liberem url, headers, body e todos os HttpHeader em generals, ou mantenha-os em smart pointers para que sejam liberados automaticamente. Libere também os buffers do pool de memória por solicitação assim que a resposta for enviada.