Advisory3 min

Vulnérabilités multiples dans InvoicePlane

Jonathan Chambre

Par Jonathan Chambre

Publié le 15 janvier 2026

Read in English
Bulletin de sécurité
Produit
InvoicePlane
Sévérité
High
Versions affectées
≤ 1.6.3
Version corrigée
1.6.4

Introduction

InvoicePlane est une application web open source auto-hébergée conçue pour gérer les devis, les factures, les clients et les paiements. Elle est utilisée par les petites entreprises et les indépendants comme solution de facturation.

Vulnérabilités

Plusieurs vulnérabilités de sécurité ont été identifiées dans InvoicePlane et affectent la version « 1.6.3 ». Elles comprennent une lecture de fichiers non authentifiée, une injection SQL authentifiée et un upload arbitraire de fichiers PHP authentifié, susceptible de conduire à une exécution de code à distance (RCE).

Au moment de la découverte, InvoicePlane ne met pas en œuvre de séparation des rôles : le seul rôle utilisateur disponible est le rôle d'administrateur. Si cela limite les scénarios d'élévation de privilèges, l'impact des vulnérabilités authentifiées reste important en raison du niveau d'accès élevé accordé par défaut.

Chronologie

DateDescription
18/08/2025Signalement des vulnérabilités via le projet GitHub
21/08/2025Réponse de l'éditeur et début des corrections
01/12/2025La v1.6.4-beta-1 corrige les vulnérabilités
06/01/2026Réservation des identifiants CVE

Détails techniques

Lecture de fichiers non authentifiée / CVE-2025-67083

Un attaquant non authentifié peut lire des fichiers présents sur le serveur au moyen d'une vulnérabilité de traversée de répertoire (directory traversal). L'étendue de l'accès aux fichiers dépend de la configuration du serveur web et des permissions du système de fichiers.

L'endpoint vulnérable est le suivant : /guest/get/get_file/<filename>


public function get_file($filename): void
    {
        $filename = urldecode($filename);
        if ( ! file_exists($this->targetPath . $filename)) {
            $ref = isset($_SERVER['HTTP_REFERER']) ? ', Referer:' . $_SERVER['HTTP_REFERER'] : '';
            $this->respond_message(404, 'upload_error_file_not_found', $this->targetPath . $filename . $ref);
        }

        $path_parts = pathinfo($this->targetPath . $filename);
        $file_ext   = mb_strtolower($path_parts['extension'] ?? '');
        $ctype      = $this->content_types[$file_ext] ?? $this->ctype_default;

        $file_size = filesize($this->targetPath . $filename);

        header('Expires: -1');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('Pragma: no-cache');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Type: ' . $ctype);
        header('Content-Length: ' . $file_size);

        readfile($this->targetPath . $filename);
    }

Le paramètre filename est utilisé sans assainissement ni validation appropriés, ce qui permet d'y injecter des séquences de traversée (par exemple ../). Un attaquant peut ainsi accéder à des fichiers arbitraires sur le serveur, sous réserve des restrictions du serveur web.

Cette vulnérabilité peut permettre à des attaquants de lire des fichiers de configuration sensibles, des journaux ou d'autres données applicatives.

Injection SQL authentifiée / CVE-2025-67082

Un utilisateur authentifié peut injecter des commandes SQL arbitraires via des paramètres POST vulnérables de la fonctionnalité de reporting.

Le problème se situe dans le fichier Mdl_reports.php, où les paramètres minQuantity et maxQuantity sont directement intégrés dans une requête SQL sans assainissement approprié ni recours à des requêtes préparées.


$this->db->where('
  (
  SELECT SUM(amounts.invoice_total) FROM ip_invoice_amounts amounts
      WHERE amounts.invoice_id IN
      (
          SELECT inv.invoice_id FROM ip_invoices inv
              WHERE inv.client_id=ip_clients.client_id
                  AND ' . $this->db->escape($from_date) . ' <= inv.invoice_date_created
                  AND ' . $this->db->escape($to_date) . ' >= inv.invoice_date_created
                  AND ' . $minQuantity . ' <=
                  (
                      SELECT SUM(amounts2.invoice_total) FROM ip_invoice_amounts amounts2
                          WHERE amounts2.invoice_id IN
                          (
                              SELECT inv2.invoice_id FROM ip_invoices inv2
                                  WHERE inv2.client_id=ip_clients.client_id
                                      AND ' . $this->db->escape($from_date) . ' <= inv2.invoice_date_created
                                      AND ' . $this->db->escape($to_date) . ' >= inv2.invoice_date_created
                          )
                  )
      )
) <>0');

Ces paramètres n'étant pas traités de manière sûre, un attaquant peut manipuler la requête SQL et potentiellement provoquer :

  • La divulgation d'informations sensibles de la base de données
  • La modification ou la suppression de données
  • Le détournement de fonctionnalités de la base de données selon les permissions

Upload arbitraire de fichiers PHP authentifié / CVE-2025-67084

Un utilisateur authentifié peut téléverser des fichiers PHP arbitraires via la fonctionnalité d'upload de pièces jointes, ce qui conduit à une exécution de code à distance.

Dans le gestionnaire d'upload Upload.php, une vérification du type MIME est partiellement mise en place :


$tempFile = $_FILES['file']['tmp_name'];
if (extension_loaded('fileinfo')) {
    $this->validate_mime_type(mime_content_type($tempFile));
}

Cependant, la fonction s'appuie sur un tableau contenant les types de contenu autorisés, dont text/plain. Il est alors possible de téléverser un fichier PHP tout en déclarant un type MIME anodin tel que text/plain.

Une fois téléversés, ces fichiers PHP peuvent être appelés et exécutés par le serveur, ce qui permet à un attaquant d'exécuter du code arbitraire dans le contexte de l'application web.

Ressources

Continuer la lecture

Parlez-nous de votre projet.

Discutons ensemble de vos besoins et attentes pour vous proposer un service sur mesure.