Dokploy : RCE sur l'hôte depuis un compte membre
Un membre Dokploy peut mettre un backtick dans un mot de passe de base de données et exécuter des commandes en root sur l'hôte ; le correctif est sur canary.
En bref
- Un membre Dokploy autorisé à créer un service de base de données peut exécuter des commandes en root sur l'hôte. Le moyen est un backtick dans un mot de passe, ou un point-virgule dans le nom d'utilisateur.
- Dokploy v0.29.0 à v0.31.0 est concerné, et v0.31.0, publié le 5 novembre 2026, est la version vulnérable actuelle. L'attaquant a besoin d'un compte membre avec la permission de création de service ; ce n'est pas une faille non authentifiée.
- Aucune CVE ni score CVSS n'est attribué à ce problème. Le chercheur rapporte une preuve en direct contre l'image officielle v0.31.0 et note que Dokploy a noté 9,9 la même classe de précondition dans CVE-2026-72868. Il ne figure pas au catalogue Known Exploited Vulnerabilities (KEV) de la CISA au 10 novembre 2026.
- Le correctif est sur canary, pas dans une version étiquetée. Retirez la permission de création de service aux membres non fiables dès maintenant, puis appliquez le correctif ou attendez une version. Voir « Comment corriger ? ».
Suis-je concerné ?
Toutes ces conditions doivent être réunies :
- Vous exécutez Dokploy auto-hébergé v0.29.0 à v0.31.0. Le validateur de mot de passe vulnérable a été introduit dans v0.29.0 et le chercheur indique qu'il est inchangé sur toutes les branches.
- Vous accordez à un membre de l'organisation la permission de création de service et l'accès à un service de base de données. Les procédures
changePasswordde Dokploy vérifientservice: ["create"]avant d'exécuter la commande de base de données. - Le membre peut atteindre le panneau. Dans une installation à administrateur unique, il n'y a pas de frontière à franchir, car l'administrateur détient déjà la permission.
Le chercheur a testé l'image officielle dokploy/dokploy v0.31.0 et rapporte une preuve en direct. Le correctif est la fusion du commit 1c862c9cb0 de la pull request #5910 sur la branche canary, fusionnée le 9 novembre 2026 à 16:59 UTC. Les étiquettes de version s'arrêtent à v0.31.0.
| Branche | Versions concernées | Version corrigée |
|---|---|---|
| Dokploy auto-hébergé | v0.29.0 à v0.31.0 | Aucune version étiquetée au 10 novembre 2026 ; le correctif est sur canary dans la pull request #5910 |
Vérifiez l'image et la version en cours :
docker inspect --format '{{.Config.Image}}' dokploy
docker images dokploy/dokploy
Le panneau affiche aussi sa version dans l'interface. Une image étiquetée v0.29.0 à v0.31.0 est concernée. Une version canary qui inclut la pull request #5910 a le correctif, mais ce n'est pas une version publiée.
Comment corriger ?
Il n'y a pas encore de version corrigée. Le correctif est fusionné sur canary, alors choisissez l'une de ces voies :
- Construisez ou récupérez une image Dokploy qui contient le commit canary de la pull request #5910, puis redéployez le panneau. Confirmez que la construction inclut l'appel
quote()dans les routeurs de base de données avant de vous y fier. - Si vous ne pouvez pas exécuter une version canary, appliquez le même changement à votre construction : chaque argument après
docker exec <container>passe parquote()du paquetshell-quote. - Tant que le panneau n'est pas corrigé, retirez la permission de création de service à chaque membre qui n'en a pas besoin. Traitez un membre qui peut créer une base de données comme équivalent à root sur l'hôte.
- Limitez l'accès au panneau Dokploy aux réseaux de confiance, et ne l'exposez pas directement à Internet.
- Examinez le journal d'audit pour les changements de mot de passe que vous ne pouvez pas justifier. Faites tourner les identifiants de base de données si vous en trouvez.
- Surveillez une version étiquetée de Dokploy qui nomme la pull request #5910 ou ce correctif, puis mettez à jour et confirmez la version.
Le papier du chercheur est la référence pour la portée du correctif. La pull request modifie les chemins de mot de passe Postgres, MySQL, MariaDB, MongoDB et Redis.
Quelle est la cause racine ?
Le validateur de mot de passe de Dokploy bloque plusieurs caractères de shell mais autorise le backtick, le point-virgule, le pipe, l'esperluette, les parenthèses et les redirections. Les procédures changePassword interpolent ensuite le mot de passe dans une commande docker exec que bash analyse, et le nom d'utilisateur de base de données est interpolé sans validateur.
Voici le validateur dans apps/dokploy/server/src/db/schema/utils.ts à v0.31.0 :
/** Database password: blocks shell-dangerous characters like $ ! ' " \ / and spaces. */
export const DATABASE_PASSWORD_REGEX =
/^[a-zA-Z0-9@#%^&*()_+\-=[\]{}|;:,.<>?~`]*$/;
Le commentaire nomme les caractères bloqués. La classe de caractères inclut encore `, ;, |, &, (, ), > et <. Cela suffit pour la substitution de commande et pour une seconde commande.
Voici la procédure changePassword Postgres à v0.31.0 :
const command = `docker exec ${container.Id} psql -U ${databaseUser} -d postgres -c "ALTER USER \\"${databaseUser}\\" WITH PASSWORD '${password}';"`;
await db.transaction(async (tx) => {
...
if (serverId) {
await execAsyncRemote(serverId, command);
} else {
await execAsync(command, { shell: "/bin/bash" });
}
});
databaseUser vient de l'enregistrement Postgres stocké et n'a aucun validateur. Il est placé après -U sans guillemets. Le mot de passe est entre guillemets simples, mais tout l'argument -c est entre guillemets doubles. Bash développe les backticks et $() à l'intérieur des guillemets doubles, donc un mot de passe comme P2`id` exécute id pendant que le shell construit la commande. Un point-virgule dans databaseUser termine la commande et en démarre une autre.
La commande s'exécute via execAsync avec /bin/bash dans le processus serveur Dokploy. Ce processus est root dans le conteneur serveur, qui détient la socket Docker de l'hôte. L'exécution de commande y équivaut à root sur l'hôte en pratique.
La même construction existe dans les routeurs MySQL, MariaDB et MongoDB. Le chercheur rapporte avoir déclenché les chemins Postgres et MySQL et qualifie les deux autres d'identiques au source. Le chemin Redis place le mot de passe entre guillemets simples de premier niveau et n'a pas été déclenché, ce qui est le contrôle qui prouve le mécanisme.
Comment la faille est-elle exploitée ?
Un membre qui peut créer un service de base de données change son mot de passe ou son nom d'utilisateur en une valeur qui ferme le quoting du shell. Le serveur Dokploy exécute alors la commande injectée en root.
- L'attaquant se connecte à Dokploy comme membre de l'organisation avec la permission de création de service, ou crée un tel membre s'il contrôle déjà l'organisation.
- L'attaquant crée un service de base de données, ou utilise un service auquel il a accès. L'enregistrement Postgres du service stocke un nom d'utilisateur.
- L'attaquant appelle la procédure
changePasswordavec un mot de passe qui passeDATABASE_PASSWORD_REGEXmais contient un backtick, par exempleP2`id>x`. Le validateur l'accepte parce qu'il ne bloque pas le backtick. - Dokploy construit la commande
docker execet la passe à/bin/bash. Bash effectue la substitution de commande sur le backtick et exécuteid, en redirigeant sa sortie vers un fichier choisi par l'attaquant. Le changement de mot de passe de la base s'effectue aussi. - Sinon, l'attaquant définit le nom d'utilisateur de la base avec un point-virgule. Le nom n'a aucun validateur, donc il atteint l'argument
psql -Usans guillemets et démarre une seconde commande. - La commande s'exécute en root dans le conteneur serveur Dokploy. Le conteneur détient la socket Docker de l'hôte, donc l'attaquant peut l'utiliser pour atteindre l'hôte et les services des autres locataires.
La preuve en direct du chercheur a utilisé d'abord un mot de passe bénin, puis un mot de passe $(id) rejeté par le validateur. Le mot de passe avec backtick a ensuite renvoyé 200 et laissé un fichier canari contenant uid=0(root) gid=0(root) dans le conteneur serveur.
Le test a tourné contre l'image officielle v0.31.0 sur une installation liée à localhost. Le chercheur rapporte aussi avoir déclenché le chemin MySQL comme second point d'entrée et un nom d'utilisateur avec point-virgule comme troisième.
Aucune exploitation dans la nature n'est connue. Le dossier public est le message oss-security du chercheur, le papier qu'il lie et le correctif fusionné.
Comment se déroule l'attaque ?
Un membre avec la permission de création de service soumet un mot de passe que le validateur accepte, et le mot de passe atteint une commande bash dans docker exec. Bash exécute alors la commande injectée en root dans le conteneur qui détient la socket Docker de l'hôte.
Que peut faire un attaquant ?
Un attaquant qui déclenche l'injection exécute des commandes en root dans le conteneur serveur Dokploy et peut atteindre l'hôte via sa socket Docker. C'est le contrôle du panneau, de chaque serveur qu'il gère et des secrets de chaque locataire.
Les conditions font partie de l'impact :
- L'attaquant a besoin d'un compte membre Dokploy authentifié avec la permission de création de service et l'accès au service de base de données. Le chercheur indique que ce n'est pas non authentifié et que ce n'est pas une défaillance inter-organisations.
- Dans une installation à administrateur unique, l'administrateur détient déjà la permission, donc il n'y a pas de frontière entre l'utilisateur du panneau et l'hôte.
- La commande s'exécute en root dans le conteneur serveur. Ce conteneur atteint la socket Docker de l'hôte par conception. L'attaquant peut donc lancer des conteneurs privilégiés, lire les variables d'environnement des autres services et atteindre le système de fichiers de l'hôte.
- L'injection se déclenche à la soumission du changement de mot de passe. Le mot de passe de la base est aussi changé, donc l'opération peut sembler réussir pendant que la charge s'exécute.
- Aucune exploitation dans la nature n'est connue, et aucune victime n'est nommée.
L'impact est au niveau de l'hôte, pas de la base de données. Un membre qui peut créer une base de données est déjà responsable de ce service ; cette faille transforme cette confiance en contrôle de l'hôte et des autres locataires.
Pourquoi le correctif fonctionne-t-il ?
Le correctif construit chaque commande docker exec à partir d'un tableau d'arguments avec quote() de shell-quote. Le mot de passe et le nom d'utilisateur restent donc des arguments uniques, et bash n'analyse plus leur contenu comme de la syntaxe.
Voici le changement dans apps/dokploy/server/api/routers/postgres.ts de la pull request #5910 :
- const command = `docker exec ${container.Id} psql -U ${databaseUser} -d postgres -c "ALTER USER \\"${databaseUser}\\" WITH PASSWORD '${password}';"`;
+ const command = `docker exec ${container.Id} ${quote([
+ "psql",
+ "-U",
+ databaseUser,
+ "-d",
+ "postgres",
+ "-c",
+ `ALTER USER "${databaseUser}" WITH PASSWORD '${password}';`,
+ ])}`;
quote() renvoie une chaîne échappée pour le shell pour chaque argument, donc un backtick ou un point-virgule dans databaseUser ou password reste dans son argument. L'instruction SQL reste un argument -c unique, et la base reçoit le mot de passe littéral. La pull request indique que le mot de passe reste sûr dans la chaîne SQL parce que le validateur interdit le guillemet simple.
La même réécriture couvre les routeurs MySQL, MariaDB, MongoDB et Redis. Le correctif ne change pas le validateur, donc un membre peut toujours définir un mot de passe avec un backtick. La différence est que le backtick n'atteint plus un shell.
Comment vérifier si j'ai été compromis ?
Aucun indicateur de compromission n'est publié. Examinez le journal d'audit du panneau et les enregistrements de base de données pour les entrées dont l'exploit a besoin.
- Examinez le journal d'audit Dokploy pour les changements de mot de passe et les créations de service que vous ne pouvez pas justifier. La procédure
changePasswordécrit une entrée d'audit après l'exécution de la commande. - Inspectez les mots de passe et noms d'utilisateur stockés pour les backticks, points-virgules, pipes et autres métacaractères de shell. Une valeur que le validateur autorise mais qui ressemble à de la syntaxe shell est une piste.
- Cherchez des fichiers inattendus dans le conteneur serveur Dokploy, notamment un fichier canari ou un script shell créé par une commande de base de données.
- Examinez le conteneur serveur pour des processus root inattendus, de nouveaux conteneurs privilégiés et des connexions sortantes. Vérifiez les événements Docker de l'hôte pour des conteneurs que vous n'avez pas lancés.
- Si vous trouvez une piste, conservez la base du panneau, le conteneur serveur et les événements Docker avant de reconstruire l'hôte. Faites tourner tous les identifiants de base de données et de service stockés par le panneau.
Une injection échouée peut ne laisser aucune trace au-delà de l'entrée d'audit du changement de mot de passe. L'entrée d'audit seule ne prouve pas l'exploitation.
Chronologie
- 2026-11-05 : Dokploy publie v0.31.0, la version actuelle et celle testée par le chercheur.
- 2026-11-07 : La pull request #5910, « fix(security): database changePassword command injection (all 5 DB types) », est ouverte.
- 2026-11-09 16:59 UTC : La pull request est fusionnée sur la branche canary. Aucune version étiquetée ne la contient.
- 2026-11-10 02:11 UTC : Le chercheur publie la divulgation prouvée en direct sur la liste oss-security.
FAQ
La faille Dokploy est-elle non authentifiée ?
Non. L'attaquant a besoin d'un membre d'organisation authentifié avec la permission de création de service et l'accès au service de base de données. Le chercheur énonce clairement la précondition et indique que la faille n'est pas une défaillance inter-organisations.
Dokploy v0.31.0 corrige-t-il la faille ?
Non. v0.31.0 est la version actuelle et celle testée par le chercheur. Le correctif est sur la branche canary dans la pull request #5910, fusionnée le 9 novembre 2026, et aucune version étiquetée ne le contient au 10 novembre 2026.
Y a-t-il une CVE pour ce problème ?
Aucune CVE n'est attribuée au 10 novembre 2026. Dokploy a noté une autre faille avec la même classe de précondition, CVE-2026-72868, à CVSS v3.1 9,9 ; ce score appartient à l'injection antérieure destination.testConnection, pas à celle-ci.
Existe-t-il un exploit public ?
Le chercheur a publié la méthode, la preuve en direct et un papier, et la preuve est reproductible contre l'image officielle v0.31.0. Aucun dépôt d'exploit autonome n'est lié dans le message public.
Faut-il traiter chaque membre Dokploy comme root ?
Un membre qui peut créer un service de base de données peut atteindre root sur l'hôte par cette faille, donc oui pour cette permission. Retirez la création de service aux membres qui n'en ont pas besoin, et traitez le panneau lui-même comme un système équivalent à root.
Cela affecte-t-il un service Dokploy hébergé ?
Dokploy est un logiciel auto-hébergeable. La divulgation et le correctif concernent le panneau auto-hébergé. Aucun service hébergé n'est nommé dans le dossier public, donc cet article ne fait pas de déclaration à leur sujet.
Références
- Divulgation oss-security du chercheur, « Dokploy: the validator allows the backtick : a member's database password change is host RCE, 9.9 on the vendor's own vector (v0.31.0, live-proven) », 9 novembre 2026, avec la preuve en direct, la portée et le lien du papier : https://www.openwall.com/lists/oss-security/2026/11/10/2 (vérifié le 10 novembre 2026)
- Pull request Dokploy #5910, « fix(security): database changePassword command injection (all 5 DB types) », ouverte le 7 novembre 2026 et fusionnée le 9 novembre 2026 : https://github.com/Dokploy/dokploy/pull/5910 (vérifié le 10 novembre 2026)
- Le
DATABASE_PASSWORD_REGEXvulnérable dansapps/dokploy/server/src/db/schema/utils.tsà v0.31.0 : https://github.com/Dokploy/dokploy/blob/v0.31.0/apps/dokploy/server/src/db/schema/utils.ts#L50-L52 (vérifié le 10 novembre 2026) - La commande
changePasswordPostgres vulnérable dansapps/dokploy/server/api/routers/postgres.tsà v0.31.0 : https://github.com/Dokploy/dokploy/blob/v0.31.0/apps/dokploy/server/api/routers/postgres.ts#L448 (vérifié le 10 novembre 2026) - Version Dokploy v0.31.0, publiée le 5 novembre 2026 : https://github.com/Dokploy/dokploy/releases/tag/v0.31.0 (vérifié le 10 novembre 2026)
- Enregistrement CVE-2026-72868, l'injection rclone
destination.testConnectionantérieure de Dokploy, CVSS v3.1 9.9, citée comme score du vendeur pour la même classe de précondition : https://www.cve.org/CVERecord?id=CVE-2026-72868 (vérifié le 10 novembre 2026) - Dépôt Docker Hub de
dokploy/dokploy, 16 116 660 téléchargements, vérifié le 10 novembre 2026 : https://hub.docker.com/r/dokploy/dokploy (vérifié le 10 novembre 2026) - Flux JSON du catalogue Known Exploited Vulnerabilities de la CISA, vérifié le 10 novembre 2026, sans entrée Dokploy : https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (vérifié le 10 novembre 2026)