The 6 most common attack vectors in Laravel
Understanding how attackers get in is the first step to keeping them out.
This chapter covers the six most common attack vectors we’ve identified targeting Laravel applications. Each one has been used in real-world attacks - including critical CVEs discovered in 2024-2026.
Vector 1: Debug mode exploitation
The most embarrassing vulnerability is often the most common: leaving APP_DEBUG=true in production.
CVE-2024-13919 high Reflected XSS in Debug Error Page
laravel/framework Affected: 11.9.0 - 11.35.x When debug mode is enabled, Laravel’s error page is vulnerable to XSS attacks. Attackers can inject malicious scripts that execute in admin browsers.
Why it’s dangerous
When APP_DEBUG=true:
- Full stack traces reveal file paths, database credentials, and environment variables
- Error pages expose your application’s internal structure
- XSS vulnerabilities in the error page allow script injection
- Session data may be visible in debug output
The attack
- Attacker triggers an error (malformed input, missing route)
- Debug page reveals sensitive information
- With XSS, attacker can steal admin session cookies
- Full application compromise follows
Detection
Check your production environment:
// .env (WRONG - in production)
APP_ENV=production
APP_DEBUG=true // NEVER do this!
// This combination is actively dangerous
// CVE-2024-13919 makes this exploitable Fix
# In production .env
APP_DEBUG=false
APP_ENV=production
Vector 2: Livewire hydration smuggling
This is the most critical Laravel ecosystem vulnerability discovered in recent years.
CVE-2025-54068 critical Remote Code Execution via Hydration Smuggling
livewire/livewire Affected: 3.0.0 - 3.6.3 Unauthenticated attackers can achieve RCE by manipulating Livewire’s JSON payload during the hydration process. No authentication required.
CVSS 9.8 - Maximum Severity
This vulnerability allows unauthenticated remote code execution. If you’re running Livewire 3.0-3.6.3, you are vulnerable RIGHT NOW. There is no workaround except updating.
How it works
Livewire components serialize their state to JSON for client-server communication. The vulnerability exists in how this data is deserialized (hydrated):
- Attacker crafts malicious JSON payload
- Payload contains serialized PHP objects
- During hydration, these objects are unserialized
- Gadget chains execute arbitrary code
Attack indicators
Watch for these in your logs:
- Unusual Livewire component requests
- Malformed JSON in
wire:snapshot - Unexpected object types in hydration errors
__PHP_Incomplete_Classin error messages
Fix
composer require livewire/livewire:^3.6.4
Vector 3: Environment variable injection
A subtle but devastating attack that exploits PHP’s register_argc_argv setting.
CVE-2024-52301 high Environment Injection via Query String
laravel/framework Affected: Multiple versions (see below) When register_argc_argv=On in PHP, attackers can manipulate Laravel’s
environment variables through URL query strings.
The Attack
When register_argc_argv is enabled (default on many systems):
https://yoursite.com/?APP_ENV=local&APP_DEBUG=true
This query string can override your environment variables, enabling debug mode or changing the application environment.
Affected versions
| Laravel Version | Patched Version |
|---|---|
| 6.x | 6.20.45 |
| 7.x | 7.30.7 |
| 8.x | 8.83.28 |
| 9.x | 9.52.17 |
| 10.x | 10.48.23 |
| 11.x | 11.31.0 |
Detection
// Check PHP configuration
if (ini_get('register_argc_argv') === '1') {
echo "VULNERABLE: register_argc_argv is enabled";
} Fix
Two options:
- Update Laravel to patched versions
- Disable in php.ini:
register_argc_argv = Off
Vector 4: Laravel pulse RCE
If you use Laravel Pulse for monitoring, this one’s for you.
CVE-2024-55661 critical RCE via Public remember() Method
laravel/pulse Affected: < 1.3.1 The remember() method in Pulse’s Livewire trait was publicly accessible,
allowing cache poisoning and remote code execution.
The attack
- Attacker accesses Pulse dashboard (often unprotected)
- Exploits public
remember()method - Injects malicious cached data
- Cached data executes on subsequent requests
Fix
composer require laravel/pulse:^1.3.1
Also ensure Pulse access is restricted:
// In PulseServiceProvider or Gate
Gate::define('viewPulse', function ($user) {
return $user->isAdmin();
}); Vector 5: File upload exploitation
The attack vector we experienced firsthand. Twice.
Why Laravel apps are vulnerable
Laravel makes file uploads easy - sometimes too easy:
// DANGEROUS: No extension validation
public function upload(Request $request)
{
$request->validate([
'file' => 'required|file|max:2048|mimes:jpg,png'
]);
// mimes only checks MIME type, not extension!
$path = $request->file('file')->store('public/uploads');
} The mimes rule checks the file’s MIME type, which can be forged. An attacker can upload shell.php with a forged image/jpeg MIME type.
The safe way
public function upload(Request $request)
{
$request->validate([
'file' => [
'required',
'file',
'max:2048',
// Check actual extension
function ($attribute, $value, $fail) {
$ext = strtolower($value->getClientOriginalExtension());
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
if (!in_array($ext, $allowed)) {
$fail('Invalid file type.');
}
// Also block PHP
if (in_array($ext, ['php', 'phtml', 'php3', 'php4', 'php5', 'phar'])) {
$fail('PHP files are not allowed.');
}
},
],
]);
// Generate safe filename
$safeName = Str::uuid() . '.' . $request->file('file')
->getClientOriginalExtension();
$path = $request->file('file')->storeAs('uploads', $safeName);
} Critical: Block PHP in upload directories
Add .htaccess to prevent PHP execution:
# storage/app/public/.htaccess
<FilesMatch "\.php$">
Deny from all
</FilesMatch>
# Or completely disable PHP
php_flag engine off
Vector 6: APP_KEY Deserialization
If your APP_KEY leaks, it’s game over.
Why APP_KEY matters
Laravel uses APP_KEY to:
- Encrypt cookies and session data
- Sign data with
encrypt()anddecrypt() - Generate secure tokens
The attack chain
- Attacker obtains
APP_KEY(from exposed.env, git history, error pages) - Crafts malicious serialized PHP object
- Encrypts it with the stolen key
- Sends encrypted payload as cookie or input
- Laravel decrypts and unserializes it
- Gadget chain executes arbitrary code
APP_KEY Compromise = Full RCE
If your APP_KEY is exposed, attackers can execute arbitrary code on your server using known gadget chains (phpggc). There is no mitigation except rotating the key.
Attack pattern detection
// Attacker uses decrypt() with user input
$payload = decrypt($_POST['data']); // DANGEROUS!
// Or unserializes decrypted data
$data = unserialize(decrypt($input)); // CRITICAL! Prevention
-
Never commit
.envto git# .gitignore .env .env.backup .env.production -
Check git history for leaks
git log -p --all -S 'APP_KEY' -
Rotate keys if compromised
php artisan key:generate # Then invalidate all sessions -
Never pass encrypted user input to unserialize()
Summary: The 6 Vectors
| # | Vector | CVE | Severity | Key Defense |
|---|---|---|---|---|
| 1 | Debug Mode | CVE-2024-13919 | HIGH | APP_DEBUG=false in production |
| 2 | Livewire Hydration | CVE-2025-54068 | CRITICAL | Update to Livewire 3.6.4+ |
| 3 | Environment Injection | CVE-2024-52301 | HIGH | register_argc_argv=Off |
| 4 | Pulse RCE | CVE-2024-55661 | CRITICAL | Update Pulse, restrict access |
| 5 | File Upload | N/A | HIGH | Validate extensions, block PHP |
| 6 | APP_KEY Leak | N/A | CRITICAL | Never expose, rotate if leaked |
Are You Vulnerable?
Right now, ask yourself:
- Is my Livewire version 3.6.4 or higher?
- Is APP_DEBUG set to false in production?
- Is my APP_KEY safe and uncompromised?
- Can PHP files execute in my upload directories?
If you answered “no” or “I don’t know” to any of these, you’re at risk.
Next: Chapter 4 - The 87 Signatures: A Deep Dive into PHP Malware →
In the next chapter, we’ll examine the specific malware patterns attackers use - the 87 signatures our research identified targeting PHP and Laravel applications.