Cybersécurité

SmokedMeat : je l’ai testé sur un vrai scénario CI/CD

21 juin 2026 Mehdi 21:52

SmokedMeat est un framework de red team CI/CD qui aide à montrer comment une faille dans GitHub Actions peut devenir un vrai chemin d’attaque. Est-ce que ça vaut le coup ? Oui pour une équipe sécu qui veut démontrer un risque, mais pas comme petit scanner tranquille à lancer en cinq minutes.

SmokedMeat, c’est quoi ?

SmokedMeat se présente comme un Metasploit pour les pipelines CI/CD. L’idée est simple à comprendre, même si l’outil est ambitieux : analyser des workflows, trouver des injections ou des mauvaises pratiques, livrer un stager, recevoir un callback dans un serveur C2 appelé Kitchen, puis piloter un agent appelé Brisket depuis une interface terminal appelée Counter.

Le projet vient de BoostSecurity Labs et embarque poutine, leur scanner SAST spécialisé dans les pipelines de build. Le ton est très clair dans le README : usage autorisé uniquement, démonstration offensive, bruit assumé, pas de furtivité magique.

Élément Ce que j’ai observé
Langage Go 1.26
Interface opérateur TUI Bubbletea, nommée Counter
Serveur Kitchen, API HTTP avec WebSocket et graphe
Agent Brisket, agent livré au runner CI
Scanner CI/CD poutine intégré
Stockage base locale Kitchen, type bbolt dans ce build

Installation de SmokedMeat depuis les sources

Le chemin conseillé est make quickstart, qui demande Docker. Dans mon environnement de test, Docker n’était pas disponible. J’ai donc installé Go 1.26 dans un dossier temporaire, compilé les trois binaires et lancé l’infrastructure minimale à la main avec NATS.

Commandes réellement utilisées :

git clone https://github.com/boostsecurityio/smokedmeat /tmp/smokedmeat
cd /tmp/smokedmeat
go build -o /tmp/smokedmeat-bin/counter ./cmd/counter
go build -o /tmp/smokedmeat-bin/kitchen ./cmd/kitchen
go build -o /tmp/smokedmeat-bin/brisket ./cmd/brisket

Résultat : les trois binaires se compilent. Les binaires produits pesaient environ 43 Mo pour Counter, 68 Mo pour Kitchen et 52 Mo pour Brisket. J’ai aussi lancé des tests ciblés sur les parties poutine et Kitchen :

go test ./internal/poutine ./internal/kitchen -run 'Test.*(Analyze|DefaultBashPayload|Stager|Beacon)' -count=1

Sortie observée : les deux paquets testés passent, ok sur internal/poutine et internal/kitchen.

SmokedMeat à l’usage : analyse d’un workflow vulnérable

Pour éviter de jouer avec un dépôt public qui ne m’appartient pas, j’ai créé un dépôt Git local volontairement vulnérable. Le workflow GitHub Actions interpolait directement le titre et le body d’une pull request dans un run shell et dans actions/github-script.

Extrait du cas testé :

name: CI
on:
  pull_request:
    types: [opened, synchronize]
permissions: write-all
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: dangerous title interpolation
        run: |
          echo "PR title: ${{ github.event.pull_request.title }}"
      - name: dangerous script
        uses: actions/github-script@v7
        with:
          script: |
            const body = `${{ github.event.pull_request.body }}`
            console.log(body)

J’ai ensuite appelé le moteur local poutine intégré par SmokedMeat depuis un petit point d’entrée Go temporaire. Ce n’est pas juste un démarrage : l’outil a produit un JSON de findings.

La synthèse réelle était claire :

SUMMARY repos=1 findings=2 critical=0 high=2 medium=0 workflows=1 success=true
V001 high injection line=17 context=pr_body
V002 high injection line=12 context=pr_title

Ce que j’aime ici : SmokedMeat ne dit pas seulement « workflow suspect ». Il remonte la ligne, le contexte exploitable (pr_title, pr_body), la sévérité et le type de règle. Pour un audit, c’est le niveau d’information dont on a besoin pour expliquer le risque à un lead DevOps.

SmokedMeat avec Kitchen et Brisket

J’ai ensuite lancé Kitchen, le serveur C2 local, avec authentification par token et NATS en local. Le healthcheck répondait bien, et les routes protégées refusaient l’accès sans token.

nats-server -js -p 4222
AUTH_MODE=token AUTH_TOKEN=<token> KITCHEN_PORT=18080 \
  NATS_URL=nats://127.0.0.1:4222 kitchen

Ensuite, j’ai enregistré un stager demo1 pour une session sess-demo. Kitchen a répondu avec un objet JSON contenant l’URL de callback, l’identifiant du stager, les métadonnées et son mode express.

