Container Escape in Laravel (Php)
Container Escape in Laravel with Php — how this specific combination creates or exposes the vulnerability
In Laravel applications, container escape vulnerabilities often arise when user-controlled input is used to instantiate or resolve classes via the service container without proper validation. Laravel's service container is a powerful dependency injection tool, but if developers pass unsanitized input directly into app()->make() or resolve(), attackers can manipulate the container to instantiate arbitrary classes, potentially leading to object injection, remote code execution, or escape from intended application boundaries.
For example, consider a route that dynamically resolves a controller based on user input:
// routes/web.php
Route::get('/process/{controller}', function ($controller) {
$instance = app()->make($controller); // Dangerous: user input passed directly
return $instance->handle();
});
If an attacker supplies a value like App\\Http\\Controllers\\UserController, it may work as intended. However, if they supply System or a fully qualified class like Symfony\\Component\\Process\\Process, and the class has a constructor that accepts dangerous arguments, the container will attempt to instantiate it. Combined with PHP's magic methods (__construct, __destruct, __wakeup), this can lead to object injection chains.
This becomes a container escape when the resolved class has access to dangerous functionality (e.g., file system, network, or shell execution) and the attacker can control its dependencies via constructor injection. Laravel’s container will automatically resolve dependencies using type-hinted constructor arguments, which an attacker might manipulate if those dependencies are also user-influenced.
Such flaws map to OWASP API Security Top 10: 2023 - API1:2023 Broken Object Level Authorization (BOLA) and API8:2023 Security Misconfiguration, especially when combined with poor input validation. They also relate to CWE-94: Improper Control of Generation of Code ('Code Injection') and CWE-502: Deserialization of Untrusted Data when object injection leads to code execution.
middleBrick detects these risks during its Property Authorization and Input Validation checks by analyzing whether user input flows into container resolution methods without validation. It also checks for patterns indicative of unsafe class instantiation in unauthenticated endpoints, providing findings with severity ratings and remediation guidance.
Php-Specific Remediation in Laravel — concrete code fixes
To prevent container escape vulnerabilities in Laravel, developers must never pass unsanitized user input directly into the service container. Instead, use explicit validation, whitelisting, or dependency injection with known-safe types.
Replace dynamic resolution with a mapped approach:
// routes/web.php - Safe version
Route::get('/process/{type}', function ($type) {
$controllers = [
'user' => App\\Http\\Controllers\\UserController::class,
'order' => App\\Http\\Controllers\\OrderController::class,
];
if (!array_key_exists($type, $controllers)) {
abort(404, 'Invalid controller type');
}
$instance = app()->make($controllers[$type]);
return $instance->handle();
});
This ensures only predefined, safe classes can be resolved. If dynamic resolution is absolutely necessary, validate the input against a strict allowlist of allowed namespaces or classes:
// app/Http/Middleware/ValidateController.php
public function handle($request, Closure $next)
{
$controller = $request->route('controller');
$allowedPrefix = 'App\\Http\\Controllers\\';
if (str_starts_with($controller, $allowedPrefix) && class_exists($controller)) {
return $next($request);
}
return response()->json(['error' => 'Invalid controller'], 400);
}
Additionally, avoid using user input in constructor arguments that are resolved by the container. If a class requires external dependencies, inject them explicitly or use factory patterns:
// app/Services/ReportGenerator.php
class ReportGenerator
{
public function __construct(private PdfGenerator $pdf) {}
public function generate($data)
{
// Safe: $pdf is type-hinted and resolved by container
return $this->pdf->createFromData($data);
}
}
Never allow user input to influence the instantiation of classes with dangerous capabilities (e.g., PDO, Symfony\\Component\\Process\\Process, Illuminate\\Support\\Facades\\Artisan). Apply the principle of least privilege: containers should only resolve classes that are strictly necessary for the request.
middleBrick’s Input Validation and Property Authorization checks help identify risky patterns like direct user input in app()->make() calls. Its CLI (middlebrick scan https://api.example.com) and GitHub Action can be used to catch these issues early in development, ensuring that container escape risks are flagged before deployment.
Frequently Asked Questions
Can Laravel’s automatic dependency injection prevent container escape attacks?
Is using <code>app()->bind()</code> with user input safer than <code>app()->make()</code>?
make(), bind(), or singleton(). Always validate and whitelist inputs before using them in any container operation.