Modèle / jeu de données
beelzebub-labs/beelzebub avatar
beelzebub-labs/beelzebub

Beelzebub : un runtime de déception qui parle aux attaquants

A secure low code deception runtime framework, leveraging AI for System Virtualization.

2 176 étoiles209 forksGoGPL-3.0

En bref

De quoi s’agit-il ?
Beelzebub est un runtime de déception en Go, sous licence GPL-3.0, qui expose des leurres SSH, HTTP, TCP, TELNET et MCP et délègue les réponses à un LLM. Le point à trancher avant adoption : accepter que le leurre improvisé soit le produit, avec les fuites que cela suppose.
À qui s’adresse-t-il ?
Beelzebub convient aux équipes qui exploitent déjà un SOC et veulent des leurres SSH, HTTP, TCP, TELNET ou MCP sans écrire de Go, à condition d'isoler le conteneur et de porter une attention particulière aux identifiants de leurre et aux mots de passe. Il ne convient pas à qui cherche un honeypot à faible interaction, déterministe et sans dépendance à un fournisseur de modèle.
Puis-je l’utiliser commercialement ?
Oui, sous conditions. GPL-3.0 est une licence copyleft : si vous distribuez un logiciel qui l’inclut, vous devez publier le code source de ce logiciel sous la même licence. Un usage interne, sans distribution, ne déclenche pas cette obligation.
Est-il encore maintenu ?
Oui. Les derniers commits datent d’il y a 2 jours.
En quel langage est-il écrit ?
Principalement Go, d’après les statistiques de langage de GitHub.

Ces réponses reposent sur les données GitHub du projet (dernière synchronisation le 15 septembre 2026) et sur notre analyse. Elles ne constituent pas un avis juridique.

ANALYSE OPEN SOURCE APPROFONDIE

Le problème : un honeypot qui ne sait pas improviser

Un honeypot classique répond par des chaînes écrites à l'avance. L'attaquant teste une commande hors script, reconnaît la répétition, et passe à autre chose. La collecte s'arrête là. Beelzebub prend le problème par l'autre bout : le README annonce un moteur de déception adaptatif où un LLM (OpenAI ou Ollama) génère les réponses en temps réel, avec pour objectif affiché de garder l'attaquant engagé assez longtemps pour collecter des TTP exploitables. Le public visé est précis : équipes de détection, chercheurs en sécurité, et depuis peu ceux qui surveillent les surfaces d'attaque liées aux agents IA. Le projet se présente comme un « deception runtime », pas comme un outil d'analyse. Il ne cherche pas à savoir si un attaquant est présent, il cherche à le faire parler. Cette nuance change tout ce qui suit, à commencer par la surface de risque qu'on accepte d'exposer.

Ce que le LLM reçoit vraiment

Le mécanisme repose sur une correspondance par expression régulière. Les services sont décrits en YAML, chaque commande reconnue déclenche une réponse, et c'est cette réponse que le LLM peut produire. Le README parle de « low-code service definition » : pas de code à écrire pour ajouter un leurre, seulement de la configuration. Pour les cas qui sortent du cadre, une SDK publique est exposée dans pkg/plugin, avec trois interfaces. CommandPlugin renvoie une chaîne de texte et couvre SSH, TCP, TELNET et HTTP. HTTPPlugin produit une réponse HTTP complète, code de statut, en-têtes et corps. WirePlugin observe et peut réécrire les échanges binaires TCP correspondants, avec WireSessionCloser en option pour libérer l'état par connexion. Les plugins TCP sont activés explicitement, dans l'ordre d'exécution, via la clé wirePlugins dans le YAML du service. WireContext expose les octets bruts de la requête et de la réponse, la commande reconnue, l'identité du service et l'historique. C'est ce dernier point qui rend la conversation crédible, et c'est aussi ce qui fait transiter le contenu de l'attaquant vers le modèle. La documentation ne détaille pas, dans les éléments fournis, ce qui est filtré avant l'appel ni ce qui est conservé côté fournisseur. C'est une question à poser avant de déployer, pas après.

