Aller au contenu
Sécurité medium

Nuclei : scanner de vulnérabilités rapide

36 min de lecture

nucei cli

En décembre 2021, la faille Log4Shell (CVE-2021-44228) est découverte dans Log4j. En quelques heures, un template Nuclei est publié par la communauté. Dans les jours suivants, des milliers de professionnels scannent leurs infrastructures pour vérifier s'ils sont exposés. Cette réactivité illustre la puissance de l'écosystème Nuclei : plus de 13 000 templates maintenus par la communauté, prêts à détecter les dernières vulnérabilités.

Dans ce guide, je présente :

  • Ce qu'est Nuclei et pourquoi il se démarque
  • Comment l'installer sur différents systèmes
  • Les commandes essentielles pour débuter
  • L'utilisation des templates et leur personnalisation
  • L'intégration dans un pipeline CI/CD

Avant de plonger dans Nuclei, clarifions quelques termes qui reviendront souvent dans ce guide.

Le DAST (Dynamic Application Security Testing) désigne les tests de sécurité effectués sur une application en cours d'exécution. Contrairement au SAST qui analyse le code source, le DAST teste l'application comme le ferait un attaquant, c'est un test en "boîte noire".

Un template est le cœur de Nuclei : c'est un fichier YAML qui décrit comment détecter une vulnérabilité spécifique. Chaque template contient les requêtes à envoyer et les critères pour identifier un problème.

Les CVE (Common Vulnerabilities and Exposures) sont des identifiants uniques attribués aux vulnérabilités connues. Par exemple, CVE-2021-44228 désigne la fameuse faille Log4Shell. Nuclei dispose de templates pour des milliers de CVE.

Un matcher est la règle qui vérifie si une réponse correspond à une vulnérabilité. Il peut chercher un mot spécifique, un code HTTP, ou un pattern regex dans la réponse du serveur.

La sévérité indique la gravité d'une vulnérabilité. Nuclei utilise cinq niveaux : info (informatif), low (faible), medium (modéré), high (élevé) et critical (critique). Cette classification aide à prioriser les corrections.

Enfin, les tags sont des étiquettes qui catégorisent les templates. On trouve par exemple cve pour les vulnérabilités référencées, exposure pour les fichiers exposés, ou wordpress pour les failles spécifiques à ce CMS.

Nuclei est un scanner de vulnérabilités rapide et extensible développé par ProjectDiscovery. Il teste des sites web, applications web, API REST et services réseau exposés (HTTP, DNS, TCP). Contrairement aux scanners traditionnels qui embarquent leurs propres signatures, Nuclei repose sur des templates YAML décrivant comment détecter une vulnérabilité.

Concrètement, quand on lance Nuclei sur une cible, l'outil commence par charger les templates depuis le dossier ~/nuclei-templates/. Ensuite, pour chaque template, il envoie une ou plusieurs requêtes à la cible. Il analyse alors la réponse pour voir si elle correspond aux critères définis dans le template. Si c'est le cas, il signale une potentielle vulnérabilité avec tous les détails utiles : sévérité, URL concernée, et pattern détecté.

Ce qui distingue Nuclei des scanners traditionnels, c'est d'abord sa vitesse. Écrit en Go avec une architecture hautement concurrente, il peut tester des milliers de cibles en parallèle. Là où un scanner classique prendrait des heures, Nuclei termine en minutes.

L'extensibilité est son second atout majeur. Les templates YAML sont simples à lire et à écrire. Pas besoin de maîtriser un SDK complexe pour ajouter une détection personnalisée, quelques lignes de YAML suffisent.

La communauté fait le reste. La version v10.4.6 de nuclei-templates compte 10 970 templates HTTP et 4 283 templates taggés cve, maintenus par des contributeurs du monde entier ; le fichier TEMPLATES-STATS.md livré avec le dépôt donne le décompte exact de votre version. Quand une nouvelle CVE tombe, un template apparaît souvent dans les heures qui suivent.

Côté intégration, Nuclei est pensé CLI-first. Il s'intègre naturellement dans les pipelines CI/CD, là où beaucoup de scanners commerciaux nécessitent une interface graphique. Dernier point qui compte en pratique : il est open source et gratuit, donc utilisable sans négociation de licence par poste ou par cible.

