Skip to content

Commit 26a9bef

Browse files
committed
fix(security): Force Imagick to only accept HEIC/HEIF images
Signed-off-by: Fabian Zwemke <fabian@zwemke.de>
1 parent 3d9c47f commit 26a9bef

3 files changed

Lines changed: 75 additions & 5 deletions

File tree

lib/private/Preview/HEIC.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,15 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
100100
private function getResizedPreview($tmpPath, $maxX, $maxY) {
101101
$bp = new \Imagick();
102102

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

111110
// Layer 0 contains either the bitmap or a flat representation of all vector layers
112-
$bp->readImage($tmpPath . '[0]');
111+
$bp->readImage('heic:' . $tmpPath . '[0]');
113112

114113
// Fix orientation from EXIF
115114
$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: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
$this->width = 1680;
27+
$this->height = 1050;
28+
$this->provider = new HEIC;
29+
}
30+
}
31+
32+
/**
33+
* Launches all the tests we have
34+
*
35+
*
36+
* @param int $widthAdjustment
37+
* @param int $heightAdjustment
38+
*/
39+
#[\PHPUnit\Framework\Attributes\DataProvider('dimensionsDataProvider')]
40+
#[\PHPUnit\Framework\Attributes\RequiresPhpExtension('imagick')]
41+
public function testGetThumbnail($widthAdjustment, $heightAdjustment): void {
42+
# HEIC->getThumbnail will always return null if there is an exception, be we want to check why getResizedPreview fails
43+
$reflection = new \ReflectionClass($this->provider);
44+
$method = $reflection->getMethod('getResizedPreview');
45+
$method->setAccessible(true);
46+
47+
$absolutePath = \OC::$SERVERROOT . '/tests/data/' . 'testimage-disguised-svg.heic';
48+
49+
try {
50+
$method->invoke(
51+
$this->provider,
52+
$absolutePath,
53+
$this->width,
54+
$this->height
55+
);
56+
$this->fail('Expected ImagickException was not thrown.');
57+
} catch (\ImagickException $e) {
58+
$this->assertStringStartsWith('ImageTypeNotSupported', $e->getMessage());
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)