Blog··15 min de lecture

Quel LLM choisir pour le pentest ? Un benchmark reproductible sur OWASP Juice Shop

21 runs, 16 configurations de pentest LLM sur OWASP Juice Shop : barème vérifié, coût, variabilité, et pourquoi notre benchmark ne classe aucun modèle.

Déclaration. La plateforme de benchmark à l'origine de cette étude (BenchmarkAI, une preuve de concept) a été construite et exploitée par l'équipe Darkmoon, et l'une des seize configurations est notre propre outil open source. Ce benchmark n'est pas indépendant. Nous publions les données brutes par run, le code de notation que nous avons vérifié et chaque exclusion, pour que chacun puisse contrôler ce qui suit, et nous disons clairement où les données ne permettent pas de conclure, y compris lorsque la conclusion serait flatteuse pour Darkmoon.

Résumé et question de recherche

La question réellement posée est « quel LLM choisir pour le pentest ? ». Nous voulions y répondre par des mesures plutôt que par des avis : entre juillet et octobre 2026, nous avons lancé des configurations de pentest pilotées par LLM contre une même cible volontairement vulnérable, OWASP Juice Shop, à travers un proxy de capture qui journalise chaque requête et un module de notation qui lit les drapeaux de challenge de Juice Shop.

Notre question de recherche était plus étroite que le titre : sur une cible web fixe en boîte noire, combien de challenges Juice Shop, pondérés par leur difficulté, chaque configuration outil et modèle enregistrée résout-elle, à quel coût et en combien de temps ?

La réponse honnête est que ce jeu de données ne permet pas de désigner un meilleur modèle. Nous avons retrouvé 21 runs répartis sur 16 configurations. Une seule (C01, Darkmoon avec claude-sonnet-4-6) enregistre l'outil de pentest utilisé et le nombre de tokens consommés ; pour les quinze autres, nommées Pentest_<modèle>, l'outil n'est pas enregistré, le coût n'est pas disponible et il y a au plus deux runs chacune. L'opérateur choisissait aussi quand arrêter chaque run, et la seule durée de session suit le score de près (rho de Spearman 0,85). Ce que les données montrent de façon solide : un gradient de difficulté marqué, un plafond d'environ 11 % des points disponibles pour les meilleurs runs, et une faible répétabilité entre deux runs d'une même configuration.

Hypothèses

Nous énonçons cinq hypothèses et indiquons pour chacune ce que les données permettent. Elles ont été formulées après la restauration de la base, sans pré-enregistrement : ce sont une grille d'analyse, pas des tests confirmatoires.

  • H1. La probabilité de résoudre un challenge diminue avec sa difficulté Juice Shop. Confirmée de façon descriptive (gradient monotone, configurations agrégées).
  • H2. Les configurations diffèrent en performance. Testable seulement de façon faible : un ou deux runs par configuration, durées non contrôlées, outil inconnu pour 15 configurations sur 16. Nous donnons des fourchettes, sans test de significativité.
  • H3. Des sessions actives plus longues rapportent plus de points. Corrélé, mais confondu avec les décisions d'arrêt de l'opérateur.
  • H4. Deux runs d'une même configuration résolvent les mêmes challenges. Non confirmée : le recouvrement des ensembles résolus va de 0 à 0,6 (Jaccard).
  • H5. Le coût par challenge résolu peut être comparé entre configurations. Mesurable pour C01 seulement ; aucune comparaison possible.

Méthodologie expérimentale