interface de SmokedMeat montrant Kitchen générant un stager de callback

Quand j’ai appelé l’URL de callback, Kitchen a généré un payload bash avec un AGENT_ID, un AGENT_TOKEN et une commande qui télécharge Brisket depuis /agent/brisket-linux-amd64. J’ai ensuite exécuté Brisket en mode express avec des variables CI simulées, dont un token GitHub factice et des variables sensibles factices.

interface de SmokedMeat montrant Brisket exécutant un callback express vers Kitchen

Sortie utile :

INFO brisket agent express mode agent_id=agt_...
smokedmeat.upload.v1 callback_hash=... agent_hash=...
INFO express mode complete

Le callback fonctionne. En revanche, mon graphe /pantry est resté vide dans ce scénario local. C’est cohérent : je n’ai pas livré l’implant via une vraie pull request GitHub ni exécuté le flux complet dans un runner Actions vulnérable. Sans Docker et sans PAT GitHub, je n’ai pas validé le parcours public whooli de bout en bout.

Ce que j’aime dans SmokedMeat

D’abord, le modèle colle bien à la réalité CI/CD. Beaucoup d’outils s’arrêtent à « vous avez une injection ». SmokedMeat pense en chaîne : finding, payload, stager, callback, agent, loot, graphe.

Ensuite, le scanner embarqué est pertinent. Sur mon workflow volontairement fragile, il a trouvé exactement les deux interpolations dangereuses que j’attendais. Le résultat est exploitable pour un rapport client, pas seulement pour un log de dev.

J’aime aussi la séparation des rôles : Counter pour l’opérateur, Kitchen pour l’équipe serveur, Brisket pour l’agent. C’est plus lourd qu’un simple CLI, mais plus proche d’un exercice red team réel.

Les limites de SmokedMeat

La première limite est la friction. Le quickstart demande Docker, les scénarios publics demandent un token GitHub, et l’expérience complète suppose une vraie cible de test. Ce n’est pas un outil que je donnerais tel quel à une équipe non technique.

Deuxième limite : le produit est offensif par design. Même en labo, il faut être carré sur les autorisations. Le stager et l’agent sont faits pour exécuter du code dans un pipeline, donc le cadre légal et opérationnel doit être net.

Troisième limite : sans le flux complet GitHub Actions, une partie de la valeur reste théorique. J’ai validé le scanner local, la génération de stager, le callback Brisket et le serveur Kitchen. Je n’ai pas validé la création automatique de PR ni l’exploitation complète d’un runner GitHub public.

Est-ce que SmokedMeat marche vraiment ?

Oui, sur les briques que j’ai testées. Le build source fonctionne avec Go 1.26, les tests ciblés passent, le scanner trouve des injections réelles dans un workflow local, Kitchen enregistre un stager et Brisket sait rappeler le serveur en express.

Mon verdict reste nuancé : SmokedMeat marche, mais sa valeur maximale apparaît dans un vrai exercice CI/CD contrôlé, avec une organisation de test, un token GitHub adapté et Docker disponible. En mode local, il reste déjà utile pour montrer la qualité du moteur d’analyse et la mécanique de callback.

Faut-il adopter SmokedMeat ?

Pour une équipe red team, une équipe AppSec mature ou un freelance sécu qui fait des audits CI/CD, je dirais : essayer. L’outil peut aider à transformer une vulnérabilité abstraite en démonstration concrète.

Pour une équipe DevOps qui cherche seulement un scanner simple à brancher dans la CI, je dirais plutôt : passer, ou regarder poutine directement. SmokedMeat est un framework d’exercice offensif, pas un petit garde-fou de pipeline.

Mon verdict : à essayer en labo si vous voulez prouver l’impact d’une faille GitHub Actions. À éviter en production sans cadre d’autorisation strict.

FAQ

SmokedMeat remplace-t-il un scanner CI/CD classique ?

Non. Il va plus loin qu’un scanner, avec stager, agent et serveur C2. Pour du contrôle continu simple, un outil plus léger sera souvent préférable.

Peut-on utiliser SmokedMeat sans Docker ?

Partiellement, oui. J’ai compilé les binaires depuis les sources et lancé Kitchen avec NATS, puis testé le scanner local et Brisket. Le quickstart officiel et les scénarios complets restent pensés pour Docker.

SmokedMeat est-il dangereux ?

Oui, si on l’utilise hors cadre. Il est conçu pour démontrer des chemins d’attaque CI/CD. Il faut l’utiliser uniquement sur des environnements détenus ou explicitement autorisés.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *