VYPR
Critical severityNVD Advisory· Published Jul 28, 2025· Updated Jul 28, 2025

CodeIgniter4's ImageMagick Handler has Command Injection Vulnerability

CVE-2025-54418

Description

CodeIgniter is a PHP full-stack web framework. A command injection vulnerability present in versions prior to 4.6.2 affects applications that use the ImageMagick handler for image processing (imagick as the image library) and either allow file uploads with user-controlled filenames and process uploaded images using the resize() method or use the text() method with user-controlled text content or options. An attacker can upload a file with a malicious filename containing shell metacharacters that get executed when the image is processed or provide malicious text content or options that get executed when adding text to images Users should upgrade to v4.6.2 or later to receive a patch. As a workaround, switch to the GD image handler (gd, the default handler), which is not affected by either vulnerability. For file upload scenarios, instead of using user-provided filenames, generate random names to eliminate the attack vector with getRandomName() when using the move() method, or use the store() method, which automatically generates safe filenames. For text operations, if one must use ImageMagick with user-controlled text, sanitize the input to only allow safe characters and validate/restrict text options.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A command injection in CodeIgniter 4 before 4.6.2 lets attackers execute arbitrary OS commands via malicious filenames or text options when using ImageMagick.

Overview

CVE-2025-54418 is an OS command injection vulnerability in the ImageMagick image processing handler of CodeIgniter 4, affecting versions prior to 4.6.2 [2]. The root cause lies in the framework's failure to properly sanitize user-controlled inputs that are incorporated into shell commands executed by ImageMagick [1]. In particular, the _resize() and _text() methods build command strings by concatenating unfiltered user-supplied data—such as filenames, text content, or options—with shell metacharacters directly into the command line [4].

Exploitation

Requirements

To exploit the vulnerability, an application must use the imagick handler (not the default gd handler) and either allow file uploads with user-controlled filenames that are subsequently processed by the resize() method, or allow user-controlled text or options passed to the text() method [2]. An attacker can craft a filename containing shell metacharacters (e.g., backticks, semicolons, or pipes) when uploading an image, or inject malicious characters into text content/options, causing the injected command to be executed when the image is processed [3]. No authentication is mentioned as a prerequisite; the attack surface is accessible via any feature that feeds user input into these methods.

Impact

Successful exploitation results in arbitrary OS command execution with the privileges of the web server process [1]. This can lead to full compromise of the application and underlying server, including data exfiltration, system takeover, or lateral movement within the network.

Mitigation

The official fix is to upgrade to CodeIgniter 4.6.2 or later, which escapes shell arguments using escapeshellarg() in the affected methods [4]. Two workarounds exist: switch to the GD image handler, which is not vulnerable; or, for file uploads, generate random filenames using getRandomName() or the store() method, and for text operations, sanitize input to allow only safe characters and validate options [2].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
codeigniter4/frameworkPackagist
< 4.6.24.6.2

Affected products

2

Patches

1
e18120bff1da

Merge commit from fork

