RCE dans Flowise exploitée par le framework Greeter (CVE-2024-58351)
Avant 2.1.4, Flowise laisse overrideConfig remplacer le JavaScript d'un nœud Custom JS Function ; le framework Greeter l'a exploité, et 2.1.4 corrige.
En bref
- CVE-2024-58351 permet à une requête de prédiction de remplacer le JavaScript d'un nœud Custom JS Function de Flowise, et le serveur exécute ce code. La faille est l'absence de liste d'autorisation sur le champ
overrideConfigde la requête. - Toutes les versions de Flowise antérieures à 2.1.4 sont concernées. Era a compté 4 372 instances Flowise exposées sur internet, et 703 des 3 277 dont elle a lu la version n'avaient aucune authentification.
- VulnCheck note la faille 9,8 Critical. Greeter l'a exploitée sur des pots de miel de juillet à octobre 2026 et le KEV la référence. La CISA ne la référence pas au 8 novembre 2026.
- Passez à 2.1.4 ou ultérieur, de préférence à 3.1.4, qui contient aussi le durcissement de 2026 du même chemin de code. Voir « Comment corriger ? ».
Suis-je concerné ?
Vous êtes concerné si vous exécutez une version de Flowise antérieure à 2.1.4 et que des utilisateurs non fiables peuvent atteindre son API de prédiction. Toutes ces conditions doivent être réunies :
- Vous exécutez Flowise avant 2.1.4, depuis le paquet npm
flowise, une image Docker officielle ou un produit qui l'embarque. - Le point d'entrée de prédiction
POST /api/v1/prediction/<chatflow-id>est accessible à des utilisateurs non fiables, directement ou via un widget de chat intégré. - Un chatflow accessible à ces utilisateurs contient un nœud Custom JS Function, ou ils peuvent en créer un parce que l'authentification au niveau de l'application est désactivée.
L'authentification au niveau de l'application dans les versions 1.x et 2.0.x concernées repose sur le couple FLOWISE_USERNAME et FLOWISE_PASSWORD. Elle est désactivée quand les deux variables ne sont pas définies. Les pots de miel d'Era exécutaient Flowise 1.8.2 sans ces deux variables, et les attaques enregistrées utilisaient un chatflow avec un nœud Custom JS Function.
Le cas non authentifié est courant dans la population exposée. Le recensement d'Era a trouvé 4 372 instances Flowise sur internet et lu une version sur 3 277. Sur ces dernières, 703 n'avaient aucune authentification, et 46 des 703 correspondaient à la configuration vulnérable qu'elle avait recréée.
| Branche | Versions concernées | Version corrigée |
|---|---|---|
| 1.x | toutes les versions | 2.1.4 (2024-11-13) |
| 2.0.x | toutes les versions | 2.1.4 (2024-11-13) |
| 2.1.x | 2.1.0 à 2.1.3 | 2.1.4 (2024-11-13) |
| 2.1.4 et ultérieures | non concernées par CVE-2024-58351 | exécutez 3.1.4 ou ultérieur pour le durcissement de 2026 |
Vérifiez la version du paquet sur chaque installation, y compris les conteneurs et les copies embarquées dans un autre produit :
# Global npm install
npm ls -g flowise
# Project install
npm ls flowise
# Docker: read the version inside the running container
docker exec <container> cat /usr/local/lib/node_modules/flowise/package.json | grep '"version"'
# Running instance
curl -s http://localhost:3000/api/v1/version
Le point d'entrée de version lit le package.json le plus proche sur le serveur, donc il indique le paquet que le processus exécute réellement. L'étiquette d'une image de conteneur ne suffit pas quand l'image a été construite à partir d'un paquet plus ancien.
Comment corriger ?
Passez à 2.1.4 ou ultérieur, et utilisez la version 3.1.4 actuelle car elle contient deux commits de durcissement ultérieurs sur la même fonction. Vérifiez ensuite que la substitution de configuration est désactivée pour chaque chatflow.
- Mettez à jour le paquet. Pour une installation globale, exécutez
npm install -g flowise@3.1.4. Pour une installation de projet, exécuteznpm install flowise@3.1.4. Pour Docker, téléchargez l'imageflowiseai/flowiseactuelle et recréez le conteneur en conservant son volume de données. - Ouvrez chaque chatflow et vérifiez Réglages, puis Configuration, puis l'onglet Security. La substitution de configuration est désactivée par défaut après 2.1.4. Activez uniquement les paramètres de nœud qui doivent être substituables, car la liste d'autorisation est stockée par chatflow et par type de nœud.
- Placez une authentification devant l'instance. Définissez
FLOWISE_USERNAMEetFLOWISE_PASSWORDsur les branches concernées, ou créez le compte administrateur sur 3.x, et limitez l'API de prédiction aux réseaux qui en ont besoin. - Si vous ne pouvez pas mettre à jour tout de suite, bloquez
POST /api/v1/predictionpour les clients non fiables sur le reverse proxy. Désactivez les chatflows publics et retirez les nœuds Custom JS Function de tout flux accessible à ces clients. Ces mesures suppriment les points d'entrée ; elles ne corrigent pas le code.
La solution de contournement a des limites. L'authentification seule ne supprime pas la faille. Tout compte qui peut créer un chatflow peut ajouter un nœud Custom JS Function. Sur les branches 1.x et 2.0.x concernées, l'authentification applicative est un unique compte administrateur. Un mot de passe administrateur divulgué suffit donc, ce qui explique pourquoi la mise à jour est le correctif et le blocage au proxy une mesure temporaire.
Quelle est la cause racine ?
L'API de prédiction traite un champ de requête comme une configuration de confiance, et cette configuration peut remplacer du code exécutable. Les chatflows Flowise sont des graphes de nœuds, et le nœud Custom JS Function possède une entrée nommée javascriptFunction dont la valeur est du code JavaScript. Avant 2.1.4, l'objet overrideConfig du corps de la requête était appliqué à toutes les entrées de nœud sans liste d'autorisation. Ce code est cité depuis packages/server/src/utils/index.ts à Flowise 2.1.3 :
export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: ICommonObject) => {
const types = 'inputs'
const getParamValues = (inputsObj: ICommonObject) => {
for (const config in overrideConfig) {
// If overrideConfig[key] is object
if (overrideConfig[config] && typeof overrideConfig[config] === 'object') {
const nodeIds = Object.keys(overrideConfig[config])
if (nodeIds.includes(flowNodeData.id)) {
inputsObj[config] = overrideConfig[config][flowNodeData.id]
continue
} else if (nodeIds.some((nodeId) => nodeId.includes(flowNodeData.name))) {
/*
* "systemMessagePrompt": {
* "chatPromptTemplate_0": "You are an assistant" <---- continue for loop if current node is chatPromptTemplate_1
* }
*/
continue
}
}
let paramValue = inputsObj[config]
const overrideConfigValue = overrideConfig[config]
if (overrideConfigValue) {
if (typeof overrideConfigValue === 'object') {
switch (typeof paramValue) {
case 'string':
if (paramValue.startsWith('{') && paramValue.endsWith('}')) {
try {
paramValue = Object.assign({}, JSON.parse(paramValue), overrideConfigValue)
break
} catch (e) {
// ignore
}
}
paramValue = overrideConfigValue
break
case 'object':
paramValue = Object.assign({}, paramValue, overrideConfigValue)
break
default:
paramValue = overrideConfigValue
break
}
} else {
paramValue = overrideConfigValue
}
}
// Check if boolean
if (paramValue === 'true') paramValue = true
else if (paramValue === 'false') paramValue = false
inputsObj[config] = paramValue
}
}
const inputsObj = flowNodeData[types] ?? {}
getParamValues(inputsObj)
return flowNodeData
}
La boucle lit toutes les clés envoyées par l'appelant. Quand la clé est javascriptFunction, l'affectation finale remplace le JavaScript du nœud par la chaîne de l'appelant. Le flux est construit à partir du chatflow stocké, la substitution est appliquée aux données du nœud en mémoire, puis le nœud s'initialise avec le code de l'attaquant. Rien n'est réécrit dans le chatflow, ce qui explique pourquoi la définition stockée peut sembler inoffensive.
Le nœud Custom JS Function enveloppe cette chaîne dans une fonction asynchrone. Il l'exécute dans un NodeVM de vm2, cité depuis la source du nœud à Flowise 1.8.2 :
const nodeVMOptions = {
console: 'inherit',
sandbox,
require: {
external: { modules: deps },
builtin: builtinDeps
}
} as any
const vm = new NodeVM(nodeVMOptions)
const response = await vm.run(`module.exports = async function() {${javascriptFunction}}()`, __dirname)
La liste d'autorisation intégrée couvre des modules comme http, net et path, pas child_process. L'avis du fournisseur liste l'évasion de bac à sable comme impact de la fonctionnalité. La reconstruction d'Era montre le payload exécutant des commandes shell via child_process.execSync(). vm2 n'est pas une frontière de sécurité face à du JavaScript hostile. Ses propres mainteneurs l'ont abandonné en 2023 parce que des évasions continuaient d'apparaître.
Comment la faille est-elle exploitée ?
Un attaquant envoie l'exploit sous forme de requête de prédiction normale, donc le chatflow stocké n'a jamais besoin de contenir le code malveillant. Le corps de la requête porte une question anodine et un objet overrideConfig dont la clé javascriptFunction contient l'étape à exécuter :
{
"question": "hello",
"overrideConfig": {
"javascriptFunction": "<JavaScript that returns the command output>"
}
}
Les étapes, telles qu'Era les a reconstruites à partir du trafic des pots de miel :
- Atteignez l'instance et, quand l'authentification applicative est désactivée, utilisez ou créez un chatflow contenant un nœud Custom JS Function. Le flux du framework s'appelait
ghsa-5cph-wvm9-45gj-poc. - Envoyez
POST /api/v1/prediction/<chatflow-id>avec ce corps de requête, en utilisanthellocomme question. - Le serveur applique la substitution à l'entrée
javascriptFunctiondu nœud avant son initialisation. - Le nœud exécute le JavaScript de l'appelant dans le bac à sable vm2. L'étape s'échappe du bac à sable et atteint
child_process.execSync(). - La sortie de la commande revient dans la réponse de prédiction. Le framework envoie la commande suivante environ 3,5 secondes plus tard, de nouveau sous la forme
hello, et répète le cycle. - Les étapes suivantes énumèrent l'hôte et lisent les variables d'environnement et les fichiers d'identifiants. Elles interrogent aussi les métadonnées cloud, vérifient la présence du socket Docker et préparent la persistance et des payloads uniquement en mémoire.
Era a compté 4 972 de ces messages sur deux mois et demi, de juillet à octobre 2026, contre sept pots de miel Flowise 1.8.2 dans quatre régions. L'adresse source qu'elle a relevée était le nœud de sortie TOR 185.246.188[.]74.
Le correctif était disponible depuis novembre 2024, 20 mois avant le début de la campagne. L'écart est l'histoire : les déploiements qui n'avaient jamais appliqué la mise à jour 2.1.4 sont restés exploitables pendant toute la campagne.
Comment se déroule l'attaque ?
Une seule requête de prédiction transporte le JavaScript de l'attaquant, et le serveur le substitue dans le nœud sans liste d'autorisation. Le code s'échappe ensuite du bac à sable et exécute des commandes avec les droits de l'utilisateur Flowise.
avec overrideConfig.javascriptFunction"] --> B["replaceInputsWithConfig applique
la substitution à l'entrée du nœud
aucune liste d'autorisation"] B --> C["Le nœud Custom JS Function
exécute le JavaScript de l'appelant
dans vm2"] C --> D["Évasion du bac à sable vm2"] D --> E["child_process.execSync
s'exécute avec les droits de l'utilisateur Flowise"] E --> F["Reconnaissance, .env et clés SSH,
identifiants des métadonnées cloud"] F --> G["Persistance et préparation
d'un payload en mémoire"]
Que peut faire un attaquant ?
Un attaquant qui atteint l'API de prédiction exécute des commandes avec les droits de l'utilisateur du processus Flowise et peut lire tous les secrets que ce processus peut atteindre. Les preuves des pots de miel d'Era montrent :
- L'exécution de commandes avec le compte de service. Dans le pot de miel d'Era, le processus tournait en root avec un sudo sans restriction, ce qui est un choix de déploiement et non une propriété de la faille.
- La reconnaissance de l'hôte : identité, noyau, distribution, processus, ports en écoute, routes, environnement, identifiants de conteneur et capacités Linux.
- La découverte d'identifiants : fichiers
.env, clés privées SSH etauthorized_keys, certificats clients TLS, fichiers SQL et SQLite, et la clé de chiffrement Flowise dans/root/.flowise/encryption.key. - Le vol d'identifiants cloud via le service de métadonnées de l'instance, puis l'usage de ce que l'identité cloud de la charge de travail est autorisée à faire.
- L'usage d'un socket Docker monté, qui peut mener au contrôle de l'hôte et des autres conteneurs.
- La persistance par cron et des unités systemd, et la préparation de payloads exécutés depuis la mémoire via
memfd_create().
Les conditions sont celles de « Suis-je concerné ? ». L'impact dépend ensuite de l'utilisateur du processus, des volumes montés, du socket Docker et de l'identité cloud attachée à la charge de travail.
Aucune compromission réussie d'un déploiement Flowise de production n'est publiée dans le rapport d'Era. Les preuves d'exploitation viennent de ses pots de miel.
Pourquoi le correctif fonctionne-t-il ?
Le correctif rend chaque substitution opt-in par chatflow et par paramètre de nœud, donc une requête ne peut plus remplacer javascriptFunction sauf si l'opérateur l'a activé. Flowise 2.1.4 ajoute getAPIOverrideConfig(), qui lit la configuration API du chatflow :
export const getAPIOverrideConfig = (chatflow: IChatFlow) => {
try {
const apiConfig = chatflow.apiConfig ? JSON.parse(chatflow.apiConfig) : {}
const nodeOverrides = apiConfig.overrideConfig && apiConfig.overrideConfig.nodes ? apiConfig.overrideConfig.nodes : {}
const variableOverrides = apiConfig.overrideConfig && apiConfig.overrideConfig.variables ? apiConfig.overrideConfig.variables : []
const apiOverrideStatus = apiConfig.overrideConfig && apiConfig.overrideConfig.status ? apiConfig.overrideConfig.status : false
return { nodeOverrides, variableOverrides, apiOverrideStatus }
} catch (error) {
return { nodeOverrides: {}, variableOverrides: [], apiOverrideStatus: false }
}
}
replaceInputsWithConfig() reçoit désormais la liste d'autorisation par nœud et la vérifie avant d'écrire une entrée :
const isParameterEnabled = (nodeType: string, paramName: string): boolean => {
if (!nodeOverrides[nodeType]) return false
const parameter = nodeOverrides[nodeType].find((param: any) => param.name === paramName)
return parameter?.enabled ?? false
}
// ...
if (!isParameterEnabled(flowNodeData.label, config)) {
continue
}
Une substitution exige désormais deux validations : overrideConfig.status doit être vrai sur le chatflow, et le type de nœud doit lister le paramètre comme activé. La valeur par défaut est faux, et javascriptFunction n'est pas dans la liste sauf si un opérateur l'ajoute. La même garde s'applique aux chemins de prédiction, de graphe d'agents et d'upsert.
La première liste d'autorisation n'a pas clos le sujet. Le commit c8282c97fb (2026-02-06) a retiré une exception FILE-STORAGE:: qui laissait une valeur contourner la vérification d'activation. Il a aussi ajouté NODE_OPTIONS aux variables d'environnement que l'outil MCP refuse. Le commit 23b997ee5e (2026-05-07) a cessé d'étaler l'objet overrideConfig brut dans les données du flux, ce qui laissait un second chemin pour les clés contrôlées par l'appelant. Flowise 3.1.4, publié le 2026-07-29, contient les deux, ce qui en fait la version à exécuter.
Comment vérifier si j'ai été compromis ?
Cherchez les marqueurs du framework dans les journaux de requêtes Flowise et sur l'hôte ; la campagne laisse des chaînes distinctives même si ses messages de chat ne contiennent que hello. Era a publié ces indicateurs :
- Des requêtes de prédiction dont le corps JSON contient
overrideConfigetjavascriptFunction. - Un chatflow nommé
ghsa-5cph-wvm9-45gj-poc. - Des messages de chat contenant
VP_DOCKER,VP_MEMFD,VP_W_OKouVP_INIT_OK, des réponses de balise correspondant àvp-alive-[0-9a-f]{8}, et des rapports de sortie correspondant à__VP_EXIT_[0-9]+. - Des noms de processus
polld-keeper-{8-hex}etvarrun-watcher-{8-hex}. - Un fichier cron dans
/etc/cron.d/syslog-cronrun-{8-hex}ou une unité systemd dans/etc/systemd/system/taskd-sysrun-{8-hex}.service. - Le hachage de configuration
07f8464533b3446e918feff1ea14c4ae, partagé par les deux composants de persistance. - Des connexions depuis le nœud de sortie TOR
185.246.188[.]74.
Exécutez ces vérifications sur l'hôte Flowise et sur tout hôte dont le socket Docker est accessible au conteneur :
# Flowise request logs (Docker example; adjust the container name)
docker logs <container> 2>&1 | grep -Ei 'overrideConfig|javascriptFunction|ghsa-5cph-wvm9-45gj'
# Persistence artifacts
sudo find /etc/cron.d /etc/systemd/system -maxdepth 1 \( -name 'syslog-cronrun-*' -o -name 'taskd-sysrun-*.service' \)
# Framework processes
ps -eo pid,user,args | grep -E 'polld-keeper-|varrun-watcher-'
Un résultat est une piste, pas une preuve. Flowise lui-même utilise overrideConfig dans sa documentation et ses SDK, donc une requête qui mentionne le champ peut être légitime. La combinaison du champ avec javascriptFunction, ou avec le nom du chatflow et les marqueurs VP_, est le signal le plus fort. Les preuves d'Era viennent de pots de miel ; aucun indicateur d'une victime de production n'est publié.
Chronologie
- 2024-11-13 : Flowise 2.1.4 est publié avec la liste d'autorisation de substitution par chatflow.
- 2024-11-21 : L'avis Flowise GHSA-5cph-wvm9-45gj est publié, avec une sévérité High et un score CVSS v4.0 de 8,6.
- 2026-02-06 : Le commit
c8282c97fbretire un contournementFILE-STORAGE::de la liste d'autorisation. - 2026-05-07 : Le commit
23b997ee5ecesse d'étaler l'objetoverrideConfigbrut dans les données du flux. - 2026-06-20 : VulnCheck publie CVE-2024-58351 avec un score CVSS v3.1 de 9,8.
- 2026-11-03 : Era publie son analyse du framework Greeter, dont les pots de miel ont enregistré 4 972 requêtes de prédiction de juillet à octobre 2026.
- 2026-11-08 : Cet article est publié.
FAQ
Flowise 2.1.4 suffit-il ?
Oui pour CVE-2024-58351, car 2.1.4 ajoute la liste d'autorisation que la faille contourne. Exécutez tout de même 3.1.4 ou ultérieur. Deux commits de 2026 ont fermé des contournements de la première liste et retiré un second chemin pour les clés contrôlées par l'appelant.
L'authentification arrête-t-elle l'attaque ?
Pas à elle seule. L'authentification supprime le cas non authentifié, mais tout compte qui peut créer un chatflow peut ajouter un nœud Custom JS Function et envoyer la substitution. Sur les branches 1.x et 2.0.x concernées, l'authentification applicative est un unique compte administrateur, donc un mot de passe divulgué suffit.
Faut-il un nœud Custom JS Function dans le chatflow ?
Oui. La substitution remplace la valeur d'une entrée, et javascriptFunction est l'entrée du nœud Custom JS Function. Un attaquant non authentifié peut créer un flux avec ce nœud ; le flux observé dans le pot de miel d'Era s'appelait ghsa-5cph-wvm9-45gj-poc.
La faille a-t-elle été exploitée contre de vraies organisations ?
Era a observé le framework Greeter contre ses propres pots de miel, pas contre des victimes nommées. Elle a aussi trouvé 4 372 instances Flowise exposées sur internet et 46 instances non authentifiées qui correspondaient à la configuration vulnérable recréée. Ce sont des preuves d'exposition, pas des preuves de compromission.
Pourquoi Flowise note-t-il le problème High alors que VulnCheck le note Critical ?
L'avis Flowise est classé High, et son vecteur CVSS v4.0 utilise PR:H, qui suppose que l'attaquant détient déjà des privilèges élevés, avec un score de 8,6. VulnCheck, l'autorité de numérotation CVE, utilise PR:N et le note 9,8 en CVSS v3.1 et 9,3 en CVSS v4.0. Le chemin d'exploitation décrit ici ne demande qu'un accès réseau quand l'authentification applicative est désactivée, ce qui correspond au vecteur de VulnCheck.
Que faire si je ne peux pas mettre à jour cette semaine ?
Bloquez POST /api/v1/prediction pour les clients non fiables sur le reverse proxy. Désactivez les chatflows publics et retirez les nœuds Custom JS Function de tout flux accessible à ces clients. Planifiez ensuite la mise à jour, et faites tourner les identifiants que le processus Flowise peut lire si l'hôte a été exposé.
Trouver les instances Flowise exposées avec Ostorlab
La découverte de la surface d'attaque d'Ostorlab recense les services exposés sur internet dans votre parc, pour trouver les hôtes exposés qui exécutent Flowise et prioriser la mise à jour.
Références
- Avis Flowise GHSA-5cph-wvm9-45gj, publié le 2024-11-21, avec la liste d'impacts d'
overrideConfiget le correctif 2.1.4 : https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-5cph-wvm9-45gj (vérifié le 8 novembre 2026) - Enregistrement CVE-2024-58351, publié le 2026-06-20, avec les scores CVSS v3.1 9.8 et v4.0 9.3 et le bloc SSVC de la CISA ADP : https://www.cve.org/CVERecord?id=CVE-2024-58351 (vérifié le 8 novembre 2026)
- Avis VulnCheck, « Flowise - Remote Code Execution via overrideConfig Parameter », publié le 2026-06-20 : https://www.vulncheck.com/advisories/flowise-remote-code-execution-via-overrideconfig-parameter (vérifié le 8 novembre 2026)
- Commit de correction Flowise 2.1.4, « Enable/disable variables in override configuration », 2024-11-13 : https://github.com/FlowiseAI/Flowise/commit/537aa51ef8 (vérifié le 8 novembre 2026)
- Paquet npm Flowise, version 2.1.4 publiée le 2024-11-13 et version actuelle 3.1.4 publiée le 2026-07-29 : https://www.npmjs.com/package/flowise (vérifié le 8 novembre 2026)
- Commit Flowise
c8282c97fb, « Fix Paramater Override Bypass », 2026-02-06 : https://github.com/FlowiseAI/Flowise/commit/c8282c97fb (vérifié le 8 novembre 2026) - Commit Flowise
23b997ee5e, « remove ungated overrideConfig spread », 2026-05-07 : https://github.com/FlowiseAI/Flowise/commit/23b997ee5e (vérifié le 8 novembre 2026) - Source du nœud Custom JS Function de Flowise 1.8.2, avec l'enveloppe
NodeVM: https://github.com/FlowiseAI/Flowise/blob/5e4d640ed7/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts (vérifié le 8 novembre 2026) - Era Security, « You Had Me at Hello: Inside The Greeter, A Chinese-Language Framework Targeting AI Infrastructure », 2026-11-03, avec les étapes de l'attaque, les chiffres d'exposition et les indicateurs : https://era.security/blog/greeter-flowise-ai-infrastructure-attack (vérifié le 8 novembre 2026)
- Documentation Flowise, « Prediction », avec le point d'entrée, le champ
overrideConfiget la substitution de configuration désactivée par défaut : https://docs.flowiseai.com/using-flowise/prediction (vérifié le 8 novembre 2026) - Documentation Flowise, authentification « Application », avec les variables
FLOWISE_USERNAMEetFLOWISE_PASSWORD: https://docs.flowiseai.com/configuration/authorization/app-level (vérifié le 8 novembre 2026) - Catalogue Known Exploited Vulnerabilities de la CISA, vérifié pour CVE-2024-58351 : https://www.cisa.gov/known-exploited-vulnerabilities-catalog (vérifié le 8 novembre 2026)