Skip to content

Commit 52cc349

Browse files
committed
fix(security): Force Imagick to only accept HEIC/HEIF images
Signed-off-by: Fabian Zwemke <[email protected]>
1 parent ca245b4 commit 52cc349

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

lib/private/Preview/HEIC.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
6565
'app' => 'core',
6666
]
6767
);
68+
if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
69+
throw $e;
70+
}
6871
return null;
6972
}
7073

@@ -96,16 +99,15 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
9699
private function getResizedPreview($tmpPath, $maxX, $maxY) {
97100
$bp = new \Imagick();
98101

99-
// Some HEIC files just contain (or at least are identified as) other formats
100-
// like JPEG. We just need to check if the image is safe to process.
101-
$bp->pingImage($tmpPath . '[0]');
102+
// Force Imagick to only accept HEIC or HEIF images
103+
$bp->pingImage('heic:' . $tmpPath . '[0]');
102104
$mimeType = $bp->getImageMimeType();
103-
if (!preg_match('/^image\/(x-)?(png|jpeg|gif|bmp|tiff|webp|hei(f|c)|avif)$/', $mimeType)) {
105+
if (!preg_match('/^image\/(x-)?hei(f|c)$/', $mimeType)) {
104106
throw new \Exception('File mime type does not match the preview provider: ' . $mimeType);
105107
}
106108

107109
// Layer 0 contains either the bitmap or a flat representation of all vector layers
108-
$bp->readImage($tmpPath . '[0]');
110+
$bp->readImage('heic:' . $tmpPath . '[0]');
109111

110112
// Fix orientation from EXIF
111113
$bp->autoOrient();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<svg
3+
xmlns:svg="http://www.w3.org/2000/svg"
4+
xmlns="http://www.w3.org/2000/svg"
5+
xmlns:xlink="http://www.w3.org/1999/xlink"
6+
style="overflow: hidden; position: relative;"
7+
width="500"
8+
height="500">
9+
<image x="0" y="0" width="500" height="500" xlink:href="/var/www/html/secret.png" stroke-width="1" id="image3204" />
10+
</svg>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
8+
namespace Test\Preview;
9+
10+
use OC\Preview\HEIC;
11+
12+
/**
13+
* Class HEICDisguisedSVGTest
14+
*
15+
*
16+
* @package Test\Preview
17+
*/
18+
#[\PHPUnit\Framework\Attributes\Group('DB')]
19+
class HEICDisguisedSVGTest extends Provider {
20+
protected function setUp(): void {
21+
if (!in_array('HEIC', \Imagick::queryFormats('HEI*'))) {
22+
$this->markTestSkipped('ImageMagick is not HEIC aware. Skipping tests');
23+
} else {
24+
parent::setUp();
25+
26+
$fileName = 'testimage-disguised-svg.heic';
27+
$this->imgPath = $this->prepareTestFile($fileName, \OC::$SERVERROOT . '/tests/data/' . $fileName);
28+
$this->width = 1680;
29+
$this->height = 1050;
30+
$this->provider = new HEIC;
31+
}
32+
}
33+
34+
/**
35+
* Launches all the tests we have
36+
*
37+
*
38+
* @param int $widthAdjustment
39+
* @param int $heightAdjustment
40+
*/
41+
#[\PHPUnit\Framework\Attributes\DataProvider('dimensionsDataProvider')]
42+
#[\PHPUnit\Framework\Attributes\RequiresPhpExtension('imagick')]
43+
public function testGetThumbnail($widthAdjustment, $heightAdjustment): void {
44+
try {
45+
parent::testGetThumbnail($widthAdjustment, $heightAdjustment);
46+
$this->fail('Expected ImagickException was not thrown.');
47+
} catch (\ImagickException $e) {
48+
$this->assertStringStartsWith('ImageTypeNotSupported', $e->getMessage());
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)