Nuclei couvre un large spectre de problèmes de sécurité. Les CVE connues constituent une part importante : Log4Shell, ProxyShell, les RCE Confluence... tous les grands classiques sont couverts.

Au-delà des CVE, Nuclei excelle dans la détection de misconfigurations : headers de sécurité manquants, mode debug activé en production, CORS trop permissifs. Ces problèmes ne sont pas des vulnérabilités au sens strict, mais ils facilitent les attaques.

Les templates d'exposition recherchent les fichiers et pages qui ne devraient pas être accessibles : répertoires .git exposés, backups oubliés, panels d'administration sans authentification.

Nuclei peut aussi identifier les technologies utilisées par une cible : version de WordPress, type de serveur web, frameworks JavaScript. Ces informations aident à cibler les tests suivants.

Enfin, certains templates détectent des secrets dans les réponses HTTP : clés API, tokens d'authentification, credentials exposés par erreur.

Nuclei s'installe facilement sur tous les systèmes. Le choix de la méthode dépend de l'environnement et du niveau de confort avec les outils.

Pour les débutants sans Go installé, Homebrew (sur macOS ou Linux) ou le binaire précompilé sont les options les plus simples. Les développeurs habitués à Go préféreront go install pour des mises à jour faciles.

go install compile Nuclei depuis les sources et dépose le binaire dans $GOPATH/bin (~/go/bin par défaut). Ce répertoire doit être dans votre PATH, sinon la commande nuclei restera introuvable après une installation pourtant réussie. Épinglez toujours la version avec @v3.11.0 plutôt que @latest : c'est ce qui rend l'installation reproductible entre votre poste et un runner de CI.

Fenêtre de terminal
# Nécessite Go 1.21+
# Remplacer v3.11.0 par la dernière version stable
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@v3.11.0
# Vérifier l'installation
nuclei -version

La sortie attendue est Nuclei Engine Version: v3.11.0, écrite sur la sortie d'erreur et non sur la sortie standard.

Homebrew installe un binaire déjà compilé, sans dépendre de Go. En contrepartie, vous récupérez la version que la formule propose au moment de l'installation : vous ne choisissez pas la vôtre. Sur un poste de travail c'est confortable, sur un runner CI préférez go install avec une version épinglée ou l'image de conteneur officielle.

Fenêtre de terminal
brew install nuclei

Cette méthode évite d'installer Go, mais elle vous rend responsable de la vérification d'intégrité de l'archive. ProjectDiscovery publie un fichier nuclei_<version>_checksums.txt à côté des binaires de chaque release : téléchargez-le systématiquement et validez l'archive avant de déplacer quoi que ce soit dans /usr/local/bin/. Sans cette étape, vous exécutez en root un binaire dont rien n'atteste la provenance.

Fenêtre de terminal
# Linux AMD64 (remplacer v3.11.0 par la version souhaitée)
wget https://github.com/projectdiscovery/nuclei/releases/download/v3.11.0/nuclei_3.11.0_linux_amd64.zip
wget https://github.com/projectdiscovery/nuclei/releases/download/v3.11.0/nuclei_3.11.0_checksums.txt
# Vérifier l'empreinte SHA-256 avant toute extraction
sha256sum --ignore-missing --check nuclei_3.11.0_checksums.txt
unzip nuclei_3.11.0_linux_amd64.zip
sudo mv nuclei /usr/local/bin/
# Vérifier
nuclei -version

La commande sha256sum doit afficher nuclei_3.11.0_linux_amd64.zip: OK. Toute autre réponse, y compris un simple avertissement, doit stopper l'installation.

Au premier lancement, Nuclei télécharge automatiquement les templates communautaires dans ~/nuclei-templates/. Pour les mettre à jour :

Fenêtre de terminal
nuclei -update-templates

Nouveauté Nuclei 3.11 : les templates personnalisés utilisant le protocole javascript: doivent désormais être signés pour être chargés, les templates JS non signés sont ignorés au chargement et lorsqu'un workflow les référence. Les templates officiels de nuclei-templates sont pré-signés et vérifiés avec la clé publique de ProjectDiscovery, les scans par défaut ne sont donc pas affectés. Pour signer vos propres templates JS : nuclei -sign -t mon-template.yaml, avec la clé privée fournie par la variable d'environnement NUCLEI_SIGNATURE_PRIVATE_KEY.