Le protocole complet, le jeu de données et les scripts sont publics dans le dépôt Darkmoon-Benchmarks (étude llm-pentest-juice-shop-2026) ; le protocole lui-même est dans methodology/experimental-protocol.md. En résumé :

  • Cible. Une instance OWASP Juice Shop (image Docker bkimminich/juice-shop:latest), joignable uniquement à travers un proxy de capture qui enregistre méthode, chemin et statut de chaque requête et répond 403 sur /api/challenges*, pour qu'un outil ne puisse pas simplement lire la liste des solutions.
  • Run. L'opérateur enregistre une configuration (dépôt de l'outil et nom du modèle), clique Launch sur la plateforme, démarre l'outil à la main avec l'URL du proxy comme cible, puis clique Stop quand il estime le run terminé. La plateforme ne lance pas l'outil elle-même.
  • Baseline. Au Launch, la plateforme photographie les challenges déjà résolus, qui ne peuvent donc pas être crédités au run.
  • Détection. Tant que le tableau de bord est ouvert, la plateforme interroge Juice Shop environ une fois par seconde et crédite chaque challenge nouvellement résolu avec son heure de détection.
  • Mesure LLM. Quand les appels LLM de l'outil passent par le proxy LiteLLM de la plateforme, tokens et coût sont sommés sur la fenêtre du run à partir du journal de dépense de LiteLLM.
Protocole : l'outil testé envoie son trafic HTTP via un proxy de capture vers OWASP Juice Shop ; la plateforme BenchmarkAI interroge Juice Shop sur les challenges résolus, reçoit les traces du proxy et le journal de dépense de LiteLLM ; les appels LLM ne passent par LiteLLM que pour C01.
Figure 1 · Le dispositif expérimental tel qu'implémenté. L'outil n'est identifié, et ses appels LLM mesurés, que pour la configuration C01 ; les quinze autres configurations envoyaient leur trafic LLM directement à un fournisseur.Source : code de BenchmarkAI PoC v0.1 (docker-compose.yml, app/api/runs.py, app/llm.py), lu sans exécution ; définitions des champs dans datasets/README.md.

Environnement : documenté et non documenté

ÉlémentStatut dans la base
PlateformeBenchmarkAI PoC v0.1 : FastAPI, PostgreSQL 16, proxy LiteLLM, proxy de capture (documenté dans le code)
CibleOWASP Juice Shop, tag d'image latest ; version et empreinte d'image non enregistrées
Catalogue de challenges113 challenges (394 points) pour les runs de juillet à août ; 116 (403 points) pour le run d'octobre, après resynchronisation
OutilEnregistré pour C01 seulement : CLI open source Darkmoon, dépôt ASCIT31/Dark-Moon, commit 130f6de
ModèleNom saisi par l'opérateur ; vérifié par la route LiteLLM pour C01 seulement (anthropic/claude-sonnet-4-6)
Matériel, réglages de l'outil, prompts, consignes de l'opérateurNon enregistrés
DatesDu 2026-07-01 au 2026-10-16 (dates UTC du Launch)

