Prise de contrôle complète de Postiz par tout utilisateur inscrit (CVE-2026-115931, CVE-2026-115932, CVE-2026-115933)
Dans Postiz auto-hébergé 2.23.0 à 2.25.2, tout utilisateur inscrit peut lire les fichiers du serveur ; dans 2.15.0 à 2.25.2, il peut forger des jetons de connexion pour prendre le contrôle d'autres organisations. Corrigé dans 2.25.3.
En bref
- Trois failles critiques de l'application de planification de publications sociales Postiz sont exploitables par tout utilisateur disposant d'un compte ordinaire. Les appels sans restriction aux méthodes des fournisseurs (CVE-2026-115931) et une traversée de répertoires dans les médias (CVE-2026-115932) permettent à cet utilisateur de lire tout fichier accessible au backend, y compris le secret de signature JWT, et de faire planter le backend avec une seule requête. La falsification de jetons à secret partagé (CVE-2026-115933) lui permet de se connecter comme n'importe quel utilisateur ou comme super-administrateur de n'importe quelle organisation. L'équipe de sécurité d'Anthropic a découvert les trois failles ; les avis leur attribuent les scores CVSS v3.1 9.9 (CVE-2026-115931), 9.6 (CVE-2026-115932) et 9.9 (CVE-2026-115933).
- L'inscription libre est ouverte dans la configuration par défaut : l'attaquant n'a donc besoin ni de compte existant, ni de privilège, ni d'action d'un tiers. Toutes les instances affectées sont auto-hébergées. Le dépôt comptait 37 856 étoiles GitHub et 7 395 forks au moment de la rédaction, un indicateur approximatif de l'étendue des déploiements.
- Les trois failles ont été divulguées le 23 octobre 2026 et corrigées en moins d'un jour : la version 2.25.2 corrige la lecture de fichiers (CVE-2026-115931), et la version 2.25.3 corrige la falsification de jetons (CVE-2026-115933) ainsi que la traversée de répertoires des médias (CVE-2026-115932).
- Installez la version 2.25.3 ou ultérieure, puis renouvelez le secret de signature JWT, les identifiants de la base de données et de Redis, ainsi que les clés API de chaque fournisseur connecté. En attendant la mise à jour, définissez
DISABLE_REGISTRATION=trueet bloquezPOST /integrations/extension-refresh.
Suis-je concerné ?
Vous êtes concerné si vous auto-hébergez Postiz (le projet gitroomhq/postiz-app, généralement déployé depuis ses images Docker) et si l'une de ces conditions est remplie :
- Votre instance utilise une version de 2.23.0 à 2.25.1, pour les appels de fonctions sans restriction (CVE-2026-115931), corrigés dans 2.25.2.
- Votre instance utilise une version de 2.23.0 à 2.25.2, pour la traversée de répertoires des médias (CVE-2026-115932), corrigée dans 2.25.3. La version 2.25.2 reste affectée.
- Votre instance utilise une version de 2.15.0 à 2.25.2, pour les jetons signés falsifiés (CVE-2026-115933), corrigés dans 2.25.3.
| Faille | Versions affectées | Version corrigée |
|---|---|---|
| CVE-2026-115931, appels sans restriction aux méthodes des fournisseurs (lecture de fichiers, plantage du backend) | 2.23.0 à 2.25.1 | 2.25.2 (23 octobre 2026) |
| CVE-2026-115932, traversée de répertoires des médias (lecture arbitraire de fichiers transmis à l'attaquant) | 2.23.0 à 2.25.2 | 2.25.3 (24 octobre 2026) |
| CVE-2026-115933, jetons signés falsifiés (session, invitation, réinitialisation de mot de passe, entreprise) | 2.15.0 à 2.25.2 | 2.25.3 (24 octobre 2026) |
Vérifiez la version déployée et si l'inscription libre est ouverte :
docker inspect --format '{{.Config.Image}}' $(docker ps -q --filter name=postiz) # the image tag you run
docker compose config | grep -iE 'image:|DISABLE_REGISTRATION' # compose pin and the registration flag
Si vous avez récupéré une étiquette flottante latest avant le 24 octobre 2026, considérez que l'instance était affectée. L'inscription libre est ouverte sauf si DISABLE_REGISTRATION est explicitement défini sur true, et même si elle est fermée, tout utilisateur existant peut exploiter les trois failles. Deux détails de configuration conditionnent les lectures de fichiers :
- Le Dockerfile de développement et le conteneur fourni exécutent le processus en tant que root : tout fichier lisible par root est donc accessible.
- Le principal chemin de transmission de la traversée de répertoires nécessite un fournisseur Discord configuré, que le docker-compose fourni laisse vide.
Comment corriger le problème ?
Passez à Postiz 2.25.3 ou ultérieur, qui contient les trois correctifs, puis redémarrez le backend et le worker de publication :
- Verrouillez l'image sur
v2.25.3ou une version plus récente dans votre fichier compose, puis exécutezdocker compose pull && docker compose up -d --force-recreatepour recréer les conteneurs avec la version corrigée. - Renouvelez le secret de signature JWT (la variable d'environnement
JWT_SECRET) : avec l'ancien secret, un jeton falsifié par l'attaquant avant la mise à jour resterait valide. Le renouvellement du secret invalide simultanément tous les jetons de session, d'invitation, de réinitialisation de mot de passe et d'entreprise. - Renouvelez les identifiants de la base de données et de Redis ainsi que les clés API de chaque fournisseur connecté, car les avis indiquent que l'environnement qui les contient est lisible via les failles de lecture de fichiers.
- Examinez la liste des utilisateurs pour repérer les comptes que vous n'avez pas créés et la liste des organisations pour repérer des super-administrateurs inattendus, deux traces que la prise de contrôle peut laisser.
Si vous ne pouvez pas effectuer la mise à jour aujourd'hui, trois mesures réduisent l'exposition. Chacune possède une limite indiquée dans les avis :
- Définissez
DISABLE_REGISTRATION=true. Cela supprime l'accès anonyme initial, mais ne protège pas contre les utilisateurs existants. - Bloquez
POST /integrations/extension-refreshau niveau du proxy inverse si vous n'utilisez pas de canaux reposant sur l'extension de navigateur Postiz. Cela supprime le principal chemin de signature pour la falsification de jetons, mais laisse le chemin d'invitation plus restreint. - Laissez l'identifiant client, le secret client et le jeton de bot Discord non définis. Cela supprime le principal chemin d'exfiltration de la traversée de répertoires, mais laisse ses deux autres chemins.
Quelle est la cause profonde ?
Trois contrôles distincts manquent, un par faille, tous dans le traitement des requêtes d'un utilisateur connecté par le backend.
CVE-2026-115931 : le backend exécutait les méthodes des fournisseurs par leur nom sans liste d'autorisation. La route POST /integrations/function reçoit un canal et un nom de fonction, puis appelle cette fonction sur l'objet fournisseur, en lui transmettant le jeton stocké du canal comme premier argument.
Avant le correctif, le seul contrôle vérifiait qu'une méthode portant ce nom existait sur l'objet. Le commit de correction 9383f5be restreint la route aux méthodes enregistrées comme @Tool ou marquées avec un nouveau décorateur @DashboardFunction.
L'une des fonctions internes désormais bloquées lit un fichier dont le chemin arrive dans ce premier argument : un canal dont le jeton stocké est un chemin de fichier transforme donc la route en lecteur de fichiers ; une autre fonction termine le processus backend.
- // @ts-ignore
- if (integrationProvider[body.name]) {
+ if (
+ this._integrationManager.isDashboardCallable(
+ integrationProvider,
+ body.name
+ )
+ ) {
CVE-2026-115933 : un secret de signature unique, aucun marqueur de type de jeton et une route qui signait les données de requête. Postiz signe ses jetons de session, d'invitation, de réinitialisation de mot de passe et d'entreprise avec un secret partagé unique, et ne stocke rien dans le jeton indiquant son type.
La route d'actualisation des identifiants de l'extension de navigateur signait une charge utile JSON provenant de la requête elle-même et stockait le résultat à un emplacement lisible par l'utilisateur demandeur. Celui-ci obtenait ainsi un jeton valablement signé contenant les revendications de son choix.
Le commit de correction a5affe62 cesse de signer les données de requête (AuthService.signJWT devient AuthService.fixedEncryption, « stocké chiffré comme le fait connectSocialMedia, jamais signé »). Il ajoute aussi une distinction entre types de jetons. Chaque route consommant un jeton rejette désormais les charges utiles contenant des champs appartenant à un autre type, comme timeLimit pour les invitations d'équipe et expires pour les réinitialisations de mot de passe.
CVE-2026-115932 : le chemin d'un média était supposé rester dans le répertoire de téléversement. Lorsqu'un post est publié, Postiz traite un chemin de média qui n'est pas une adresse web comme un fichier sur disque. Il ne vérifie pas que le fichier se trouve dans le répertoire de téléversement.
Un utilisateur inscrit pouvait stocker un chemin de média spécialement conçu avec un post et passer les contrôles qui le restreignent normalement. Le worker de publication lisait ensuite le fichier et l'envoyait comme pièce jointe à un serveur Discord contrôlé par l'utilisateur.
Le commit de correction 12db9bd2 rejette les noms de médias contenant / ou \, limite les lectures de fichiers du worker au répertoire de téléversement et fait passer les récupérations d'URL influencées par l'utilisateur par le même client HTTP protégé contre les SSRF que celui des fournisseurs.
Comment les failles sont-elles exploitées ?
Trois chaînes ne nécessitent qu'un compte créé par inscription libre : une lecture de fichiers (CVE-2026-115931), une prise de contrôle par falsification de jetons (CVE-2026-115933) et une exfiltration via les médias (CVE-2026-115932). L'auteur du signalement a démontré chacune de bout en bout sur une version non modifiée au commit 3a7d28b7ad96 :
- La lecture de fichiers (CVE-2026-115931) : s'inscrire, connecter un canal dont le jeton stocké est un chemin de fichier, appeler la fonction interne de lecture via
POST /integrations/functionet recevoir le contenu du fichier sous forme d'octets. La démonstration a renvoyé un fichier situé hors des répertoires de l'application. Elle a aussi lu l'environnement du processus : le secret JWT avec lequel le backend avait démarré, l'adresse de la base de données, la chaîne de connexion Redis et les identifiants des fournisseurs connectés. -
La prise de contrôle (CVE-2026-115933) : obtenir un jeton valablement signé avec les revendications de son choix via la route d'actualisation de l'extension. Le présenter ensuite sous l'une de ces formes :
- Une session pour un autre utilisateur. Il n'est pas nécessaire de connaître son identifiant. Les revendications du jeton servent de filtre de base de données : un objet de filtre correspondant à un autre utilisateur sélectionne donc cet utilisateur.
- Une invitation d'organisation avec un rôle de super-administrateur, pour toute organisation dont un lien partagé d'aperçu de post expose l'identifiant.
- Une réinitialisation de mot de passe pour un utilisateur dont l'identifiant est connu.
- Un jeton de provisionnement entreprise qui accorde à une organisation un abonnement à vie à l'offre la plus élevée.
La démonstration a promu un second utilisateur inscrit librement au rôle de super-administrateur de l'organisation d'un autre utilisateur, puis lu sa clé API. Les jetons falsifiés n'expirent pas et sont indiscernables des jetons authentiques. - L'exfiltration (CVE-2026-115932) : stocker un post dont le chemin de média pointe hors du répertoire de téléversement, le publier et recevoir le fichier octet pour octet comme pièce jointe sur le serveur Discord de l'attaquant. Un second chemin révèle si un chemin existe et peut épuiser la mémoire du backend en pointant vers un fichier de périphérique ; un troisième atteint la même lecture sur les instances utilisant le stockage local.
Quel est le déroulement de l'attaque ?
Un compte inscrit librement sur une instance non corrigée lit le secret de signature des sessions, puis se connecte sous l'identité de son choix.
(ouvert par défaut)"] --> B["Connecter un canal dont le jeton
stocké est un chemin de fichier"] B --> C["POST /integrations/function
appelle la fonction interne de lecture"] C --> D["Le fichier d'environnement est renvoyé
avec le secret de signature JWT"] D --> E["Forger un jeton de session
avec des revendications arbitraires"] E --> F["Se connecter comme n'importe quel utilisateur
ou super-administrateur de toute organisation"]
La faille de falsification de jetons aboutit au même résultat, la connexion comme n'importe quel utilisateur ou super-administrateur de n'importe quelle organisation, sans lecture de fichiers. La traversée de répertoires réalise la même lecture de fichiers et envoie leur contenu à un serveur Discord contrôlé par l'attaquant.
Que peut faire un attaquant ?
Un attaquant peut lire tout fichier accessible au backend, se connecter comme n'importe quel utilisateur ou super-administrateur de n'importe quelle organisation, arrêter le backend avec une requête et déchiffrer les données chiffrées avec le secret partagé. Voici l'ensemble des impacts décrits par les avis :
- Lire tout fichier accessible au processus backend sous forme d'octets bruts, y compris les fichiers binaires. Dans le conteneur fourni exécuté en tant que root, cela couvre tous les fichiers lisibles par root, notamment le fichier d'environnement, les secrets montés et les journaux de l'application.
- Se connecter comme n'importe quel utilisateur, rejoindre n'importe quelle organisation comme super-administrateur, lire sa clé API et sa liste de canaux, et planifier des publications via ses comptes sociaux connectés.
- Réinitialiser le mot de passe de tout utilisateur dont l'identifiant est connu.
- Créer une organisation disposant d'un abonnement à vie à l'offre la plus élevée via le point de terminaison entreprise.
- Arrêter le backend avec une seule requête, répétable après chaque redémarrage, via la fonction de plantage (CVE-2026-115931) ou le chemin d'épuisement de mémoire (CVE-2026-115932).
- Déchiffrer les données que l'application stocke chiffrées avec le même secret que la clé de signature JWT.
Les conditions sont un compte ordinaire (fourni par l'inscription libre sur une instance par défaut), un accès réseau à l'interface web Postiz et, pour le principal chemin d'exfiltration, un fournisseur Discord configuré. Aucun autre utilisateur n'a besoin d'agir et aucun privilège au-delà du compte n'est requis.
Pourquoi le correctif fonctionne-t-il ?
Chaque correctif ajoute le contrôle manquant plutôt que de masquer le problème sur la route.
- Liste d'autorisation des appels de fonctions. Un nom fourni par l'appelant ne peut atteindre que les méthodes déclarées sûres pour un appel depuis le tableau de bord. Aucune fonction interne lisant des fichiers ou terminant le processus n'est accessible par son nom.
- Chiffrement au lieu de signature. La route d'actualisation de l'extension chiffre désormais les données de requête au lieu de les signer : elle ne peut donc plus fournir de signatures valides. La distinction des types de jetons garantit qu'une charge utile signée n'est acceptée que par la route dont elle respecte l'ensemble de champs.
- Validation des chemins de médias. Les noms contenant des séparateurs sont rejetés et les lectures restent dans le répertoire de téléversement : un post stocké ne peut donc pas diriger le worker de publication ailleurs.
Les mêmes correctifs ferment également trois chemins plus restreints nommés dans les avis : le chemin de signature d'invitations, la traversée de répertoires qui révèle l'existence d'un chemin et peut épuiser la mémoire, et la lecture de fichiers du stockage local.
Comment vérifier si j'ai été compromis ?
Aucun indicateur de compromission n'est publié pour ces failles, et aucune exploitation dans la nature n'a été signalée. Effectuez ces vérifications au regard des impacts documentés :
- Examinez la liste des utilisateurs de l'instance pour repérer les comptes créés par inscription libre sans invitation d'un administrateur, et la liste des membres de chaque organisation pour repérer des super-administrateurs inattendus.
- Recherchez parmi les canaux connectés ceux dont le jeton stocké ressemble à un chemin de fichier plutôt qu'à un identifiant de fournisseur, trace de la chaîne de lecture de fichiers.
- Examinez les posts publiés pour repérer les chemins de médias résolus hors du répertoire de téléversement, et auditez les envois de webhooks Discord contenant des pièces jointes que vous n'avez pas envoyées.
- Considérez le secret JWT, les identifiants de la base de données et de Redis ainsi que les clés API de chaque fournisseur connecté comme exposés si l'instance exécutait une version affectée et avait l'inscription ouverte ou au moins un compte utilisateur, puisque tout utilisateur authentifié peut atteindre les failles. Renouvelez-les. Un jeton falsifié ne se distingue pas d'un jeton authentique à l'inspection : le renouvellement est donc la mesure fiable.
Chronologie
- 2026-10-23 17:45 UTC : Anthropic divulgue CVE-2026-115932 et CVE-2026-115933 à Postiz avec des preuves de concept fonctionnelles ; Postiz reproduit les deux en 15 minutes.
- 2026-10-23 19:45 UTC : Anthropic divulgue CVE-2026-115931 avec une preuve de concept fonctionnelle ; Postiz la reproduit et travaille sur les correctifs.
- 2026-10-23 21:33 UTC : Postiz pousse et vérifie le correctif de CVE-2026-115931.
- 2026-10-23 21:59 UTC : Postiz publie 2.25.2 avec le correctif de CVE-2026-115931 et son avis.
- 2026-10-24 12:26 et 13:27 UTC : Postiz pousse et vérifie les correctifs de CVE-2026-115932 et CVE-2026-115933.
- 2026-10-24 14:16 UTC : Postiz publie 2.25.3 avec les deux correctifs et les avis.
- 2026-10-26 : publication de cet article.
FAQ
Les trois failles peuvent-elles être enchaînées ?
Oui, et chacune permet également la prise de contrôle à elle seule. La lecture de fichiers (CVE-2026-115931) et la traversée de répertoires (CVE-2026-115932) exposent chacune le secret de signature JWT, et quiconque le possède peut forger des jetons valides. La falsification de jetons (CVE-2026-115933) produit directement des jetons valablement signés, sans lire préalablement le secret.
Le service Postiz hébergé est-il affecté ?
Les avis concernent le dépôt auto-hébergé postiz-app et donnent ses versions affectées et corrigées. Pour toute offre managée, la version déployée par l'opérateur et son niveau de correctifs déterminent l'exposition. Pour votre propre instance, vérifiez l'image utilisée par vos conteneurs avec docker inspect --format '{{.Config.Image}}' $(docker ps -q --filter name=postiz).
Nous ne pouvons pas mettre à jour aujourd'hui. Qu'est-ce qui réduit le plus l'exposition ?
Fermez l'inscription libre (DISABLE_REGISTRATION=true), bloquez POST /integrations/extension-refresh au niveau du proxy inverse si vous n'utilisez pas l'extension de navigateur et laissez les identifiants du fournisseur Discord non définis. Chaque mesure supprime un chemin, mais aucune n'élimine les failles elles-mêmes ; les utilisateurs existants restent capables d'exploiter les chemins encore ouverts.
Que faut-il renouveler après la mise à jour ?
D'abord le secret de signature JWT, car les jetons falsifiés avant la mise à jour restent valides jusqu'au changement du secret, puis les identifiants de la base de données et de Redis ainsi que les clés API de chaque fournisseur connecté, car les avis indiquent que l'environnement qui les contient est lisible. Le renouvellement du secret entraîne l'invalidation des sessions.
Existe-t-il une preuve de concept publique ?
Aucun code n'est publié. Chaque divulgation à Postiz comprenait une preuve de concept fonctionnelle, et l'auteur du signalement a démontré les trois chaînes de bout en bout sur une version non modifiée, mais les avis décrivent les mécanismes plutôt que de publier des scripts. Aucune exploitation dans la nature n'a été signalée.
Comment ces failles ont-elles été découvertes ?
L'équipe de sécurité d'Anthropic a signalé les trois. Enno Gelhaus a coordonné la divulgation via GAdvisory. Nevo David les a corrigées, et chaque correctif a été vérifié en quelques heures.
Références
- PSA-2026-JNXM56, l'avis CVE-2026-115931 avec le vecteur CVSS v3.1 9.9, la plage affectée, les contournements, les impacts démontrés et la chronologie : https://gadvisory.org/advisories/PSA-2026-JNXM56 (consulté le 26 octobre 2026)
- PSA-2026-YT2HMH, l'avis CVE-2026-115933 avec le vecteur CVSS v3.1 9.9 et les impacts de prise de contrôle : https://gadvisory.org/advisories/PSA-2026-YT2HMH (consulté le 26 octobre 2026)
- PSA-2026-E9AHFV, l'avis CVE-2026-115932 avec le vecteur CVSS v3.1 9.6 et les préconditions de configuration par chemin : https://gadvisory.org/advisories/PSA-2026-E9AHFV (consulté le 26 octobre 2026)
- Les avis GitHub portant les mêmes trois failles, GHSA-h5r5-h782-vqvp, GHSA-9j6f-8rw3-93c4 et GHSA-rmc2-p2gv-m88f : https://github.com/gitroomhq/postiz-app/security/advisories (consulté le 26 octobre 2026)
- Commits de correction : 9383f5be (méthodes de fournisseurs sur liste d'autorisation, CVE-2026-115931), a5affe62 (chiffrement au lieu de signature et distinction des types de jetons, CVE-2026-115933) et 12db9bd (validation des chemins de médias et confinement au répertoire de téléversement, CVE-2026-115932) : https://github.com/gitroomhq/postiz-app/commit/9383f5be4d310c346e33a3748a9a7ded64c96fed, https://github.com/gitroomhq/postiz-app/commit/a5affe62c74e39c1e7ac960d50d8418b807d532c, https://github.com/gitroomhq/postiz-app/commit/12db9bd2f428b628a62809669c3d76297e07750a (consulté le 26 octobre 2026)
- Notes de version Postiz 2.25.2, 23 octobre 2026, corrigeant PSA-2026-JNXM56 : https://github.com/gitroomhq/postiz-app/releases/tag/v2.25.2 (consulté le 26 octobre 2026)
- Notes de version Postiz 2.25.3, 24 octobre 2026, corrigeant PSA-2026-E9AHFV et PSA-2026-YT2HMH : https://github.com/gitroomhq/postiz-app/releases/tag/v2.25.3 (consulté le 26 octobre 2026)
- Le dépôt Postiz, dont les nombres d'étoiles et de forks (37 856 et 7 395 au 26 octobre 2026) servent d'indicateurs de l'étendue des déploiements auto-hébergés : https://github.com/gitroomhq/postiz-app (consulté le 26 octobre 2026)