Pour pratiquer sans risque légal, on va utiliser OWASP Juice Shop : une application web intentionnellement vulnérable, conçue pour l'apprentissage de la sécurité. Elle contient des dizaines de failles que Nuclei peut détecter.

Le point à ne pas rater dans la commande ci-dessous est la publication de port 127.0.0.1:3000:3000. Écrire -p 3000:3000 ferait écouter Juice Shop sur toutes les interfaces de la machine, donc potentiellement sur le réseau local : une application volontairement vulnérable n'a rien à y faire. Le --rm détruit le conteneur à l'arrêt et garantit un état propre à chaque session, et la version épinglée v17.1.1 rend les résultats comparables d'une exécution à l'autre.

Fenêtre de terminal
# Lancer Juice Shop avec Docker (version épinglée, écoute sur la boucle locale)
docker run --rm -d -p 127.0.0.1:3000:3000 --name juice-shop bkimminich/juice-shop:v17.1.1
# Vérifier que l'application est accessible
curl -s http://localhost:3000 | head -5

L'application est maintenant disponible sur http://localhost:3000. On peut aussi y accéder via un navigateur pour explorer l'interface. Ce sera notre cible pour tous les exemples qui suivent.

Quand on lance Nuclei, l'outil commence par charger tous les templates depuis le dossier ~/nuclei-templates/. Ensuite, pour chaque template, il envoie une ou plusieurs requêtes à la cible. Les réponses sont alors comparées aux matchers définis dans chaque template. Enfin, les correspondances sont affichées dans le terminal avec tous les détails utiles.

Le premier scan peut prendre du temps, parfois 10 à 30 minutes, car Nuclei teste des milliers de templates. Pour des tests plus rapides, on peut filtrer par sévérité ou par tags comme expliqué plus loin.

Commencez toujours par la première commande, celle qui filtre sur -tags exposure,misconfig. Elle réduit le jeu de templates à environ deux mille au lieu de treize mille et rend le premier scan lisible en une trentaine de secondes. Le scan complet sans filtre a sa place, mais pas pour découvrir l'outil : vous y perdriez le lien entre une ligne de résultat et le template qui l'a produite. Le troisième appel, avec -v, affiche chaque requête envoyée et sert surtout quand un template ne se déclenche pas alors qu'il le devrait.

Fenêtre de terminal
# Scan rapide sur Juice Shop (exposures et misconfigs seulement)
nuclei -u http://localhost:3000 -tags exposure,misconfig
# Scan complet avec tous les templates (plus long)
nuclei -u http://localhost:3000
# Scan avec sortie détaillée (voir ce qui se passe)
nuclei -u http://localhost:3000 -v

Sur Juice Shop, Nuclei détecte plusieurs problèmes en quelques secondes. Voici un exemple de sortie réelle :

[INF] Templates loaded for current scan: 1978
[swagger-api] [http] [info] http://localhost:3000/api-docs/swagger.json [paths="/api-docs/swagger.json"]
[http-missing-security-headers:strict-transport-security] [http] [info] http://localhost:3000
[http-missing-security-headers:content-security-policy] [http] [info] http://localhost:3000
[http-missing-security-headers:permissions-policy] [http] [info] http://localhost:3000
[missing-sri] [http] [info] http://localhost:3000/ ["//cdnjs.cloudflare.com/..."]
[prometheus-metrics] [http] [medium] http://localhost:3000/metrics
[INF] Scan completed in 30.601140469s. 11 matches found.

Chaque ligne de résultat suit un format standard. Prenons l'exemple de la ligne [prometheus-metrics] [http] [medium] http://localhost:3000/metrics :

Le premier élément [prometheus-metrics] est l'identifiant du template qui a déclenché l'alerte. Ici, Nuclei a détecté que l'endpoint /metrics de Prometheus est exposé publiquement, ce qui peut révéler des informations sensibles sur l'infrastructure.

