Skip to content

Commit e18120b

Browse files
Merge commit from fork
* fix: prevent command injection in ImageMagick handler * fix: prevent command injection in ImageMagick _text() method * add code suggestion from the code review Co-authored-by: John Paul E. Balandan, CPA <[email protected]> * add code suggestion from the code review Co-authored-by: John Paul E. Balandan, CPA <[email protected]> --------- Co-authored-by: John Paul E. Balandan, CPA <[email protected]>
1 parent 90edae6 commit e18120b

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

system/Images/Handlers/ImageMagickHandler.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ public function _resize(bool $maintainRatio = false)
8282
}
8383

8484
$action = $maintainRatio
85-
? ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . ' "' . $source . '" "' . $destination . '"'
86-
: ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . "{$escape}! \"" . $source . '" "' . $destination . '"';
85+
? ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . ' ' . escapeshellarg($source) . ' ' . escapeshellarg($destination)
86+
: ' -resize ' . ($this->width ?? 0) . 'x' . ($this->height ?? 0) . "{$escape}! " . escapeshellarg($source) . ' ' . escapeshellarg($destination);
8787

8888
$this->process($action);
8989

@@ -354,7 +354,7 @@ protected function _text(string $text, array $options = [])
354354

355355
// Font
356356
if (! empty($options['fontPath'])) {
357-
$cmd .= " -font '{$options['fontPath']}'";
357+
$cmd .= ' -font ' . escapeshellarg($options['fontPath']);
358358
}
359359

360360
if (isset($options['hAlign'], $options['vAlign'])) {
@@ -393,28 +393,28 @@ protected function _text(string $text, array $options = [])
393393
$xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis;
394394
$yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis;
395395

396-
$cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}";
396+
$cmd .= ' -gravity ' . escapeshellarg($gravity) . ' -geometry ' . escapeshellarg("{$xAxis}{$yAxis}");
397397
}
398398

399399
// Color
400400
if (isset($options['color'])) {
401401
[$r, $g, $b] = sscanf("#{$options['color']}", '#%02x%02x%02x');
402402

403-
$cmd .= " -fill 'rgba({$r},{$g},{$b},{$options['opacity']})'";
403+
$cmd .= ' -fill ' . escapeshellarg("rgba({$r},{$g},{$b},{$options['opacity']})");
404404
}
405405

406406
// Font Size - use points....
407407
if (isset($options['fontSize'])) {
408-
$cmd .= " -pointsize {$options['fontSize']}";
408+
$cmd .= ' -pointsize ' . escapeshellarg((string) $options['fontSize']);
409409
}
410410

411411
// Text
412-
$cmd .= " -annotate 0 '{$text}'";
412+
$cmd .= ' -annotate 0 ' . escapeshellarg($text);
413413

414414
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
415415
$destination = $this->getResourcePath();
416416

417-
$cmd = " '{$source}' {$cmd} '{$destination}'";
417+
$cmd = ' ' . escapeshellarg($source) . ' ' . $cmd . ' ' . escapeshellarg($destination);
418418

419419
$this->process($cmd);
420420
}

tests/system/Images/ImageMagickHandlerTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,4 +487,65 @@ public function testImageReorientPortrait(): void
487487
$this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb);
488488
}
489489
}
490+
491+
public function testCommandInjectionPrevention(): void
492+
{
493+
$injectionFile = 'ci4_security_test.txt';
494+
$maliciousFilename = 'image.png`echo 123456 | tee ' . $injectionFile . '`';
495+
$tempPath = $this->root . $maliciousFilename;
496+
497+
$source = $this->origin . 'rocket.png';
498+
499+
if (file_exists($injectionFile)) {
500+
unlink($injectionFile);
501+
}
502+
503+
file_put_contents($tempPath, file_get_contents($source));
504+
505+
try {
506+
$this->handler->withFile($tempPath);
507+
$this->handler->resize(50, 50);
508+
} catch (ImageException) {
509+
$this->fail('Command injection succeeded. Fix is incomplete.');
510+
} finally {
511+
// Check that the command injection file was NOT created
512+
$this->assertFileDoesNotExist($injectionFile);
513+
514+
// Verify the image processing still works normally
515+
$this->assertSame(50, $this->handler->getWidth());
516+
$this->assertSame(50, $this->handler->getHeight());
517+
518+
if (file_exists($tempPath)) {
519+
unlink($tempPath);
520+
}
521+
}
522+
}
523+
524+
public function testCommandInjectionPreventionWithText(): void
525+
{
526+
$injectionFile = 'ci4_security_test.txt';
527+
$tempFilename = 'image.png';
528+
$tempPath = $this->root . $tempFilename;
529+
530+
$source = $this->origin . 'rocket.png';
531+
532+
if (file_exists($injectionFile)) {
533+
unlink($injectionFile);
534+
}
535+
536+
file_put_contents($tempPath, file_get_contents($source));
537+
538+
try {
539+
$this->handler->withFile($tempPath);
540+
$text = "Hello'; echo 123456 > {$injectionFile}; echo 'World";
541+
$this->handler->text($text);
542+
} finally {
543+
// Check that the command injection file was NOT created
544+
$this->assertFileDoesNotExist($injectionFile);
545+
546+
if (file_exists($tempPath)) {
547+
unlink($tempPath);
548+
}
549+
}
550+
}
490551
}

user_guide_src/source/changelogs/v4.6.2.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Release Date: Unreleased
1010
:local:
1111
:depth: 3
1212

13+
********
14+
SECURITY
15+
********
16+
17+
- **ImageMagick Handler:** *Command Injection Vulnerability in ImageMagick Handler* was fixed.
18+
See the `Security advisory GHSA-9952-gv64-x94c <https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-9952-gv64-x94c>`_
19+
for more information.
20+
1321
********
1422
BREAKING
1523
********

0 commit comments

Comments
 (0)