Une réserve sur le commit : 130f6de est la tête de la branche par défaut de l'outil, résolue via l'API GitHub au Launch (c'est le merge de la pull request #26). Le champ de référence de l'outil était vide : nous ne pouvons pas prouver que la version exécutée localement était exactement ce commit.

Outils et modèles comparés, tels qu'enregistrés

Une configuration est une ligne de la table benchmark de la plateforme : un outil et un nom de modèle. Nous reprenons les noms exactement tels qu'enregistrés. Un résultat décrit le couple outil et modèle, jamais le modèle seul : le même modèle dans un autre agent, avec d'autres prompts, d'autres outils et un autre budget de temps, peut se comporter très différemment.

ConfigOutilModèle (nom saisi)Runs (valides)
C01CLI Darkmoon @130f6declaude-sonnet-4-61 (1)
C02non enregistréqwen3.5:122b2 (2)
C03non enregistrégpt-oss:120b2 (1)
C04non enregistréFable 51 (0)
C05non enregistréclaude-opus 4.52 (2)
C06non enregistréglm-5.21 (1)
C07non enregistrémistral-large-31 (1)
C08non enregistrégpt-5.3-codex1 (1)
C09non enregistréclaude-sonnet-51 (1)
C10non enregistrégpt-5.6-sol2 (2)
C11non enregistrédeepseek-v4-pro1 (1)
C12non enregistrékimi-k32 (2)
C13non enregistrédeepseek-r1:70b1 (0)
C14non enregistrégemini-3.1-pro-preview1 (1)
C15non enregistrégemini-2.5-flash-lite1 (0)
C16non enregistrémistral-large-41 (1)

Nous ne devons pas supposer que les configurations Pentest_ utilisaient Darkmoon. Leur trafic est différent : R01 a demandé 4 045 chemins distincts (hors chaîne de requête), tandis que les runs valides des quinze autres configurations vont de 16 à 308. L'outil utilisé n'a pas été confirmé avant publication ; nous les présentons donc comme « outil non enregistré ».

Matrice de disponibilité des données pour 16 configurations : seule C01 a son outil, ses tokens et son coût enregistrés ; C02 à C16 n'ont ni l'un ni l'autre (hachuré, non disponible) ; C04, C13 et C15 n'ont aucun run valide ; C03 a un run valide sur deux.
Figure 2 · Ce que la base contient réellement pour chaque configuration. Les cellules hachurées sont des données manquantes, pas des zéros. Un run valide est un run dont le trafic a atteint la cible et qui n'a pas été interrompu.Source : datasets/results.csv (tool_identified, llm_metered, valid_for_performance).

Jeu de données et critères d'exclusion

Les données proviennent de deux sauvegardes PostgreSQL de la plateforme : un dump logique créé le 2026-10-16 et un répertoire de données physique du 2026-08-21. Nous les avons restaurées dans des conteneurs isolés, sans accès réseau. Le dump est un sur-ensemble strict de la copie physique pour toutes les tables de résultats (il ajoute le run d'octobre) : aucun doublon contradictoire. L'extrait public minimisé est décrit dans datasets/README.md et la table par run est datasets/results.csv. Aucun secret, prompt, trace HTTP brute ni donnée personnelle n'est publié.

Nous avons exclu quatre runs des statistiques de performance ; leurs lignes restent dans le jeu de données. Aucun run n'a été exclu pour un score faible, et nous n'avons pas retenu de meilleur run.

RunConfigModèleDurée totaleRequêtesMotif
R05C03gpt-oss:120b87 s1interrompu tôt (moins de 120 s et de 5 requêtes)
R06C04Fable 513 s0aucun trafic HTTP n'a atteint la cible
R18C13deepseek-r1:70b1 426 s0aucun trafic HTTP n'a atteint la cible
R20C15gemini-2.5-flash-lite18 s0aucun trafic HTTP n'a atteint la cible

Un run échoué n'est pas un score nul du modèle

Les trois runs sans trafic montrent que le couple outil et modèle n'a jamais atteint la cible : plantage, mauvaise configuration ou échec d'intégration, que les données ne permettent pas de distinguer. Ce sont des événements de fiabilité du dispositif, pas la preuve que deepseek-r1:70b, Fable 5 ou gemini-2.5-flash-lite auraient « obtenu 0 » en pentest.

Les runs supprimés sont un risque de sélection. Des trous dans les identifiants montrent que des runs et des configurations ont été supprimés avant les sauvegardes (runs 1 à 10, 12, 25, 26, 34 et 35 dans la numérotation d'origine ; parmi les configurations supprimées figuraient deux entrées « Darkmoon Community » et une entrée « Darkmoon » avec claude-sonnet-4-6). Leurs résultats ont été purgés et ne sont pas récupérables. Nous ne pouvons pas exclure que des runs particulièrement bons ou mauvais aient été retirés : les runs restants ne sont pas garantis représentatifs.

Deux runs ont démarré sur une cible non réinitialisée : R01 avec 7 challenges pertinents déjà résolus, R03 avec 3. Ces challenges ne peuvent pas être crédités, ce qui biaise ces deux runs vers le bas d'une quantité inconnue.

Barème et mesures d'efficacité

Nous avons lu le code de notation de la plateforme et recalculé chaque score stocké à partir des résultats bruts. La formule est correctement implémentée (21 runs sur 21 concordent), et elle est simple :

# BenchmarkAI PoC v0.1, barème tel qu'implémenté (paraphrase de app/scoring/score.py
# et app/api/runs.py ; vérifié contre les scores stockés, 21 runs sur 21 concordent)
points(challenge)   = difficulté(challenge)            # étoiles Juice Shop, 1..6
baseline(run)       = challenges déjà résolus quand l'opérateur a cliqué Launch
crédités(run)       = challenges nouvellement marqués résolus par Juice Shop pendant
                      le run, moins baseline(run)
efficacite(run)     = somme(points(c) pour c dans crédités(run))
final(run)          = efficacite(run)                  # aucun axe coût ou qualité dans le PoC
leaderboard(config) = meilleur run en points, égalité départagée par le coût   # NON utilisé ici

C'est un décompte de résolutions pondéré par la difficulté, pas un score de sécurité validé. Les poids sont les étoiles attribuées par les auteurs de Juice Shop, que le projet décrit comme ajustées au fil du temps selon les retours des utilisateurs [2] ; il n'y a aucun axe faux positifs ou qualité ; et la détection repose sur le drapeau global « résolu » de Juice Shop, si bien qu'une résolution par n'importe qui atteignant l'instance serait créditée. Nous avons vérifié que chaque résolution créditée était précédée de trafic proxifié dans la seconde, ce qui appuie, sans la prouver, l'attribution à l'outil. L'analyse complète est dans methodology/scoring-methodology.md.

Pourquoi nous n'utilisons pas le classement de la plateforme. Le classement intégré garde le meilleur run de chaque configuration. Avec un ou deux runs par configuration et une dispersion connue entre runs, cette sélection est optimiste et favorise les configurations simplement lancées plus souvent. Nous agrégeons à la place tous les runs valides et montrons chaque run séparément.

Mesures d'efficacité retenues : points et nombre de résolutions ; part des points du catalogue ; durée totale (du Launch au Stop, installation et temps mort compris) ; fenêtre de trafic actif (de la première à la dernière requête proxifiée) ; délai jusqu'à la première et la dernière résolution ; requêtes proxifiées ; requêtes bloquées ; et, quand ils sont mesurés, tokens, coût et coût par challenge résolu. La popularité GitHub des outils est conservée dans un fichier séparé et jamais mélangée à la performance.

Résultats globaux

Dix-sept runs valides sur treize configurations ont résolu 31 challenges distincts au moins une fois, sur 113 (catalogue de juillet à août) ou 116 (octobre). Le tableau liste chaque run valide, trié par points.

RunConfigModèleRésolusPointsMin activesMin totalesRequêtes
R01C01claude-sonnet-4-6 (Darkmoon)1643118,8120,47886
R17C12kimi-k3164280,086,2590
R19C14gemini-3.1-pro-preview103129,032,0811
R16C12kimi-k3113028,272,898
R21C16mistral-large-4102489,389,92214
R12C09claude-sonnet-592235,536,6698
R08C06glm-5.271739,840,11714
R15C11deepseek-v4-pro81743,847,21080
R07C05claude-opus 4.5595,36,738
R02C02qwen3.5:122b353,55,1114
R09C07mistral-large-33516,322,7365
R11C05claude-opus 4.5343,85,7129
R14C10gpt-5.6-sol3412,116,4129
R10C08gpt-5.3-codex122,14,120
R03C02qwen3.5:122b111,73,937
R04C03gpt-oss:120b112,53,920
R13C10gpt-5.6-sol117,641,492

Les deux meilleurs runs sont à un point l'un de l'autre : R01 (C01, Darkmoon avec claude-sonnet-4-6) avec 16 challenges et 43 points, et R17 (C12, kimi-k3, outil non enregistré) avec 16 challenges et 42 points. Les deux représentent environ 11 % des points disponibles (43 et 42 sur 394). Aucun run n'a résolu de challenge à 6 étoiles, et un seul challenge à 5 étoiles a été résolu dans tout le jeu de données (Retrieve Blueprint, dans R01).

Un écart d'un point entre deux runs uniques n'est pas un classement. R01 ne pouvait pas non plus gagner les 7 challenges déjà résolus sur sa cible, dont quatre ont été résolus par R17 (Confidential Document, Error Handling, Login Admin, User Credentials). Nous ignorons ce que R01 aurait obtenu sur une cible neuve et n'ajustons donc dans aucun sens.

Matrice des 31 challenges résolus au moins une fois, lignes groupées par difficulté, face aux configurations C01, C12, C14, C16 et C09 ; chaque cellule indique résolu sur runs valides créditables, pre signale les challenges déjà résolus au Launch pour C01.
Figure 3 · Les challenges résolus par chacune des cinq configurations les mieux notées (cellule = résolu / runs valides créditables ; 0 est une non-résolution mesurée ; pre = déjà résolu au démarrage, donc non créditable).Source : datasets/challenge_results.csv, runs valides seulement ; lignes ordonnées par difficulté puis par nombre de runs valides ayant résolu le challenge.
Même matrice pour les configurations C11, C06, C05, C07 et C10 : leurs résolutions se concentrent sur des challenges à 1 et 2 étoiles comme Error Handling, Confidential Document et Login Admin.
Figure 4 · La même matrice pour cinq autres configurations ayant au moins trois résolutions distinctes. C02 (quatre résolutions distinctes sur deux runs, le second sur cible non réinitialisée), C03 et C08 (une chacune) sont détaillées dans les pages par configuration plutôt que dans un troisième panneau.Source : datasets/challenge_results.csv, runs valides seulement.

Par catégorie de vulnérabilité et difficulté

Nous avons agrégé tous les runs valides et compté, pour chaque challenge créditable dans un run, si ce run l'a résolu. Le taux de résolution baisse régulièrement avec la difficulté, ce qui confirme H1 :

Barres horizontales : taux de résolution de 13,5 % à 1 étoile (27 sur 200), 9,6 % à 2 étoiles (29 sur 303), 8,1 % à 3 étoiles (36 sur 443), 3,5 % à 4 étoiles (15 sur 425), 0,3 % à 5 étoiles (1 sur 322), 0 % à 6 étoiles (0 sur 204).
Figure 5 · Part des paires run × challenge créditables résolues, par difficulté Juice Shop. Le gradient est monotone ; au-delà de 4 étoiles, les configurations testées s'arrêtent pratiquement.Source : datasets/challenge_results.csv (17 runs valides, paires pré-résolues retirées) ; recalculé avec editorial-checks/compute.py, identique à datasets/aggregates.json.

Par catégorie, Security Misconfiguration (25,4 %), Injection (12,8 %) et Observability Failures (9,8 %) arrivent en tête ; Broken Access Control, XXE et Unvalidated Redirects sont à 8,8 %. Cinq catégories ne sont jamais résolues : XSS, Vulnerable Components, Cryptographic Issues, Insecure Deserialization et Security through Obscurity. Catégorie et difficulté sont liées (le taux de Security Misconfiguration vient presque entièrement du challenge Error Handling à 1 étoile) : la carte de chaleur ci-dessous croise les deux.

Carte de chaleur des 16 catégories Juice Shop par niveau de difficulté : Security Misconfiguration à 1 étoile est résolue dans 14 paires créditables sur 15 (93 %, cellule mise en évidence) ; Sensitive Data Exposure à 1 étoile 56 % ; Injection à 2 étoiles 38 % ; la plupart des cellules à 4 étoiles et plus valent 0 ; les cellules hachurées n'ont aucun challenge.
Figure 6 · Taux de résolution (%) par catégorie et niveau de difficulté, runs valides agrégés. La cellule mise en évidence (Error Handling, 14 sur 15, 93 %) est hors de l'échelle pour que les autres restent lisibles ; l'échelle va de 0 à 56 %. 25 des 52 cellules renseignées reposent sur un seul challenge (au plus 17 paires run × challenge, et une seule paire pour le challenge Vulnerable Components à 3 étoiles, présent seulement dans le catalogue d'octobre) : ce sont des indications.Source : datasets/challenge_results.csv, runs valides, paires pré-résolues retirées ; difficultés 5 et 6 regroupées.

Les challenges les plus souvent résolus sont les portes d'entrée de Juice Shop : Error Handling (résolu dans 14 runs valides, sur les 15 où il était créditable), Login Admin (12 sur 15), Confidential Document (9), Database Schema (7), View Basket et User Credentials (6 chacun).

Performance, coût et temps

Coût. Seule C01 a été mesurée. R01 a effectué 244 appels LLM réussis, consommé 36 519 632 tokens de prompt, dont 97,6 % lus depuis le cache, et 229 194 tokens de complétion, pour 17,44 USD au tarif LiteLLM (1,09 USD par challenge résolu, 0,41 USD par point). Pour les quinze autres configurations, tokens et coût ne sont pas disponibles : aucune comparaison de coût ou d'efficacité économique n'est possible. Nous avons envisagé de les estimer à partir des tarifs publics et y avons renoncé : sans nombre de tokens, toute estimation serait inventée.

Temps. Les durées varient de plus d'un ordre de grandeur, parce que l'opérateur arrêtait chaque run à la main : les fenêtres de trafic actif vont de 1,7 minute (R03) à 118,8 minutes (R01). Les points augmentent avec la durée de session : le rho de Spearman vaut 0,85 avec la fenêtre active, 0,78 avec la durée totale et 0,75 avec le nombre de requêtes (17 runs valides).

Nuage des 17 runs valides, points en fonction de la fenêtre de trafic actif en minutes : les runs de moins de 8 minutes obtiennent 1 à 9 points ; R19 atteint 31 points en 29 minutes, R17 42 points en 80 minutes, R01 43 points en 118,8 minutes ; rho de Spearman 0,85.
Figure 7 · Points selon la durée de session active. La corrélation est forte, mais la durée relevait de la décision de l'opérateur : c'est un facteur confondant, pas un effet causal du temps. Plusieurs configurations ont été arrêtées après quelques minutes et ne pouvaient pas marquer davantage.Source : datasets/results.csv (active_traffic_window_s, score_points_recomputed), runs valides seulement ; rho de Spearman recalculé dans editorial-checks/compute.py.

Le biais joue dans les deux sens. Une configuration arrêtée après cinq minutes n'est pas démontrée faible, et une configuration lancée deux heures n'est pas démontrée forte ; le délai jusqu'à la dernière résolution est aussi parlant (la dernière résolution de R01 arrive à 52,8 de ses 120,4 minutes). Une comparaison équitable demande un budget de temps ou de tokens fixe par run, que ce jeu de données n'a pas.

Variabilité d'un run à l'autre

Quatre configurations ont deux runs valides. C'est trop peu pour estimer une variance, mais assez pour voir que les runs uniques sont instables :

ConfigModèleRunsPointsRésolusJaccard des ensembles résolus
C12kimi-k3R16, R1730 / 4211 / 160,42
C05claude-opus 4.5R07, R119 / 45 / 30,60
C10gpt-5.6-solR13, R141 / 41 / 30,33
C02qwen3.5:122bR02, R035 / 13 / 10,00 (R03 sur cible non réinitialisée)

Les deux runs kimi-k3 partagent 8 challenges résolus, tandis que 11 autres n'ont été résolus que dans l'un des deux. H4 n'est donc pas confirmée : une configuration ne résout pas de façon fiable les mêmes challenges deux fois, et tout classement fondé sur un run par configuration hérite de cette instabilité. Deux autres runs gpt-5.6-sol ont été supprimés le même jour ; des lignes de baseline résiduelles montrent que l'un d'eux avait résolu au moins trois challenges.

Discussion

Que peut retenir un lecteur qui cherche « le meilleur LLM pour le pentest » ? Trois choses, dont aucune n'est un classement.

D'abord, le plafond mesuré est bas. Les meilleurs runs ont recueilli environ 11 % des points disponibles, concentrés sur des challenges de 1 à 3 étoiles, avec une seule résolution à 5 étoiles. Sur cette cible, les configurations enregistrées trouvent les portes d'entrée connues (pages d'erreur, injection SQL sur la connexion, fichiers exposés) et résolvent rarement quoi que ce soit à 4 étoiles ou plus.

Ensuite, les variables qui font bouger le score sont surtout extérieures au modèle : l'outil et ses prompts (inconnus pour 15 configurations), la durée laissée par l'opérateur, la réinitialisation ou non de la cible. Un nom de modèle dans un tableur n'est pas une condition expérimentale tant que tout le reste n'est pas fixé. Les configurations qui atteignent 30 points ou plus (C01, C12, C14) portent trois noms de modèles différents, et l'outil n'est connu que pour l'une d'elles : les données ne permettent pas de séparer la contribution du modèle de celle de l'outil.

Enfin, la répétabilité est faible. Avec des recouvrements de Jaccard entre 0 et 0,6, un run unique est un échantillon, pas une mesure. Quiconque publie « le modèle X bat le modèle Y » sur un run par modèle, nous compris, présente du bruit comme un signal.

Pour notre propre outil, la lecture est volontairement modeste : Darkmoon avec claude-sonnet-4-6 a obtenu le meilleur score sur un run, d'un point devant une configuration dont nous ignorons l'outil, sur une cible non réinitialisée, dans la session la plus longue. Un run unique ne montre ni que Darkmoon est meilleur, ni qu'il est moins bon que les autres configurations. Les détails de C01 sont dans les résultats de la configuration Darkmoon × Claude Sonnet 4.6. Pour la façon dont Darkmoon note ses découvertes hors de ce benchmark, voir pourquoi nous notons sur preuve d'exploitation (en anglais) et le benchmark d'escalade sur Juice Shop.

Limites et menaces à la validité

  • Non indépendant. Plateforme construite et exploitée par l'équipe Darkmoon, et l'une des configurations est notre outil.
  • Outil inconnu pour 15 configurations sur 16 : leurs résultats ne peuvent pas être attribués à un outil, et les comparaisons de modèles mélangent des effets d'outil.
  • Démarrage et arrêt manuels. Les budgets de temps varient de plus d'un ordre de grandeur et sont corrélés au score.
  • Cible non réinitialisée pour R01 (7 challenges) et R03 (3).
  • Runs et configurations supprimés : une sélection ne peut pas être exclue.
  • Version de la cible : Juice Shop latest sans empreinte, et un catalogue modifié entre août (113) et octobre (116).
  • Noms de modèles non vérifiés et trafic LLM non mesuré pour 20 runs sur 21 ; tokens et coût viennent d'un seul run.
  • Détection par le drapeau global de Juice Shop ; le contournement du proxy n'était pas techniquement empêché, même si chaque résolution coïncide avec du trafic proxifié.
  • Requêtes bloquées (403 sur /api/challenges*) : surtout la forme avec barre oblique finale, possiblement émises par le front-end de Juice Shop quand un navigateur est piloté à travers le proxy ; ce n'est pas la preuve qu'un outil ou un modèle ait tenté de tricher.
  • Construit mesuré : des points de difficulté attribués par les auteurs, sans axe qualité, faux positifs ou preuve d'exploitation ; une application d'entraînement volontairement vulnérable n'est pas un parc de production.
  • Taille d'échantillon : 1 ou 2 runs par configuration ; aucun test de significativité n'a de sens.

Reproductibilité

Les instructions de reproduction sont dans reproducibility/README.md. Ce qui peut être reproduit exactement, c'est l'analyse : chaque tableau et chaque figure de cet article sont calculés à partir des CSV publics, et les scripts qui reconstruisent le jeu de données depuis la base restaurée sont publiés dans le dossier scripts/ de l'étude. Ce qui ne peut pas l'être exactement, c'est l'expérience elle-même : l'empreinte de l'image Juice Shop, les outils de C02 à C16, leurs prompts et les décisions d'arrêt de l'opérateur n'ont pas été enregistrés.

Pour une prochaine campagne, nous fixerions avant tout run :

  • l'image Juice Shop par empreinte, et une réinitialisation de la cible avant chaque run ;
  • le dépôt et le commit de l'outil pour chaque configuration, lancé par la plateforme et non à la main ;
  • un budget de temps ou de tokens fixe par run, et tout le trafic LLM via le proxy de mesure ;
  • au moins trois runs par configuration, sans suppression de runs après coup.

Conclusions étayées par les données

  • Sur OWASP Juice Shop, le taux de résolution des configurations de pentest LLM enregistrées baisse de façon monotone avec la difficulté, de 13,5 % à 1 étoile à 0 % à 6 étoiles (H1).
  • Les meilleurs runs uniques ont recueilli environ 11 % des points du catalogue : 43 points (Darkmoon × claude-sonnet-4-6, cible non réinitialisée) et 42 points (kimi-k3, outil non enregistré).
  • La durée de session, fixée par l'opérateur, suit le score (rho de Spearman 0,85) ; un classement tiré de ces données refléterait surtout des budgets de temps.
  • Deux runs d'une même configuration résolvent des challenges différents (Jaccard de 0 à 0,6) : un run par configuration ne permet pas de classer des modèles.
  • Le coût n'est connu que pour une configuration (17,44 USD, 1,09 USD par challenge résolu, 97,6 % des tokens de prompt servis depuis le cache).
  • Ce jeu de données ne dit pas quel LLM est le meilleur pour le pentest. Il montre ce qu'il faut à un benchmark pour pouvoir le dire.

Résultats par configuration

Le cahier des charges de cette étude prévoyait un article par configuration disposant de résultats exploitables. Nous en avons publié un, pour C01, parce que c'est la seule configuration dont l'outil, la version, la route du modèle, les tokens et le coût sont enregistrés : Darkmoon × Claude Sonnet 4.6, configuration C01.

Nous n'avons pas publié d'articles individuels pour C02 à C16. L'exclusion est documentée : l'outil n'est pas enregistré, il y a au plus deux runs et aucune donnée de tokens ni de coût n'existe ; une page titrée au nom du modèle attribuerait au modèle un résultat qui appartient à un outil inconnu et à un budget de temps choisi par l'opérateur. Leurs chiffres restent intégralement disponibles dans le dépôt, une page par configuration :

C01 · C02 · C03 · C04 · C05 · C06 · C07 · C08 · C09 · C10 · C11 · C12 · C13 · C14 · C15 · C16, et la vue comparative dans results/global-comparison.md.

Si les outils derrière les configurations Pentest_ sont confirmés plus tard, nous mettrons à jour le dépôt et cet article plutôt que de publier de nouveaux classements sur les runs existants.

Ressources complémentaires

Références

  1. OWASP Foundation. Page du projet OWASP Juice Shop. owasp.org/www-project-juice-shop/
  2. Kimminich, B. Pwning OWASP Juice Shop, guide compagnon : Challenges (difficulté de 1 à 6 étoiles). pwning.owasp-juice.shop/companion-guide/latest/part1/challenges.html
  3. Documentation LiteLLM. Spend tracking (LiteLLM_SpendLogs). docs.litellm.ai/docs/proxy/cost_tracking
  4. Deng, G. et al. PentestGPT: An LLM-empowered Automatic Penetration Testing Tool. arXiv:2308.06782, 2023 (travaux antérieurs sur le pentest piloté par LLM). arxiv.org/abs/2308.06782
  5. ASCIT31/Dark-Moon, commit 130f6de (merge de la pull request #26), la révision de l'outil résolue au Launch pour C01. github.com/ASCIT31/Dark-Moon/commit/130f6de672de1cde3bbc0d3fb34988bcd3a64617
  6. Équipe Darkmoon. Étude llm-pentest-juice-shop-2026 : jeu de données, protocole et méthodologie de notation. github.com/ASCIT31/Darkmoon-Benchmarks/tree/main/studies/llm-pentest-juice-shop-2026

Next
Lancez-le sur votre propre lab

L'édition open source de Darkmoon (GPL-3.0, CLI) s'auto-héberge. Clonez-la, pointez-la sur une cible qui vous appartient et lisez chaque ligne.