Le deuxième élément [http] indique le protocole utilisé pour le test. Nuclei supporte HTTP, DNS, TCP, et d'autres protocoles.

Le troisième élément [medium] est la sévérité. Sur les 11 résultats de notre scan, un seul est de sévérité moyenne (les métriques Prometheus exposées), les autres sont informatifs (headers manquants).

Enfin, l'URL montre exactement où le problème a été détecté. Certains résultats incluent des détails supplémentaires entre crochets, comme les ressources externes sans SRI (Subresource Integrity).

Nuclei est conçu pour minimiser les faux positifs, mais ils existent. La première règle est de vérifier manuellement chaque finding avant de le reporter ou de paniquer. Un résultat de scan n'est pas une preuve d'exploitation.

Pour réduire le bruit, on peut exclure les templates bruyants via le fichier de configuration. Après quelques scans, on identifie vite les templates qui génèrent des résultats non pertinents dans son contexte.

L'option -ms (matcher-status) affiche les échecs de matching, ce qui aide à comprendre pourquoi un template s'est déclenché. C'est utile pour distinguer un vrai positif d'un faux positif.

Enfin, la communauté Nuclei accueille volontiers les contributions. Si on identifie un template qui génère trop de faux positifs, on peut proposer une correction sur le dépôt GitHub.

Une fois les tests terminés, arrêtez le conteneur. Comme il a été lancé avec --rm, l'arrêt le supprime aussi, il ne reste donc aucun conteneur ni volume résiduel exposant une application vulnérable sur le poste. Vérifiez-le avec docker ps -a, qui ne doit plus lister juice-shop.

Fenêtre de terminal
docker stop juice-shop
docker ps -a --filter name=juice-shop

Les sévérités permettent de prioriser les résultats :

SévéritéSignificationAction recommandée
criticalExploitation immédiate possible (RCE, auth bypass)Corriger immédiatement
highRisque élevé, exploitation probableCorriger rapidement
mediumRisque modéré, exploitation sous conditionsPlanifier la correction
lowRisque faible, impact limitéÀ évaluer selon contexte
infoInformation, pas de vulnérabilitéPour investigation
Fenêtre de terminal
# Uniquement les vulnérabilités critiques et hautes
nuclei -u http://localhost:3000 -severity critical,high
# Exclure les informatives (recommandé pour un premier scan)
nuclei -u http://localhost:3000 -es info

Les templates sont catégorisés par tags, ce qui permet de cibler précisément le type de vulnérabilités à rechercher.

Le tag cve regroupe les templates qui détectent des vulnérabilités référencées : Log4Shell, ProxyShell, et des milliers d'autres. Le tag exposure cible les fichiers et pages qui ne devraient pas être accessibles : backups, fichiers de configuration, répertoires .git exposés.

Pour les erreurs de configuration, le tag misconfig détecte les problèmes comme les headers de sécurité manquants, les CORS trop permissifs ou le mode debug activé en production. Le tag tech permet d'identifier les technologies utilisées par la cible : CMS, frameworks, serveurs web.

On trouve aussi des tags spécifiques à certaines technologies. Par exemple, wordpress regroupe toutes les vulnérabilités connues de ce CMS. Le tag panel recherche les interfaces d'administration exposées sans protection.

Fenêtre de terminal
# Scanner uniquement les CVE
nuclei -u http://localhost:3000 -tags cve
# Scanner les expositions et misconfigurations
nuclei -u http://localhost:3000 -tags exposure,misconfig
# Scanner une technologie spécifique
nuclei -u http://localhost:3000 -tags wordpress

Combiner les tags permet d'affiner la recherche selon le contexte. Sur un site WordPress, on utilisera -tags wordpress,cve. Pour un audit rapide, -tags exposure,misconfig donne de bons résultats en peu de temps.

Il est possible d'exporter les résultats dans plusieurs formats pour analyse ou intégration dans des outils tiers.

Fenêtre de terminal
# Format JSON (recommandé pour l'automatisation)
nuclei -u http://localhost:3000 -jsonl -o results.jsonl
# Format SARIF (intégration GitHub/GitLab)
nuclei -u http://localhost:3000 -sarif-export results.sarif
# Format Markdown
nuclei -u http://localhost:3000 -markdown-export ./reports/

