TL;DR
Two high-severity issues affect Laravel 13: a temporary signed URL path confusion bug (affects 13.0.0–13.11.x; fixed in 13.12.0) and a CRLF injection in the default email validation rule (affects 13.0.0–13.9.x; fixed in 13.10.0). If you use Laravel 13, upgrade to at least the fixed versions immediately. The most conservative move is to go to 13.12.0 or later. Your next scheduled FrameScan run already checks for these and will alert you if affected.
At-a-glance
| ID | Impact | Severity | Affected versions | Fixed version |
|---|---|---|---|---|
| GHSA-crmm-hgp2-wgrp | Signed links can be misrouted | high | >=13.0.0,<13.12.0 | 13.12.0 |
| GHSA-5vg9-5847-vvmq | Email validation allows CRLF injection | high | >=13.0.0,<13.10.0 | 13.10.0 |
GHSA-crmm-hgp2-wgrp — Laravel Framework: Temporary Signed URL Path Confusion
An attacker could cause a signed link to resolve to an unintended path, potentially bypassing protections tied to the expected URL. This can lead to unauthorized access to actions gated by temporary or signed links. Treat this as high priority for apps relying on signed routes for account or resource access.
Technical details
Advisory summary: Temporary Signed URL Path Confusion in laravel/framework. The risk comes from discrepancies between what is signed and what is later matched or resolved. The fix ensures the signature correctly binds to the intended path and parameters.
Illustrative example — not laravel/framework source:
<?php
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
// Vulnerable pattern (illustrative): concatenating path segments after signing
// The signature covers the base URL, but not a later-added segment.
Route::get('/download/{file}', function (Request $request, string $file) {
$base = URL::temporarySignedRoute('secure.download.base', now()->addMinutes(10));
// Anti-pattern: appending user-controlled path after signing
return redirect($base . '/' . ltrim($file, '/'));
})->name('download');
// Fixed pattern: include every variable path component in the signature
Route::get('/secure-download/{file}', function (Request $request, string $file) {
// Sign the exact route with all parameters
$url = URL::temporarySignedRoute('secure.download', now()->addMinutes(10), [
'file' => $file,
]);
return redirect($url);
})->name('secure.download');
// On the receiving end, enforce validation of the signature
Route::get('/secure-download/{file}', function (Request $request, string $file) {
// Request only proceeds if signature is valid
return response()->download(storage_path('app/' . $file));
})->middleware('signed')->name('secure.download');
The fixed approach signs the full, intended route and uses the signed middleware to reject tampered paths.
GHSA-5vg9-5847-vvmq — Laravel Framework: CRLF injection in default email rule
If a crafted value passes the default email validation and is later used in email-related contexts, newline characters could allow header injection. That can lead to spoofed headers or unintended recipients. Prioritize updating if you validate user emails and pass them to mailers.
Technical details
Advisory summary: CRLF injection in the default email rule in laravel/framework. The issue centers on the validator allowing carriage return/line feed characters, which can break email header boundaries. The fixed version tightens validation to block such control characters.
Illustrative example — not laravel/framework source:
<?php
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Mail;
use Illuminate\Http\Request;
// Before: relying on a permissive rule and passing value to mail headers
function sendInvite(Request $request): void {
$data = $request->only(['email']);
// Potentially permissive validation
$validator = Validator::make($data, [
'email' => ['required', 'email'],
]);
if ($validator->fails()) {
abort(422, 'Invalid email');
}
// Risk: using un-sanitized value directly in headers
Mail::raw('Welcome!', function ($message) use ($data) {
$message->to($data['email']);
});
}
// After: upgraded framework (13.10.0+) rejects CRLF; additionally sanitize defensively
function sendInviteSafe(Request $request): void {
$data = $request->only(['email']);
// Stricter validation remains illustrative; rely primarily on the fixed framework
$validator = Validator::make($data, [
'email' => ['required', 'email'],
]);
if ($validator->fails()) {
abort(422, 'Invalid email');
}
// Defensive hardening: strip control chars before use
$cleanEmail = preg_replace("/[\r\n]+/", '', $data['email']);
Mail::raw('Welcome!', function ($message) use ($cleanEmail) {
$message->to($cleanEmail);
});
}
Upgrading to the fixed version closes the validator gap; the additional sanitation is a belt-and-suspenders measure.
Remediation
- laravel/framework GHSA-crmm-hgp2-wgrp: update to 13.12.0
- Composer:
composer require laravel/framework:13.12.0 - Advisory: https://github.com/laravel/framework/security/advisories/GHSA-crmm-hgp2-wgrp
- laravel/framework GHSA-5vg9-5847-vvmq: update to 13.10.0 or newer
- Composer:
composer require laravel/framework:13.10.0 - Advisory: https://github.com/laravel/framework/security/advisories/GHSA-5vg9-5847-vvmq
If you are on Laravel 13 and affected by both ranges, upgrading directly to 13.12.0 satisfies both fixes.
Call to action
- Existing customers: run or schedule your scan at https://framescan.io/scan
- New to FrameScan: your first scan per verified domain is free — start at https://framescan.io/#pricing