Mise en route : installateur, Makefile, Helm

Trois chemins d'installation sont documentés. ./install.sh demande local ou Docker, vérifie les prérequis et démarre ; les variantes non interactives sont ./install.sh --local et ./install.sh --docker, et ./install.sh --local --no-run installe et compile sans lancer le runtime. Le README précise que sur un hôte non root, l'installation locale ne démarre pas automatiquement lorsque la configuration par défaut contient des ports privilégiés. En Go, make start installe les plugins déclarés, les compile et exécute. En conteneur, make docker construit une image avec les plugins déclarés intégrés. Sur Kubernetes, helm install beelzebub ./beelzebub-chart, puis helm upgrade pour la suite. Le binaire expose quatre commandes. beelzebub run démarre les services avec trois drapeaux : -c pour le fichier de configuration principal (par défaut ./configurations/beelzebub.yaml), -s pour le répertoire des services (par défaut ./configurations/services/) et -m pour la limite mémoire en MiB, -1 pour la désactiver, valeur par défaut 100. beelzebub validate analyse la configuration sans démarrer de service, ce que le README recommande explicitement en CI. beelzebub plugin install github.com/your-org/beelzebub-myplugin, plugin list et plugin remove myplugin gèrent les extensions récupérées depuis GitHub. beelzebub version affiche version, SHA de commit, date de build et informations sur le runtime Go.

La limite mémoire par défaut est un piège de dimensionnement

Cent MiB par service, c'est la valeur par défaut de -m. Un leurre qui doit tenir une conversation, conserver un historique et appeler un modèle distant peut vivre dans cette enveloppe, mais l'exploitant doit savoir ce qui se passe au dépassement. Le README ne décrit pas, dans les éléments disponibles, le comportement exact à la limite. Il indique seulement que la limite existe et qu'on peut la désactiver avec -1. Poser -1 sur un service exposé à Internet revient à retirer un garde-fou dont on ne connaît pas le coût réel en cas de déclenchement. La recommandation raisonnable est de garder la limite active et de mesurer la consommation réelle par service avant de l'ajuster. Autre contrainte de dimensionnement : chaque échange non reconnu par une expression régulière peut devenir un appel au modèle. Le coût par attaquant n'est donc pas fixe, il dépend du volume d'interaction. Un scanner qui envoie du bruit en masse peut transformer un leurre en poste de dépense. Le projet ne documente pas, dans le matériel fourni, de plafond de requêtes par connexion ou par plage horaire.

Métriques, flux d'événements et validation en CI

L'observabilité est présentée comme complète : métriques Prometheus et streaming d'événements RabbitMQ. C'est le bon choix pour une intégration dans un SOC existant, où la déception n'est utile que si ses signaux rejoignent les mêmes tableaux de bord que le reste. Le revers est le nombre de composants à faire tourner : le runtime, un broker RabbitMQ si l'on veut les événements, un collecteur Prometheus, et un modèle joignable, soit via OpenAI soit via Ollama en local. Ce dernier point est le levier le plus intéressant du projet. Faire tourner Ollama sur site réduit la dépendance à un fournisseur externe et garde les charges utiles des attaquants dans le périmètre. Le README ne donne pas de modèle recommandé ni de latence attendue, et je ne peux pas en inventer. La commande beelzebub validate mérite une place dans le pipeline : elle analyse les fichiers de configuration sans lancer de service, ce qui attrape les erreurs de YAML avant le déploiement. C'est le seul garde-fou automatisable que la documentation met en avant.

Un leurre qui parle est un leurre qui fuit