Le format JSONL (JSON Lines) est idéal pour le traitement automatisé et l'ingestion dans des outils comme Elasticsearch ou Splunk. Le format SARIF s'intègre nativement avec GitHub Security et GitLab.

Les templates sont le cœur de Nuclei. Chaque template est un fichier YAML qui répond à une question simple : "Comment détecter cette vulnérabilité ?"

Un template décrit trois choses, et rien d'autre. Ce qu'on envoie : une URL construite à partir de la cible, une méthode HTTP, éventuellement des headers et un corps de requête. Ce qu'on cherche dans la réponse : un mot, un code de statut, une expression régulière. Et la conclusion à en tirer : si les critères sont satisfaits, la cible est signalée comme potentiellement vulnérable, avec la sévérité déclarée dans le template.

Un template se compose de quatre éléments. Le bloc info contient l'identité du check : son identifiant unique, son nom, l'auteur, la sévérité et les tags. Le bloc http (ou dns, tcp selon le protocole) décrit ce qu'on envoie à la cible. Les matchers définissent les critères pour détecter une vulnérabilité. Enfin, les extractors (optionnels) permettent d'extraire des informations utiles de la réponse.

Voici un template simple commenté pour comprendre chaque partie :

# Identifiant unique du template (utilisé dans les rapports)
id: git-config-exposure
# Métadonnées : qui, quoi, gravité
info:
name: Git Config File Exposure
author: ice3man
severity: medium
description: Détecte l'exposition du fichier .git/config
tags: git,config,exposure
# La requête HTTP à envoyer
http:
- method: GET
path:
# {{BaseURL}} sera remplacé par l'URL cible
- "{{BaseURL}}/.git/config"
# Conditions pour déclarer une vulnérabilité
matchers:
- type: word
words:
# Si ces deux mots sont présents dans la réponse...
- "[core]"
- "[remote"
# ...ET qu'ils sont tous les deux présents
condition: and

Ce template fait une chose simple : il accède à /.git/config et vérifie si la réponse contient des marqueurs d'un fichier de configuration Git. Si oui, le fichier est exposé publiquement, problème de sécurité.

Ces trois commandes servent à explorer le dépôt local sans lancer le moindre scan, donc sans toucher à une cible. -tl sort la liste complète des chemins de templates, -tgl sort la liste des tags utilisables avec -tags, et -td affiche le contenu YAML d'un template précis. Le point qui bloque le plus souvent est le chemin : les templates HTTP vivent sous http/ dans ~/nuclei-templates/, pas à la racine. Un -t cves/2021/... renvoie Could not find template, alors que -t http/cves/2021/... fonctionne.

Fenêtre de terminal
# Lister tous les templates
nuclei -tl
# Lister les tags disponibles
nuclei -tgl
# Afficher un template spécifique
nuclei -t http/cves/2021/CVE-2021-44228.yaml -td

Cibler un template plutôt que la collection entière change complètement la durée du scan : on passe de plusieurs milliers de requêtes à quelques-unes. C'est le réflexe à avoir quand une CVE vient de sortir et que vous voulez seulement savoir si votre parc est concerné. -t accepte indifféremment un fichier, un répertoire, et peut être répété pour combiner plusieurs sources. Les chemins restent relatifs à ~/nuclei-templates/, préfixe http/ compris.

Fenêtre de terminal
# Exécuter un template précis
nuclei -u http://localhost:3000 -t http/cves/2021/CVE-2021-44228.yaml
# Exécuter tous les templates d'un dossier
nuclei -u http://localhost:3000 -t http/cves/2024/
# Combiner plusieurs sources
nuclei -u http://localhost:3000 -t http/cves/ -t http/exposures/

Le template ci-dessous cherche une page de debug exposée, un besoin que les templates communautaires couvrent mal parce que les chemins varient d'une application maison à l'autre. Deux éléments méritent l'attention : la clé matchers-condition: or, qui déclenche l'alerte dès qu'un seul matcher correspond, et le matcher de type status, qui à lui seul remonterait toute réponse HTTP 200. Combinés en or, ils produisent beaucoup de faux positifs : c'est un exemple pédagogique, pas un template prêt pour la production, où matchers-condition: and est presque toujours le bon choix.

