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.

Critical severity Application Security Updated 2026-05-01

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. 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. 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. 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. 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

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