https://github.com/codeigniter4/CodeIgniter4Michal SniatalaJul 26, 2025via ghsa
3 files changed · +77 8
  • system/Images/Handlers/ImageMagickHandler.php+8 8 modified
    @@ -82,8 +82,8 @@ public function _resize(bool $maintainRatio = false)
             }
     
             $action = $maintainRatio
    -            ? ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . ' "' . $source . '" "' . $destination . '"'
    -            : ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . "{$escape}! \"" . $source . '" "' . $destination . '"';
    +            ? ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . ' ' . escapeshellarg($source) . ' ' . escapeshellarg($destination)
    +            : ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . "{$escape}! " . escapeshellarg($source) . ' ' . escapeshellarg($destination);
     
             $this->process($action);
     
    @@ -354,7 +354,7 @@ protected function _text(string $text, array $options = [])
     
             // Font
             if (! empty($options['fontPath'])) {
    -            $cmd .= " -font '{$options['fontPath']}'";
    +            $cmd .= ' -font ' . escapeshellarg($options['fontPath']);
             }
     
             if (isset($options['hAlign'], $options['vAlign'])) {
    @@ -393,28 +393,28 @@ protected function _text(string $text, array $options = [])
                 $xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis;
                 $yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis;
     
    -            $cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}";
    +            $cmd .= ' -gravity ' . escapeshellarg($gravity) . ' -geometry ' . escapeshellarg("{$xAxis}{$yAxis}");
             }
     
             // Color
             if (isset($options['color'])) {
                 [$r, $g, $b] = sscanf("#{$options['color']}", '#%02x%02x%02x');
     
    -            $cmd .= " -fill 'rgba({$r},{$g},{$b},{$options['opacity']})'";
    +            $cmd .= ' -fill ' . escapeshellarg("rgba({$r},{$g},{$b},{$options['opacity']})");
             }
     
             // Font Size - use points....
             if (isset($options['fontSize'])) {
    -            $cmd .= " -pointsize {$options['fontSize']}";
    +            $cmd .= ' -pointsize ' . escapeshellarg((string) $options['fontSize']);
             }
     
             // Text
    -        $cmd .= " -annotate 0 '{$text}'";
    +        $cmd .= ' -annotate 0 ' . escapeshellarg($text);
     
             $source      = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
             $destination = $this->getResourcePath();
     
    -        $cmd = " '{$source}' {$cmd} '{$destination}'";
    +        $cmd = ' ' . escapeshellarg($source) . ' ' . $cmd . ' ' . escapeshellarg($destination);
     
             $this->process($cmd);
         }
    
  • tests/system/Images/ImageMagickHandlerTest.php+61 0 modified
    @@ -487,4 +487,65 @@ public function testImageReorientPortrait(): void
                 $this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb);
             }
         }
    +
    +    public function testCommandInjectionPrevention(): void
    +    {
    +        $injectionFile     = 'ci4_security_test.txt';
    +        $maliciousFilename = 'image.png`echo 123456 | tee ' . $injectionFile . '`';
    +        $tempPath          = $this->root . $maliciousFilename;
    +
    +        $source = $this->origin . 'rocket.png';
    +
    +        if (file_exists($injectionFile)) {
    +            unlink($injectionFile);
    +        }
    +
    +        file_put_contents($tempPath, file_get_contents($source));
    +
    +        try {
    +            $this->handler->withFile($tempPath);
    +            $this->handler->resize(50, 50);
    +        } catch (ImageException) {
    +            $this->fail('Command injection succeeded. Fix is incomplete.');
    +        } finally {
    +            // Check that the command injection file was NOT created
    +            $this->assertFileDoesNotExist($injectionFile);
    +
    +            // Verify the image processing still works normally
    +            $this->assertSame(50, $this->handler->getWidth());
    +            $this->assertSame(50, $this->handler->getHeight());
    +
    +            if (file_exists($tempPath)) {
    +                unlink($tempPath);
    +            }
    +        }
    +    }
    +
    +    public function testCommandInjectionPreventionWithText(): void
    +    {
    +        $injectionFile = 'ci4_security_test.txt';
    +        $tempFilename  = 'image.png';
    +        $tempPath      = $this->root . $tempFilename;
    +
    +        $source = $this->origin . 'rocket.png';
    +
    +        if (file_exists($injectionFile)) {
    +            unlink($injectionFile);
    +        }
    +
    +        file_put_contents($tempPath, file_get_contents($source));
    +
    +        try {
    +            $this->handler->withFile($tempPath);
    +            $text = "Hello'; echo 123456 > {$injectionFile}; echo 'World";
    +            $this->handler->text($text);
    +        } finally {
    +            // Check that the command injection file was NOT created
    +            $this->assertFileDoesNotExist($injectionFile);
    +
    +            if (file_exists($tempPath)) {
    +                unlink($tempPath);
    +            }
    +        }
    +    }
     }
    
  • user_guide_src/source/changelogs/v4.6.2.rst+8 0 modified
    @@ -10,6 +10,14 @@ Release Date: Unreleased
         :local:
         :depth: 3
     
    +********
    +SECURITY
    +********
    +
    +- **ImageMagick Handler:** *Command Injection Vulnerability in ImageMagick Handler* was fixed.
    +  See the `Security advisory GHSA-9952-gv64-x94c <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-9952-gv64-x94c>`_
    +  for more information.
    +
     ********
     BREAKING
     ********
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.