id: debug-page-exposure
info:
name: Debug Page Exposure
author: votre-nom
severity: low
description: Détecte des pages de debug exposées
tags: debug,exposure,custom
http:
- method: GET
path:
- "{{BaseURL}}/debug"
- "{{BaseURL}}/_debug"
- "{{BaseURL}}/debug.php"
matchers-condition: or
matchers:
- type: word
words:
- "Debug Information"
- "Stack Trace"
- "Environment Variables"
- type: status
status:
- 200

Avant de déployer un template en production, il est essentiel de le valider. Nuclei charge et parse le YAML, puis exécute les requêtes définies. Un template mal formé sera rejeté au chargement, mais un template syntaxiquement correct peut quand même produire des faux positifs ou rater des vulnérabilités.

La démarche de validation se fait en trois étapes. D'abord, créer le fichier template dans un dossier dédié :

Fenêtre de terminal
# Créer un dossier pour les templates personnalisés
mkdir -p ~/nuclei-templates-custom
# Créer le fichier template
cat > ~/nuclei-templates-custom/debug-page.yaml << 'EOF'
id: debug-page-exposure
info:
name: Debug Page Exposure
author: votre-nom
severity: low
description: Détecte des pages de debug exposées
tags: debug,exposure,custom
http:
- method: GET
path:
- "{{BaseURL}}/debug"
- "{{BaseURL}}/_debug"
matchers:
- type: word
words:
- "Debug Information"
- "Stack Trace"
EOF

Ensuite, exécuter le template avec le flag -v (verbose) pour voir exactement ce que Nuclei fait :

Fenêtre de terminal
nuclei -u http://localhost:3000 -t ~/nuclei-templates-custom/debug-page.yaml -v

La sortie verbose montre chaque requête envoyée. Si le template est valide, Nuclei affiche le nombre de templates chargés (1) et les requêtes HTTP effectuées. Un message "No results found" est normal si la cible ne présente pas la vulnérabilité recherchée, cela confirme que le template fonctionne mais n'a rien détecté.

Par défaut, Nuclei envoie jusqu'à 150 requêtes par seconde. Cette agressivité est parfaite pour scanner ses propres infrastructures, mais elle peut poser problème dans certains contextes : saturer un serveur de test, déclencher des alert WAF, ou simplement être mal perçu lors d'un audit client.

L'optimisation des scans consiste à trouver le bon équilibre entre vitesse et discrétion, tout en évitant les templates inutiles pour son contexte.

Le rate limiting est essentiel pour les scans en environnement sensible. Une valeur de 100 requêtes par seconde est généralement bien tolérée. Pour les audits discrets, descendre à 20-50 r/s évite de déclencher les systèmes de détection d'intrusion.

Fenêtre de terminal
# Limiter le nombre de requêtes par seconde
nuclei -l targets.txt -rate-limit 100
# Ajuster la concurrence
nuclei -l targets.txt -c 50 -bulk-size 25
FlagDescriptionDéfaut
-rate-limitRequêtes par seconde maximum150
-bulk-sizeHosts en parallèle par template25
-cTemplates en parallèle25
-timeoutTimeout par requête (secondes)10

Tous les templates ne sont pas adaptés à tous les contextes. Les templates taggés dos (denial of service) peuvent perturber un service en production. Ceux taggés fuzz génèrent un grand volume de requêtes avec des payloads exotiques, ce qui peut déclencher des alertes ou surcharger les logs.

En environnement de production ou lors d'un audit client, il est prudent d'exclure ces catégories. On peut aussi exclure des templates spécifiques qu'on a identifiés comme générant des faux positifs dans son contexte.

Fenêtre de terminal
# Exclure par tags
nuclei -u http://localhost:3000 -etags dos,fuzz
# Exclure des templates spécifiques
nuclei -u http://localhost:3000 -exclude-templates cves/2020/CVE-2020-XXXX.yaml

Créer un fichier de configuration pour éviter de répéter les options :