Le cas où Beelzebub est le mauvais outil est celui d'une équipe qui ne peut pas accepter qu'un composant exposé à Internet soit non déterministe. Un leurre qui improvise peut divulguer une information plausible mais fausse sur votre infrastructure, et cette information sera reprise ailleurs. Il peut aussi produire une réponse incohérente avec la version de service annoncée, ce qui trahit le leurre auprès d'un attaquant attentif. Le README ne décrit pas, dans le matériel fourni, de garde-fou qui empêcherait le modèle de révéler quelque chose de sensible. La documentation parle d'engager l'attaquant, pas de contraindre ce qu'il peut apprendre. C'est un arbitrage assumé : plus la conversation est riche, plus le risque de fuite est réel. Trois précautions découlent de cette lecture. Isoler le conteneur du réseau de production. Ne jamais réutiliser d'identifiants réels dans la configuration des leurres. Décider en amont si les charges utiles peuvent sortir du périmètre, ce qui oriente vers Ollama plutôt que vers un service distant. Aucune de ces précautions n'est une option de configuration documentée : ce sont des décisions d'exploitation.

Face à Cowrie et aux honeypots à faible interaction

Cowrie est l'alternative la plus directement comparable : un honeypot SSH et TELNET en Python, dont le comportement repose sur une émulation écrite à la main, avec des réponses prévisibles et un périmètre stable. La différence d'approche est nette. Cowrie ne dépend d'aucun modèle, ne coûte rien par interaction et ne peut pas improviser une réponse hors de ce que ses mainteneurs ont prévu. Beelzebub fait le pari inverse : il accepte une dépendance à un LLM, un coût variable et un comportement non déterministe pour obtenir des interactions plus longues. Le choix entre les deux n'est pas une question de qualité mais de ce que vous cherchez à mesurer. Si vous voulez compter les tentatives de connexion et les mots de passe essayés, Cowrie suffit et coûte moins cher à exploiter. Si vous voulez observer comment un attaquant s'adapte quand le système répond, la réponse préenregistrée devient le facteur limitant. Beelzebub ajoute aussi une couverture que Cowrie n'a pas : HTTP, TCP, et surtout MCP, le protocole des agents IA. Le README mentionne la détection d'attaques par injection de prompt contre ces agents. C'est la partie la plus récente du projet et, à en juger par le rythme des versions, celle qui bouge le plus.

Licence, mises à jour et coût de suivi

Beelzebub est publié sous GPL-3.0. Un déploiement interne n'a pas d'implication pratique, mais l'usage de la SDK dans pkg/plugin pour distribuer un plugin lié au binaire mérite un examen attentif. Je ne donne pas d'avis juridique, et le projet ne fournit pas, dans les éléments disponibles, de clarification sur le statut des plugins externes au regard de la licence. Le rythme de publication est soutenu : v3.8.0 en juin 2026, v3.9.0 en août, v3.9.1 fin août, et le dernier push sur main en septembre 2026. Une API de plugins stable est justement ce qui rend ce rythme supportable, puisque les extensions n'ont pas à suivre chaque changement interne. Cela dit, une version mineure tous les un à deux mois signifie qu'il faut lire les notes de version avant de mettre à jour un runtime exposé. Le coût caché n'est pas la mise à jour du binaire, c'est la revalidation des configurations de leurres : une expression régulière qui ne correspond plus produit un leurre muet, et rien dans la documentation fournie n'indique qu'une alerte se déclenche dans ce cas. La commande beelzebub validate attrape les erreurs de syntaxe, pas une intention de détection devenue obsolète.

Conclusion éditoriale

Beelzebub convient aux équipes qui exploitent déjà un SOC et veulent des leurres SSH, HTTP, TCP, TELNET ou MCP sans écrire de Go, à condition d'isoler le conteneur et de porter une attention particulière aux identifiants de leurre et aux mots de passe. Il ne convient pas à qui cherche un honeypot à faible interaction, déterministe et sans dépendance à un fournisseur de modèle. Avant tout déploiement, lancer beelzebub validate sur les fichiers de configurations/services/ et vérifier si votre cas relève de la GPL-3.0.

Sources officielles

  1. beelzebub-labs/beelzebub on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
Notes de la communauté

Notes de la communauté