Scanner d'évaluation des vulnérabilités avec génération de rapports
Une plateforme automatisée d'évaluation des vulnérabilités qui orchestre 86 outils de sécurité open-source, agrège et déduplique les résultats, exécute une couche d'analyse LLM compatible OpenAI facultative pour le tri, le regroupement et la remédiation, génère des scripts de preuve de concept, et produit des rapports professionnels en Markdown, HTML et JSON — le tout à partir d'une seule image Docker BlackArch Linux.
config.toml / env vars / CLI args ↓ AppConfig (pydantic, 3-layer merge: TOML < env < CLI) ↓ Plugin loader — auto-discovers ./plugins/ + ~/.vuln-scanner/plugins/ ↓ ScanOrchestrator • classify_target() → TargetType • tool.applies_to(target) — skips mismatched pairs • asyncio + ThreadPoolExecutor — parallel (tool × target) tasks • AuthConfig forwarded to every applicable tool ↓ ScanResult[] → Assessment ↓ LLMAnalyzer (optional) • Pass 1: triage + PoC design (threaded, per result) • Pass 2: PoC generation (PocGenerator, host-safe) • Pass 3: mitigation (evidence-informed) • Pass 4: clustering + exec summary ↓ PocRunner (container-only, VS_IN_CONTAINER=1 guard) ↓ ┌────────┬────────┬────────┐ │ .md │ .html │ .json │ (all formats written in parallel) └────────┴────────┴────────┘ ↓ DefectDojo (optional)
All scanning tools and PoC execution run inside a **BlackArch Linux** Docker container — nothing is installed on the host.
---
## Outils
86 outils organisés par catégorie. Chaque outil déclare les types de cibles qu'il prend en charge ; l'orchestrateur ignore automatiquement les combinaisons incompatibles.
### Scan réseau et ports
| Outil | Notes |
|------|-------|
| `nmap` | Scan complet des ports avec détection de services/versions |
| `rustscan` | Scanner de ports rapide, alimente nmap |
| `masscan` | Scanner TCP/UDP haute vitesse |
| `naabu` | Scanner de ports avec détection de services |
| `netdiscover` | Découverte d'hôtes basée sur ARP |
### Application web
| Outil | Notes |
|------|-------|
| `nuclei` | Scanner de vulnérabilités basé sur des templates |
| `nikto` | Scanner de mauvaise configuration de serveur web |
| `wapiti` | Scanner de vulnérabilités web en boîte noire |
| `ffuf` | Fuzzer web rapide (répertoires, paramètres, en-têtes) |
| `feroxbuster` | Découverte de contenu avec récursion |
| `gobuster` | Brute-force d'URI/DNS/vhosts |
| `wfuzz` | Fuzzer d'applications web |
| `dalfox` | Scanner XSS avec analyse des paramètres |
| `xsstrike` | Moteur avancé de détection XSS |
| `commix` | Exploiteur d'injection de commandes |
| `sqlmap` | Injection SQL automatisée et prise de contrôle |
| `nosqlmap` | Scanner d'injection NoSQL |
| `httpx` | Sondage HTTP et prise d'empreintes |
| `whatweb` | Outil d'identification de technologies web |
| `wafw00f` | Détection et prise d'empreintes WAF |
| `wpscan` | Scanner de vulnérabilités WordPress |
| `acunetix` | Scanner de vulnérabilités web (basé sur API) |
| `arachni` | Scanner de sécurité d'applications web |
| `zap` | Scanner DAST OWASP ZAP |
| `wapiti` | Scanner de vulnérabilités en boîte noire |
| `drheader` | Analyseur d'en-têtes de sécurité HTTP |
| `humble` | Vérificateur de sécurité des en-têtes HTTP |
| `hakrawler` | Crawler web rapide pour URLs et endpoints |
| `katana` | Framework de crawling web nouvelle génération |
| `gau` | Collecteur d'URL connues (AlienVault, WaybackMachine) |
| `jsluice` | Extracteur de secrets et URLs dans JavaScript |
| `corscanner` | Scanner de mauvaise configuration CORS |
| `crlfuzz` | Scanner d'injection CRLF |
| `smuggler` | Détecteur de contrebande de requêtes HTTP |
| `linkfinder` | Découverte d'endpoints dans les sources JavaScript/HTML |
| `cariddi` | Crawler web avec détection de secrets et d'endpoints |
### API et GraphQL
| Outil | Notes |
|------|-------|
| `kiterunner` | Découverte de routes API avec fichiers kite |
| `graphql_cop` | Auditeur de sécurité GraphQL |
| `restler` | Fuzzer d'API REST avec état |
| `apifuzzer` | Fuzzer basé sur OpenAPI/Swagger |
| `cherrybomb` | Linter de sécurité de spécifications OpenAPI |
| `arjun` | Découverte de paramètres HTTP |
| `paramspider` | Extraction de paramètres depuis wayback/sources |
### DNS et reconnaissance
| Outil | Notes |
|------|-------|
| `amass` | Énumération de sous-domaines (passif + actif) |
| `subfinder` | Énumération passive rapide de sous-domaines |
| `dnsx` | Boîte à outils de résolution et de sondage DNS |
| `dnsrecon` | Énumération DNS et transfert de zone |
| `fierce` | Reconnaissance DNS et découverte d'hôtes |
| `theharvester` | OSINT : e-mails, noms, hôtes, sous-domaines |
| `puredns` | Brute-force rapide de sous-domaines avec filtrage par wildcard |
| `alterx` | Moteur de permutation de sous-domaines |
| `waybackurls` | Collecte d'URL historiques depuis Wayback Machine |
| `httprobe` | Sonde d'hôtes HTTP/HTTPS actifs |
### TLS / SSL
| Outil | Notes |
|------|-------|
| `testssl` | Audit de configuration TLS et de suites de chiffrement |
| `sslyze` | Scanner TLS (suites de chiffrement, Heartbleed, ROBOT) |
| `sslscan` | Scanner de services SSL/TLS |
| `tlsx` | Sondage TLS rapide |
| `tls_attacker` | Outil d'attaque du protocole TLS |
| `ssh_audit` | Auditeur de configuration et d'algorithmes SSH |
### SMB et services réseau
| Outil | Notes |
|------|-------|
| `smbmap` | Énumération des partages SMB et des permissions |
| `enum4linux` | Énumération SMB/NetBIOS |
| `crackmapexec` | Évaluation Active Directory et SMB |
| `openvas` | Scanner de vulnérabilités OpenVAS |
### SAST et analyse de code
| Outil | Notes |
|------|-------|
| `bandit` | SAST Python — anti-modèles de sécurité courants |
| `semgrep` | SAST multi-langages avec règles communautaires |
| `gosec` | Vérificateur de sécurité Go |
| `bearer` | SAST par flux de données avec règles de confidentialité et de sécurité |
| `horusec` | Moteur SAST multi-langages |
| `brakeman` | Scanner SAST Ruby on Rails |
| `flawfinder` | Analyse statique C/C++ pour failles courantes |
| `dependency_check` | Scanner de vulnérabilités de dépendances OWASP |
| `pip_audit` | Vérificateur de vulnérabilités de paquets Python |
### Analyse de composition logicielle (SCA)
| Outil | Notes |
|------|-------|
| `osv-scanner` | Scanner de la base de vulnérabilités Open Source |
| `npm-audit` | Audit de vulnérabilités de paquets Node.js |
| `govulncheck` | Vérificateur de vulnérabilités de modules Go |
### Détection de secrets
| Outil | Notes |
|------|-------|
| `gitleaks` | Scanner de secrets dans l'historique Git |
| `trufflehog` | Recherche de secrets basée sur l'entropie |
| `secretfinder` | Secrets dans les fichiers JS et endpoints |
| `detect-secrets` | Scanner de secrets basé sur une référence |
| `noseyparker` | Scanner de secrets haute vitesse avec règles de motifs |
### IaC et configuration
| Outil | Notes |
|------|-------|
| `checkov` | Scanner IaC Terraform/K8s/Dockerfile |
| `tfsec` | Analyse statique Terraform |
| `terrascan` | Scanner de sécurité IaC multi-cloud |
| `hadolint` | Linter de bonnes pratiques Dockerfile |
### Infrastructure cloud
| Outil | Notes |
|------|-------|
| `prowler` | Évaluation de la posture de sécurité AWS/GCP/Azure |
| `kube-bench` | Vérificateur CIS Kubernetes Benchmark |
### Conteneurs et chaîne d'approvisionnement
| Outil | Notes |
|------|-------|
| `trivy` | Scanner de vulnérabilités d'images de conteneurs + systèmes de fichiers |
| `grype` | Mise en correspondance de vulnérabilités de conteneurs et de paquets |
---
## Filtrage par type de cible
L'orchestrateur classe chaque cible en un ou plusieurs types et n'exécute que les outils qui déclarent prendre en charge ce type. Cela élimine le bruit, par exemple les outils SMB exécutés contre des URL web.
| Type | Exemple | Outils correspondants |
|------|---------|-----------------|
| `HOST` | `example.com` | Outils DNS, SSL, web, SMB |
| `IP` | `10.0.0.1` | Outils réseau, ports, SMB |
| `CIDR` | `10.0.0.0/24` | Scanners réseau |
| `URL` | `https://app.example.com` | Outils web, API, SSL |
| `PATH` | `/src/myapp` | Outils SAST, SCA, secrets, IaC |
| `REPO` | `https://github.com/org/repo` | Outils secrets, SAST, SCA |
| `IMAGE` | `myapp:latest` | Scanners de conteneurs |
| `CLOUD` | `aws:profile=prod`, `arn:aws:…` | Outils de posture cloud (prowler, kube-bench, terrascan) |
La classification est automatique — il suffit de fournir la chaîne de la cible ; le scanner détermine le type.
Formats de cible cloud reconnus :
- ARN AWS : `arn:aws:iam::123456789012:root`
- Raccourci de profil nommé : `aws:profile=production`
- Projet GCP : `projects/my-project-id`
- UUID d'abonnement Azure : `00000000-0000-0000-0000-000000000000`
---
## Modes de scan
| Mode | Description |
|------|-------------|
| `paranoid` | Furtivité maximale — sondage passif, empreinte minimale |
| `passive` | Aucune attaque active — énumération et collecte de bannières uniquement **(par défaut)** |
| `active` | Vérifications de vulnérabilités standard activées |
| `aggressive` | Scan complet : tous les templates, force brute, timing rapide |
---
## Scan authentifié
Les identifiants sont transmis à tous les outils web applicables (nuclei, ffuf, feroxbuster, gobuster, nikto, sqlmap, dalfox, wpscan, wapiti, katana, hakrawler, arjun, wfuzz, corscanner, kiterunner, httpx).
### Identifiants globaux
Appliqués à chaque cible sauf si une substitution par cible existe.
**Via la configuration :**```toml
[scan.auth]
bearer_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
username = "admin"
password = "secret"
[scan.auth.cookies]
session = "abc123"
[scan.auth.headers]
X-API-Key = "my-api-key"
Via les variables d'environnement (global uniquement):```bash VS_AUTH_BEARER_TOKEN=eyJ... VS_AUTH_USERNAME=admin VS_AUTH_PASSWORD=secret
**Via CLI** (global uniquement) :```bash
vuln-scanner --targets https://app.example.com \
--auth-bearer eyJ... \
--auth-cookie session=abc123 \
--auth-header X-API-Key=secret
Lors de l'analyse de plusieurs cibles nécessitant des identifiants différents, définissez des surcharges par cible sous [scan.auth.targets."<target>"]. Une entrée correspondante remplace entièrement la configuration globale pour cette cible — il n'y a pas de fusion. L'authentification par cible est uniquement configurable via le fichier de configuration (les variables d'environnement et les drapeaux CLI ne définissent que la valeur globale par défaut).```toml
[scan.auth]
bearer_token = "default-token"
[scan.auth.targets."https://app.example.com"] bearer_token = "app-specific-jwt"
[scan.auth.targets."https://admin.example.com"] [scan.auth.targets."https://admin.example.com".cookies] session = "s%3Aabc123" csrftoken = "xyz789"
[scan.auth.targets."10.0.0.50"] username = "apiuser" password = "s3cret"
[scan.auth.targets."https://legacy.example.com"] login_url = "https://legacy.example.com/login" username = "admin" password = "password123" [scan.auth.targets."https://legacy.example.com".login_data] _token = "csrf-value-here"
**Résolution :** `per-target config > global config`
---
## Analyse LLM
Lorsqu'une clé API est présente, la couche LLM s'active automatiquement. Elle effectue quatre passes sur les résultats du scan :
| Passe | Nom | Ce qu'elle fait |
|------|------|-------------|
| 1 | **Triage** | Attribue le CWE, le niveau de confiance, l'indicateur de faux positif, le résumé d'exploitabilité et conçoit un PoC pour chaque constat |
| 2 | **Génération de PoC** | Écrit des scripts Python/Bash autonomes qui confirment le constat à l'aide d'outils déjà présents dans le conteneur |
| 3 | **Atténuation** | Produit des atténuations concrètes à court terme et des remédiations permanentes, éventuellement étayées par les preuves du PoC |
| 4 | **Regroupement** | Regroupe les constats par cause racine, rédige des remédiations partagées et produit un résumé exécutif |
### Configuration du fournisseur
Le client LLM est compatible avec l'API OpenAI — il fonctionne avec OpenAI, Azure OpenAI, Ollama, vLLM, LM Studio, OpenRouter et tout autre point de terminaison compatible.```toml
[llm]
enabled = "auto" # "auto" | true | false (auto = on when api_key present)
api_key = "" # or set OPENAI_API_KEY env var
base_url = "" # leave empty for OpenAI; set for Ollama/vLLM/etc.
model = "gpt-4o" # REQUIRED when LLM is active — no default
# Sampling parameters (all OpenAI-compatible)
temperature = 0.2
top_p = 0.95
max_tokens = 4096
# top_k and other non-standard params go in extra_body:
# [llm.extra_body]
# top_k = 40
Exemple Ollama :```toml [llm] base_url = "http://localhost:11434/v1" api_key = "ollama" model = "llama3.2"
**Exemple vLLM :**```toml
[llm]
base_url = "http://localhost:8000/v1"
api_key = "token-abc123"
model = "meta-llama/Meta-Llama-3-8B-Instruct"
Chaque capacité LLM est une fonctionnalité nommée, activable globalement et remplaçable par outil ou par catégorie.
| Fonctionnalité | Défaut | Description |
|---|---|---|
logs_analysis | on | Alimenter le LLM avec la sortie brute de l'outil |
enrich | on | Triage CWE / confiance / faux positif / exploitabilité |
classify | on | Classifier le type de constatation et le risque |
cluster | on | Grouper les constatations par cause racine |
mitigation | on | Générer des mesures d'atténuation et de remédiation |
generate_poc | on | Écrire des scripts de PoC comme éléments du rapport |
execute_poc | off | Exécuter les PoC dans le conteneur (nécessite VS_IN_CONTAINER=1) |
false_positive_filter | on | Supprimer les faux positifs probables du rapport |
Configuration globale des fonctionnalités :```toml [llm.features] generate_poc = true execute_poc = false # enable only inside Docker
[llm.features.tool.bandit] generate_poc = false
[llm.features.category.web] logs_analysis = false
**Précédence des fonctionnalités :** `tool override > category override > global`
### Prompts personnalisés
Tous les prompts LLM sont remplaçables :```toml
[llm.prompts]
enrich_system = "You are a senior penetration tester..."
mitigation_user = "Write remediation steps for: {title}..."
# Available placeholders: {title} {severity} {description} {cwe}
# {exploitability} {tool} {target} {cves} {raw_output}
[llm] include_tools = [] # empty = all tools exclude_tools = ["hakrawler", "gau"] include_categories = [] exclude_categories = ["dns"]
---
## Génération et exécution de PoC
### Génération (toujours sûre pour l'hôte)
Le LLM écrit des scripts Python et/ou Bash autonomes pour chaque constat. Les scripts utilisent des outils déjà présents dans l'image BlackArch (`curl`, `sqlmap`, `nuclei`, `dalfox`, etc.) et sont écrits dans `<report>_assets/poc/`. La génération n'exécute jamais de code — elle écrit uniquement des fichiers.```toml
[llm.poc]
languages = ["python", "bash"]
only_severities = ["critical", "high", "medium"]
max_pocs = 20
allow_git_clone = false # permit cloning official exploit PoCs from GitHub
L'exécution du PoC est conditionnée par deux gardes indépendants :
execute_poc = true dans [llm.features]VS_IN_CONTAINER=1 (intégrée dans l'image Docker)Le runner refuse silencieusement si l'une de ces gardes est absente, il ne peut donc pas s'exécuter sur l'hôte. Une liste noire statique rejette les scripts contenant des motifs destructeurs (rm -rf /, mkfs., bombes fork, etc.) avant l'exécution.```bash
VS_LLM_FEATURE_EXECUTE_POC=true docker compose ... run --rm scanner ...
## Plugin System
Déposez un fichier `.py` définissant une ou plusieurs sous-classes de `AbstractTool` dans `./plugins/` (ou `~/.vuln-scanner/plugins/`) et elles sont automatiquement découvertes au démarrage — aucune modification de code nécessaire.
**Ordre de découverte** (les entrées ultérieures remplacent en cas de collision de noms) :
1. `./plugins/` (relatif au répertoire de travail courant, CWD)
2. `~/.vuln-scanner/plugins/`
3. Répertoires supplémentaires configurés via `[plugins] dirs` ou `--plugin-dir`
**Exemple de plugin** (`plugins/my_scanner.py`):```python
from vuln_scanner.tools.abstract import AbstractTool
from vuln_scanner.tools.enums import Severity, ScanStatus, TargetType
from vuln_scanner.tools.models import Finding, ScanInput, ScanResult
class MyScannerTool(AbstractTool):
name: str = "my-scanner"
category: str = "web"
# Only runs against URL targets — skipped automatically for IPs, paths, etc.
applicable_targets: frozenset[TargetType] = frozenset({TargetType.URL})
def build_command(self, target: str, scan_input: ScanInput) -> list[str]:
return ["my-scanner", "--target", target, "--json"]
def parse_output(self, raw: str, target: str) -> list[Finding]:
...
Config:```toml [plugins] enabled = true dirs = ["/opt/company-scanners"]
**CLI:**```bash
vuln-scanner --plugin-dir /opt/company-scanners --targets https://app.example.com
Les outils plugin sont enregistrés globalement, mais le type-gating de l'orchestrateur contrôle sur quelles cibles chaque plugin s'exécute réellement. Un plugin déclarant applicable_targets = frozenset({TargetType.URL}) ne se déclenchera jamais contre une IP ou un chemin de système de fichiers.
Pour restreindre un plugin à des chaînes de cibles spécifiques au-delà du type-gating (par exemple, ne s'exécuter que contre un hôte de staging connu), retournez ScanStatus.SKIPPED dans run() :```python
def run(self, target: str, scan_input: ScanInput) -> ScanResult:
if "staging" not in target:
return ScanResult(tool=self.name, target=target, status=ScanStatus.SKIPPED)
return super().run(target, scan_input)
Il n'existe pas de filtre de plugin par cible au niveau de la configuration — cette logique appartient au plugin lui-même.
---
## Formats de rapport
Trois formats sont générés en parallèle. Sélectionnez n'importe quelle combinaison :```toml
[report]
formats = ["markdown", "html", "json"]
output_dir = "./reports"
Ou via CLI : --formats markdown html json
.md)Rapport structuré professionnel suivant les conventions de pentest du secteur :
Les constatations de plusieurs outils signalant le même problème sur la même cible sont dédupliquées en une seule entrée répertoriant tous les outils ayant contribué.
.html)Rapport autonome mono-fichier (aucune dépendance externe) avec :
.json)Extraction structurée complète du modèle Assessment — constatations, enrichissement par LLM, clusters, statistiques, enregistrements PoC. Convient à l'ingestion dans les pipelines CI/CD et aux outils en aval.
Le script poc.sh lance DefectDojo, trois cibles vulnérables et le scanner en une seule commande.
Prérequis : docker, plugin docker compose, curl, `python3````bash
./poc.sh
| Étape | Action |
|------|--------|
| 1 | Vérifie les prérequis |
| 2 | Charge `.env` (copie depuis `.env.example` si absent) |
| 3 | Démarre la pile DefectDojo |
| 4 | Attend que l'API DefectDojo soit prête |
| 5 | Obtient le jeton API via les identifiants admin |
| 6 | Démarre les conteneurs cibles vulnérables |
| 7 | Attend que chaque cible soit accessible |
| 8 | Construit l'image Docker du scanner |
| 9 | Exécute le scanner, génère les rapports, les pousse vers DefectDojo |
| 10 | Affiche un résumé avec les URL et les instructions de démantèlement |
**Avec analyse LLM :**```bash
# Copy the example env and add your key
cp .env.example .env
# Edit .env: set OPENAI_API_KEY and VS_LLM_MODEL
./poc.sh
Remplacer le mode de scan :```bash SCAN_MODE=active ./poc.sh
**Démontage:**```bash
docker compose down -v
docker compose -f docker-compose.target.yaml down -v
poc.sh)| Application | URL | Description |
|---|---|---|
| OWASP Juice Shop | http://localhost:3000 | Application Node.js moderne couvrant le Top 10 de l'OWASP |
| WebGoat | http://localhost:8888/WebGoat | Application Java/Spring volontairement vulnérable |
Des systèmes disponibles publiquement et volontairement vulnérables, maintenus par pentest-ground.com. Aucune configuration requise — scannez directement pour valider les outils et la génération de PoC.
| Système | URL | Type | Classes de vulnérabilité |
|---|---|---|---|
| DVWA | https://pentest-ground.com:4280 | Application Web classique | CSRF, XSS, SQLi |
| DVGQL | https://pentest-ground.com:5013 | API GraphQL | CMDi, XSS, SQLi |
| RestFlaw | https://pentest-ground.com:9000 | API REST | SQLi, Code Injection, XXE |
| GuardianLeaks | https://pentest-ground.com:81 | Application Web | XSS, SSRF, Code Injection |
| vuln-scanner --targets \ | |||
| https://pentest-ground.com:4280 \ | |||
| https://pentest-ground.com:5013 \ | |||
| https://pentest-ground.com:9000 \ | |||
| https://pentest-ground.com:81 \ | |||
| --mode active |
---
## scanner.sh — Wrapper Docker
`scanner.sh` est l'interface recommandée au quotidien pour exécuter le scanner. Il encapsule `docker compose run` afin que vous n'ayez jamais à saisir manuellement l'invocation compose — transmettez simplement les cibles et les drapeaux directement.```bash
./scanner.sh [OPTIONS] [-- SCANNER_ARGS...]
| Flag | Description |
|---|---|
-t, --targets HOST... | Une ou plusieurs cibles de scan (URL, IP, CIDR, chemin, image) |
-m, --mode MODE | Mode de scan : passive | active | aggressive | paranoid |
-c, --config FILE | Fichier de configuration à monter (défaut : ./config.toml) |
-f, --formats FMT | Formats de rapport, séparés par des virgules : markdown,html,json ; répétable |
--no-llm | Désactiver l'enrichissement LLM |
--llm-model MODEL | Remplacement du modèle LLM (ex. gpt-4o, claude-sonnet-4-5) |
--llm-min-severity SEV | Sévérité minimale pour le LLM : info|low|medium|high|critical |
--include-tools TOOLS | Liste d'outils à exécuter, séparée par des virgules |
--exclude-tools TOOLS | Liste d'outils à ignorer, séparée par des virgules |
-e, --env KEY=VALUE | Transmettre une variable d'environnement supplémentaire au conteneur |
-b, --build | Reconstruire l'image Docker avant l'exécution |
-n, --no-defectdojo | Ignorer l'intégration DefectDojo |
--shell | Ouvrir un shell interactif dans le conteneur au lieu de scanner |
-h, --help | Afficher l'aide |
Tout ce qui suit -- est transmis tel quel au point d'entrée du scanner, en contournant toute la logique du wrapper.
./scanner.sh
./scanner.sh -t https://app.example.com 192.168.1.0/24 -m active
./scanner.sh -c /path/to/prod.toml
./scanner.sh -t https://app.example.com --llm-model gpt-4o
./scanner.sh -t https://app.example.com --include-tools nuclei,dalfox,ffuf
./scanner.sh --build -t https://app.example.com -m active
./scanner.sh -- --targets https://t.example.com --mode aggressive --formats markdown html json
./scanner.sh --shell ./scanner.sh --build --shell
### Ce qu'il fait automatiquement
- Charge `.env` (copie depuis `.env.example` si absent)
- Copie `config.example.toml` → `config.toml` si aucune configuration n'existe
- Crée le réseau Docker `vuln_scanner_network` s'il n'est pas présent
- Monte un fichier `--config` personnalisé dans le conteneur à `/app/config.toml`
- Reconstruit l'image lorsque `--build` est passé
---
## Configuration
Copiez le modèle annoté :```bash
cp config.example.toml config.toml
Référence complète :```toml [scan] targets = ["192.168.1.1", "https://app.example.com", "/src/myapp"] mode = "passive" # paranoid | passive | active | aggressive timeout = 300 # per-tool timeout in seconds rate_limit = null # requests/sec; null = no limit
[scan.auth] bearer_token = "" # Authorization: Bearer username = "" # HTTP Basic username password = "" # HTTP Basic password login_url = "" # Form-based login URL
[tools] exclude = ["nikto"] # skip specific tools by name
[categories] include = ["web", "ssl"] # limit to these categories; empty = all
[plugins] enabled = true
[report] formats = ["markdown", "html", "json"] output_dir = "./reports"
[defectdojo] url = "http://localhost:8080" api_key = "" product_name = "My Product" engagement_name = "Automated Scan"
[llm] enabled = "auto" # "auto" | true | false api_key = "" # or OPENAI_API_KEY env var base_url = "" # leave empty for OpenAI model = "" # required when active, e.g. "gpt-4o" or "llama3.2" temperature = 0.2 top_p = 0.95 max_tokens = 4096
exclude_tools = [] exclude_categories = []
[llm.features] logs_analysis = true enrich = true classify = true cluster = true mitigation = true generate_poc = true execute_poc = false # container-only; set VS_LLM_FEATURE_EXECUTE_POC=true false_positive_filter = true
[llm.features.tool.bandit] generate_poc = false
[llm.features.category.dns] logs_analysis = false
[llm.poc] languages = ["python", "bash"] only_severities = ["critical", "high", "medium"] max_pocs = 20 allow_git_clone = false
**Précédence de fusion des configurations :** `CLI > env vars > config.toml > defaults`
---
## Variables d'environnement
### Noyau
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `VS_TARGETS` | `--targets` | Liste de cibles séparées par des espaces |
| `VS_MODE` | `--mode` | Mode d'analyse |
| `VS_TIMEOUT` | `--timeout` | Délai d'expiration par outil (secondes) |
| `VS_RATE_LIMIT` | `--rate-limit` | Limite de débit (req/s) |
| `VS_MAX_CONCURRENT` | `--max-concurrent` | Emplacements d'outils en parallèle |
| `VS_INCLUDE_TOOLS` | `--include-tools` | Outils en liste blanche par nom |
| `VS_EXCLUDE_TOOLS` | `--exclude-tools` | Outils en liste noire par nom |
| `VS_INCLUDE_CATEGORIES` | `--include-categories` | Catégories en liste blanche |
| `VS_EXCLUDE_CATEGORIES` | `--exclude-categories` | Catégories en liste noire |
| `VS_OUTPUT_DIR` | `--output-dir` | Répertoire de sortie des rapports |
### Rapports
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `VS_FORMATS` | `--formats` | Formats de rapport : `markdown html json` |
### LLM
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `OPENAI_API_KEY` | — | Clé API (variable d'environnement standard, utilisée comme repli) |
| `OPENAI_BASE_URL` | — | URL de base de repli (pour les points de terminaison non-OpenAI) |
| `VS_LLM_ENABLED` | `--no-llm` | `auto` \| `true` \| `false` |
| `VS_LLM_MODEL` | `--llm-model` | Nom du modèle (requis lorsqu'il est actif) |
| `VS_LLM_TEMPERATURE` | — | Température d'échantillonnage |
| `VS_LLM_MAX_TOKENS` | — | Nombre maximal de jetons de sortie |
| `VS_LLM_FEATURE_<NAME>` | `--llm-feature NAME=on` | Bascule globale de fonctionnalité, ex. `VS_LLM_FEATURE_GENERATE_POC=false` |
| `VS_LLM_FEATURE_EXECUTE_POC` | `--llm-poc-execute` | Activer l'exécution des PoC (conteneur uniquement) |
### Analyse authentifiée
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `VS_AUTH_BEARER_TOKEN` | `--auth-bearer` | Jeton Bearer (`Authorization: Bearer …`) |
| `VS_AUTH_USERNAME` | `--auth-user` | Nom d'utilisateur HTTP Basic |
| `VS_AUTH_PASSWORD` | `--auth-pass` | Mot de passe HTTP Basic |
| `VS_AUTH_LOGIN_URL` | `--auth-login-url` | URL de connexion par formulaire |
Les cookies et en-têtes supplémentaires doivent être définis via le fichier de configuration ou les indicateurs CLI `--auth-cookie` / `--auth-header`.
### Plugins
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `VS_PLUGINS_ENABLED` | `--no-plugins` | Activer/désactiver la découverte automatique des plugins |
| `VS_PLUGINS_DIRS` | `--plugin-dir` | Répertoires de plugins supplémentaires (séparés par des espaces) |
### DefectDojo
| Variable | CLI flag | Description |
|----------|----------|-------------|
| `VS_DEFECTDOJO_URL` | `--defectdojo-url` | URL de base DefectDojo |
| `VS_DEFECTDOJO_API_KEY` | `--defectdojo-api-key` | Jeton API |
| `VS_DEFECTDOJO_PRODUCT` | — | Nom du produit |
| `VS_DEFECTDOJO_ENGAGEMENT` | — | Nom de l'engagement |
---
## Structure du projet```
vuln_scanner/
├── config/
│ ├── models.py # AppConfig, AppLLMConfig, PluginsConfig (pydantic)
│ └── loader.py # 3-layer merge: TOML + env (VS_*) + CLI
│
├── tools/
│ ├── enums.py # Severity, Confidence, ScanStatus, ScanMode, TargetType
│ ├── models.py # Finding, ScanInput, ScanResult, AuthConfig (pydantic)
│ ├── target.py # classify_target() — maps target string to TargetType set
│ ├── abstract.py # AbstractTool ABC + subprocess execution helpers
│ ├── __init__.py # TOOL_REGISTRY (86 tools)
│ └── <tool>.py # One file per tool (86 total)
│
├── llm/
│ ├── models.py # LLMConfig, LLMFeatures, PocConfig (pydantic)
│ ├── features.py # resolve_features() — tool > category > global merge
│ ├── client.py # LLMClient — thin openai SDK wrapper
│ ├── analyzer.py # LLMAnalyzer — 4-pass analysis pipeline
│ └── prompts.py # Default prompt templates (all overridable)
│
├── poc/
│ ├── models.py # Poc, PocVerdict
│ ├── generator.py # PocGenerator — writes scripts, never executes (host-safe)
│ └── runner.py # PocRunner — executes scripts (VS_IN_CONTAINER guard)
│
├── reports/
│ ├── base.py # AbstractReporter
│ ├── markdown.py # Professional structured Markdown report
│ ├── html.py # Self-contained HTML with light/dark theme
│ └── json_reporter.py # Full Assessment JSON dump
│
├── defectdojo/
│ └── client.py # DefectDojoClient — push findings via REST API
│
├── plugins.py # Plugin auto-discovery (./plugins/, ~/.vuln-scanner/plugins/)
├── model.py # Assessment, Cluster, AssessmentStats
└── orchestrator.py # ScanOrchestrator — type-gated, async concurrent execution
plugins/ # Drop .py plugin files here (auto-discovered at startup)
main.py # Entry point
config.example.toml # Fully documented configuration template
.env.example # Environment variable reference
Dockerfile # BlackArch-based image; bakes VS_IN_CONTAINER=1
docker-compose.yaml # DefectDojo stack
docker-compose.scanner.yaml # Scanner service
docker-compose.target.yaml # Vulnerable test targets (Juice Shop, WebGoat)
scanner.sh # Convenience wrapper — runs the scanner via docker compose
poc.sh # End-to-end quick-start script (DefectDojo + targets + scanner)
Pour les outils ponctuels ou privés, utilisez le Système de plugins — déposez un fichier .py dans ./plugins/ sans modification de code. Pour les outils qui devraient être livrés avec le projet :
vuln_scanner/tools/mytool.py :```python
from vuln_scanner.tools.abstract import AbstractTool
from vuln_scanner.tools.enums import Severity, TargetType
from vuln_scanner.tools.models import Finding, ScanInputclass MyTool(AbstractTool): name: str = "mytool" category: str = "web" # Declare which target types this tool supports. # The orchestrator skips mismatched (tool, target) pairs automatically. applicable_targets: frozenset[TargetType] = frozenset({TargetType.URL, TargetType.HOST})
def build_command(self, target: str, scan_input: ScanInput) -> list[str]:
return ["mytool", "--target", target]
def parse_output(self, raw: str, target: str) -> list[Finding]:
findings = []
for line in raw.splitlines():
if "VULN" in line:
findings.append(Finding(
title="Example finding",
severity=Severity.HIGH,
description=line,
tool=self.name,
target=target,
))
return findings
2. Enregistrez-le dans `vuln_scanner/tools/__init__.py`:```python
from vuln_scanner.tools.mytool import MyTool
TOOL_REGISTRY: dict[str, type[AbstractTool]] = {
...
"mytool": MyTool,
}
Dockerfile :```dockerfile
RUN pacman -Sy --noconfirm mytool**Conseils :**
- Pour les outils qui écrivent dans un fichier plutôt que sur stdout, utilisez `OUTPUT_FILE_SENTINEL` dans `build_command()` et surchargez `run()` pour appeler `self._run_with_tempfile()`.
- Les outils avec `applicable_targets = frozenset(TargetType)` (par défaut) s'exécutent sur tous les types de cibles — utilisez ceci uniquement pour des outils véritablement universels.
- Binaire introuvable → `ScanStatus.SKIPPED` (masqué du rapport). Erreur d'outil → `ScanStatus.FAILED` (affiché dans l'annexe A).
---
## Développement```bash
# Install with dev dependencies
uv sync
# Run tests (host-safe only — no real tool execution)
uv run pytest tests/ -v
# Lint
uv run ruff check .
uv run ruff format .
Catégories de tests :
tests/test_config.py — fusion et validation de la configurationtests/test_target_typing.py — classify_target() et applies_to()tests/test_orchestrator_gating.py — filtrage par type avec des outils simuléstests/test_llm.py — fonctionnalités LLM, client simulé, garde de conteneur du PoC runnertests/test_reports.py — les trois générateurs de rapports (Markdown, HTML, JSON)tests/test_nmap.py — parseur de sortie nmapRègle de sécurité : ne jamais exécuter de vrais outils de scan sur l'hôte. Toute exécution d'outil se fait à l'intérieur du conteneur Docker contre les conteneurs cibles isolés. Le PocRunner applique cette règle — il vérifie VS_IN_CONTAINER=1 avant d'exécuter tout script PoC, et l'image Docker intègre cette variable.
Les constatations sont poussées automatiquement lorsque api_key et product_name sont configurés.
Obtenez votre clé API :
admin / admin)Envoi manuel :```bash
VS_DEFECTDOJO_API_KEY=your-key
VS_DEFECTDOJO_PRODUCT="My App"
uv run vuln-scanner --targets 192.168.1.1