Fenêtre de terminal
# Créer le fichier de config
mkdir -p ~/.config/nuclei
cat > ~/.config/nuclei/config.yaml << EOF
# Sévérités à scanner par défaut
severity:
- critical
- high
- medium
# Tags à exclure
exclude-tags:
- dos
- fuzz
# Rate limiting
rate-limit: 100
# Headers personnalisés (bug bounty)
header:
- "X-Bug-Bounty: votre-pseudo"
EOF

Intégrer Nuclei dans un pipeline CI/CD permet de détecter les vulnérabilités avant qu'elles n'atteignent la production. L'idée est d'exécuter un scan automatisé à chaque déploiement ou de manière planifiée.

Deux approches complémentaires existent. Les scans planifiés (quotidiens ou hebdomadaires) effectuent un audit complet de l'infrastructure. Les scans au déploiement vérifient rapidement que la nouvelle version n'introduit pas de vulnérabilité critique.

Les exemples ci-dessous montrent comment configurer les deux approches sur GitHub Actions et GitLab CI.

Ce workflow exécute un scan à chaque push sur main et quotidiennement à 2h du matin. Il exporte les résultats au format SARIF pour une intégration native avec GitHub Security, et archive les résultats JSON pour analyse ultérieure.

Trois détails de durcissement méritent votre attention avant de copier ce fichier. Le permissions: {} au niveau du workflow retire tous les droits par défaut du GITHUB_TOKEN, et le job les redemande un par un : contents: read pour lire le dépôt, security-events: write uniquement parce qu'il publie un SARIF. Le persist-credentials: false empêche actions/checkout de laisser le jeton dans .git/config du runner, où n'importe quelle étape suivante pourrait le relire. Enfin, chaque action est épinglée par SHA et non par tag, un tag pouvant être redéplacé vers un autre commit par son mainteneur.

name: Security Scan
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # Tous les jours à 2h
# Aucun droit par défaut : chaque job redemande le strict nécessaire
permissions: {}
jobs:
nuclei-scan:
runs-on: ubuntu-24.04
permissions:
contents: read # lire targets.txt
security-events: write # publier le SARIF dans GitHub Security
steps:
# Épingler les actions par hash SHA pour la sécurité supply chain
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Ne pas laisser le GITHUB_TOKEN dans .git/config du runner
persist-credentials: false
- name: Install Nuclei
run: |
# Épingler la version pour reproductibilité
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@v3.11.0
nuclei -update-templates
- name: Run Nuclei
run: |
nuclei -l targets.txt \
-severity critical,high \
-sarif-export nuclei.sarif \
-jsonl -o nuclei-results.jsonl
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4.37.3
with:
sarif_file: nuclei.sarif
- name: Upload Results
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: nuclei-results
path: nuclei-results.jsonl

Sur GitLab, l'image Docker officielle simplifie l'intégration. Le job suivant s'exécute lors des pipelines planifiés et sur les commits de la branche main. Les résultats sont archivés pendant une semaine.

nuclei-scan:
# Épingler la version par digest pour reproductibilité
image: projectdiscovery/nuclei:v3.11.0@sha256:e677842fb1f50f29747565ba274a1d35dcf8c684132a42b0cb406e71fccae9fc
stage: security
script:
- nuclei -l targets.txt
-severity critical,high
-jsonl -o nuclei-results.jsonl
artifacts:
paths:
- nuclei-results.jsonl
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_COMMIT_BRANCH == "main"

Quelques recommandations pour une intégration réussie dans les pipelines.

Épingler les versions des images Docker et des actions GitHub. Utiliser projectdiscovery/nuclei:v3.11.0 (idéalement par digest @sha256:...) plutôt que :latest garantit la reproductibilité des scans et évite les mauvaises surprises lors des mises à jour automatiques.

En CI/CD, limiter la sévérité aux niveaux critical et high évite de bloquer les déploiements pour des problèmes mineurs. On pourra toujours exécuter des scans complets en dehors du pipeline.

Exclure les templates destructifs avec -etags dos,fuzz est essentiel. Ces templates peuvent perturber l'application ou générer un volume de requêtes problématique.

Penser à définir un timeout global pour éviter les scans qui s'éternisent. Un pipeline bloqué pendant des heures sur un scan de sécurité n'est pas acceptable.

