Laravel Dangerous Function Calls: How to Eliminate eval, shell_exec, and system from Your Codebase
Functions like eval(), shell_exec(), system(), and proc_open() execute arbitrary code. If reachable from user input, they give attackers full server access.
The Problem
Dangerous sink functions — eval(), shell_exec(), system(), exec(), proc_open(), passthru(), and popen() — execute arbitrary system commands or PHP code. If any user input reaches these functions without strict sanitization, an attacker can execute any command on your server: reading files, installing backdoors, or pivoting to other systems. Even indirect paths through variable concatenation or string interpolation create exploitable attack vectors.
How to Fix
-
1
Find all dangerous function calls in your codebase
Search for dangerous functions across your project:
grep -rn 'eval\|shell_exec\|system\|exec\|proc_open\|passthru\|popen\|pcntl_exec' app/ routes/ resources/Also check for backtick operator usage:
grep -rn '`.*\$' app/Document each occurrence and trace whether user input can reach it.
-
2
Replace with safe Laravel alternatives
Laravel provides safe alternatives for most use cases:// Instead of shell_exec('git log') use Symfony\Component\Process\Process; $process = new Process(['git', 'log', '--oneline', '-10']); $process->run();// Instead of exec('convert image.png ...') use Intervention\Image\Facades\Image; Image::make($path)->resize(300, 200)->save();// Instead of eval() for dynamic logic use a strategy pattern, config-driven behavior, or Blade::render()The Symfony Process component is preferred because it uses array arguments, preventing shell injection by design. -
3
If you must use process execution, sanitize strictly
When shell commands are unavoidable, never pass user input directly:
// DANGEROUS shell_exec('ffmpeg -i ' . $request->input('file'));// SAFE — use escapeshellarg for each argument $file = escapeshellarg($validated['file']); shell_exec('ffmpeg -i ' . $file);// SAFEST — use Symfony Process with array arguments use Symfony\Component\Process\Process; $process = new Process(['ffmpeg', '-i', $validated['file']]); $process->setTimeout(60); $process->run();Array-based process execution prevents shell metacharacter injection entirely. -
4
Disable dangerous functions in php.ini
On production servers, disable functions you never need:
; php.ini disable_functions = eval,exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec
Note: Some packages legitimately need exec() or proc_open() (like Symfony Process). Only disable functions your application does not require. Test thoroughly after making changes.
How to Verify
Run the Stackshield scanner:
php artisan stackshield:scan --check=SS003
Manually verify by searching for dangerous functions:
grep -rn 'eval(\|shell_exec(\|system(' app/ --include='*.php'
Any remaining occurrences should be documented with justification and wrapped in strict input validation.
Prevention
Add a PHPStan or Psalm rule to flag dangerous function calls in CI. Use Symfony Process for all external command execution. Never concatenate user input into shell commands. Use StackShield to continuously scan for new dangerous sink introductions.
Frequently Asked Questions
Is escapeshellarg() enough to prevent command injection?
escapeshellarg() prevents most injection attacks by wrapping the argument in single quotes and escaping existing quotes. However, it has edge cases on Windows and doesn't protect against all attack vectors. The Symfony Process component with array arguments is the safest approach.
What about eval() in Blade templates?
Blade compiles to PHP with eval-like behavior internally, but this is safe because template code is developer-controlled. The danger is using eval() directly in controllers or services with user-supplied strings. Never do eval($request->input('code')).
Can attackers exploit shell_exec() if I only pass a filename?
Yes. A filename like "file.png; rm -rf /" contains a shell metacharacter (;) that terminates the first command and starts a new one. Always use escapeshellarg() or array-based Process execution, even for seemingly safe values like filenames.
Related Security Terms
Related Guides
How to Prevent SQL Injection in Laravel
SQL injection vulnerabilities in raw queries and improper Eloquent usage can expose your database. Learn how to write secure queries.
Laravel XSS Prevention Guide: Blade Escaping, {!! !!} Risks & CSP Headers
Prevent cross-site scripting in Laravel. Learn when {!! !!} is safe, how to sanitize HTML input, encode output in Blade templates, and add Content Security Policy headers.
Laravel File Upload Security: How to Validate Type, Size, and Storage Location
File uploads without type or size validation let attackers upload PHP shells, oversized files, or executable scripts that compromise your server.
Detect This Automatically with StackShield
StackShield continuously monitors your Laravel application from the outside and alerts you when security issues are found. No installation required.
Start Free Trial