L'export en SARIF permet une intégration native avec GitHub Security et GitLab. Les vulnérabilités apparaissent directement dans l'interface de la plateforme.

Enfin, archiver les résultats permet de suivre l'évolution de la posture de sécurité dans le temps et d'identifier les régressions.

Les scans de base couvrent les vulnérabilités accessibles sans authentification. Mais une grande partie de la surface d'attaque se trouve derrière une authentification : dashboards d'administration, API internes, espaces clients. Nuclei propose plusieurs mécanismes pour scanner ces zones protégées.

Pour scanner des endpoints protégés, on passe les headers d'authentification directement à Nuclei. Cela peut être un token Bearer pour une API REST, un cookie de session pour une application web classique, ou un header custom.

L'idéal est de récupérer ces credentials via l'API de l'application ou de les générer dans le pipeline CI/CD. Éviter de stocker des credentials en dur dans les scripts. Attention aussi à la ligne de commande elle-même : un token passé en -H apparaît dans l'historique du shell et dans la table des processus. Sur un poste partagé ou un runner, le flag -secret-file est préférable, il lit les identifiants depuis un fichier de configuration dédié.

Fenêtre de terminal
# Avec un header d'authentification
nuclei -u https://app.production.interne \
-H "Authorization: Bearer $API_TOKEN" \
-tags misconfig,exposure
# Avec un cookie de session
nuclei -u https://app.production.interne \
-H "Cookie: session=$SESSION_ID" \
-tags misconfig,exposure
# Avec un fichier de secrets (pas de credential sur la ligne de commande)
nuclei -u https://app.production.interne -secret-file secrets.yaml

Certaines vulnérabilités ne se manifestent pas dans la réponse HTTP immédiate. Une injection SSRF peut déclencher une requête vers un serveur externe. Une RCE blind exécute du code sans retourner le résultat directement. Pour détecter ces cas, Nuclei utilise Interactsh : un serveur qui capture les callbacks générés par les payloads injectés.

Concrètement, Nuclei insère des URLs Interactsh dans ses payloads. Si la cible est vulnérable et exécute le payload, elle contacte le serveur Interactsh. Nuclei détecte alors la callback et signale la vulnérabilité.

Fenêtre de terminal
# Activer Interactsh (activé par défaut)
nuclei -u http://localhost:3000 -tags oast
# Désactiver si nécessaire
nuclei -u http://localhost:3000 -no-interactsh

Les workflows permettent d'enchaîner des templates conditionnellement. Par exemple, le workflow WordPress commence par détecter si la cible utilise ce CMS. Si oui, il exécute tous les templates spécifiques à WordPress. Sinon, il passe à la cible suivante sans perdre de temps.

Cette approche optimise les scans sur de larges listes de cibles hétérogènes : chaque cible ne reçoit que les tests pertinents pour sa stack technique.

Fenêtre de terminal
# Exécuter un workflow
nuclei -u http://localhost:3000 -w workflows/wordpress-workflow.yaml

Les workflows disponibles couvrent les CMS populaires (WordPress, Joomla, Drupal), les technologies courantes (PHP, Java, .NET) et certains produits spécifiques (GitLab, Confluence, Grafana).

Nuclei s'impose comme l'outil de référence pour le DAST grâce à sa rapidité, son extensibilité et sa communauté active. En quelques minutes, on peut scanner une infrastructure pour les dernières CVE et misconfigurations.

Pour démarrer efficacement, commencer par installer Nuclei via Go ou le binaire précompilé. Ensuite, prendre l'habitude de mettre à jour les templates régulièrement avec -update-templates, c'est là que réside la valeur de l'outil.

Lors des scans, filtrer par sévérité et tags selon le contexte évite de se noyer dans les résultats. Pour les équipes, intégrer Nuclei dans la CI/CD avec export SARIF automatise la détection.

Avec le temps, on apprend à personnaliser l'outil avec des templates maison pour les checks spécifiques à son environnement. Et toujours, vérifier manuellement les findings avant de les reporter, un scanner n'est pas infaillible.

La puissance de Nuclei réside dans son écosystème : quand une nouvelle CVE tombe, un template est souvent disponible dans les heures qui suivent.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn