
Escáner de Evaluación de Vulnerabilidades con Generación de Informes
Una plataforma automatizada de evaluación de vulnerabilidades que orquesta 86 herramientas de seguridad de código abierto, agrega y deduplica hallazgos, ejecuta una capa opcional de análisis LLM compatible con OpenAI para triaje, agrupación y remediación, genera scripts de prueba de concepto y produce informes profesionales en Markdown, HTML y JSON — todo desde una única imagen Docker de 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)
Todas las herramientas de escaneo y la ejecución de PoC se ejecutan dentro de un contenedor Docker **BlackArch Linux** — nada se instala en el host.
---
## Herramientas
86 herramientas organizadas por categoría. Cada herramienta declara los tipos de objetivo que soporta; el orquestador omite automáticamente las combinaciones incompatibles.
### Escaneo de Red y Puertos
| Tool | Notas |
|------|-------|
| `nmap` | Escaneo completo de puertos con detección de servicios/versiones |
| `rustscan` | Escáner de puertos rápido, alimenta a nmap |
| `masscan` | Escáner TCP/UDP de alta velocidad |
| `naabu` | Escáner de puertos con detección de servicios |
| `netdiscover` | Descubrimiento de hosts basado en ARP |
### Aplicaciones Web
| Tool | Notas |
|------|-------|
| `nuclei` | Escáner de vulnerabilidades basado en plantillas |
| `nikto` | Escáner de malas configuraciones de servidores web |
| `wapiti` | Escáner de vulnerabilidades web de caja negra |
| `ffuf` | Fuzzer web rápido (directorios, parámetros, cabeceras) |
| `feroxbuster` | Descubrimiento de contenido con recursión |
| `gobuster` | Fuerza bruta de URI/DNS/vhost |
| `wfuzz` | Fuzzer de aplicaciones web |
| `dalfox` | Escáner XSS con análisis de parámetros |
| `xsstrike` | Motor avanzado de detección de XSS |
| `commix` | Explotador de inyección de comandos |
| `sqlmap` | Inyección SQL y toma de control automatizada |
| `nosqlmap` | Escáner de inyección NoSQL |
| `httpx` | Sondaje y fingerprinting HTTP |
| `whatweb` | Fingerprinter de tecnologías web |
| `wafw00f` | Detección y fingerprinting de WAF |
| `wpscan` | Escáner de vulnerabilidades de WordPress |
| `acunetix` | Escáner de vulnerabilidades web (basado en API) |
| `arachni` | Escáner de seguridad de aplicaciones web |
| `zap` | Escáner DAST de OWASP ZAP |
| `wapiti` | Escáner de vulnerabilidades de caja negra |
| `drheader` | Analizador de cabeceras de seguridad HTTP |
| `humble` | Verificador de seguridad de cabeceras HTTP |
| `hakrawler` | Rastreador web rápido para URLs y endpoints |
| `katana` | Framework de rastreo web de próxima generación |
| `gau` | Recolector de URLs conocidas (AlienVault, WaybackMachine) |
| `jsluice` | Extractor de secretos y URLs de JavaScript |
| `corscanner` | Escáner de malas configuraciones CORS |
| `crlfuzz` | Escáner de inyección CRLF |
| `smuggler` | Detector de contrabando de peticiones HTTP |
| `linkfinder` | Descubrimiento de endpoints en código fuente JavaScript/HTML |
| `cariddi` | Rastreador web con detección de secretos y endpoints |
### API y GraphQL
| Tool | Notas |
|------|-------|
| `kiterunner` | Descubrimiento de rutas de API con archivos kite |
| `graphql_cop` | Auditor de seguridad de GraphQL |
| `restler` | Fuzzer de API REST con estado |
| `apifuzzer` | Fuzzer basado en OpenAPI/Swagger |
| `cherrybomb` | Linter de seguridad de especificaciones OpenAPI |
| `arjun` | Descubrimiento de parámetros HTTP |
| `paramspider` | Minería de parámetros desde wayback/fuentes |
### DNS y Reconocimiento
| Tool | Notas |
|------|-------|
| `amass` | Enumeración de subdominios (pasiva + activa) |
| `subfinder` | Enumeración pasiva rápida de subdominios |
| `dnsx` | Kit de herramientas de resolución y sondeo DNS |
| `dnsrecon` | Enumeración DNS y transferencia de zona |
| `fierce` | Reconocimiento DNS y descubrimiento de hosts |
| `theharvester` | OSINT: correos, nombres, hosts, subdominios |
| `puredns` | Fuerza bruta rápida de subdominios con filtrado de comodines |
| `alterx` | Motor de permutación de subdominios |
| `waybackurls` | Recopilación de URLs históricas de Wayback Machine |
| `httprobe` | Sonda de hosts HTTP/HTTPS activos |
### TLS / SSL
| Tool | Notas |
|------|-------|
| `testssl` | Auditoría de configuración TLS y suites de cifrado |
| `sslyze` | Escáner TLS (suites de cifrado, Heartbleed, ROBOT) |
| `sslscan` | Escáner de servicios SSL/TLS |
| `tlsx` | Sondaje TLS rápido |
| `tls_attacker` | Herramienta de ataque al protocolo TLS |
| `ssh_audit` | Auditor de configuración y algoritmos SSH |
### SMB y Servicios de Red
| Tool | Notas |
|------|-------|
| `smbmap` | Enumeración de recursos compartidos SMB y permisos |
| `enum4linux` | Enumeración SMB/NetBIOS |
| `crackmapexec` | Evaluación de Active Directory y SMB |
| `openvas` | Escáner de vulnerabilidades OpenVAS |
### SAST y Análisis de Código
| Tool | Notas |
|------|-------|
| `bandit` | SAST de Python — anti-patrones de seguridad comunes |
| `semgrep` | SAST multilenguaje con reglas de la comunidad |
| `gosec` | Verificador de seguridad de Go |
| `bearer` | SAST de flujo de datos con reglas de privacidad y seguridad |
| `horusec` | Motor SAST multilenguaje |
| `brakeman` | Escáner SAST para Ruby on Rails |
| `flawfinder` | Análisis estático de C/C++ para fallos comunes |
| `dependency_check` | Escáner de vulnerabilidades de dependencias OWASP |
| `pip_audit` | Verificador de vulnerabilidades de paquetes Python |
### Análisis de Composición de Software (SCA)
| Tool | Notas |
|------|-------|
| `osv-scanner` | Escáner de la base de datos de vulnerabilidades de código abierto |
| `npm-audit` | Auditoría de vulnerabilidades de paquetes Node.js |
| `govulncheck` | Verificador de vulnerabilidades de módulos Go |
### Detección de Secretos
| Tool | Notas |
|------|-------|
| `gitleaks` | Escáner de secretos en historial de Git |
| `trufflehog` | Buscador de secretos profundo basado en entropía |
| `secretfinder` | Secretos en archivos JS y endpoints |
| `detect-secrets` | Escáner de secretos basado en línea base (baseline) |
| `noseyparker` | Escáner de secretos de alta velocidad con reglas de patrones |
### IaC y Configuración
| Tool | Notas |
|------|-------|
| `checkov` | Escáner IaC para Terraform/K8s/Dockerfile |
| `tfsec` | Análisis estático de Terraform |
| `terrascan` | Escáner de seguridad IaC multinube |
| `hadolint` | Linter de mejores prácticas para Dockerfile |
### Infraestructura en la Nube
| Tool | Notas |
|------|-------|
| `prowler` | Evaluación de postura de seguridad de AWS/GCP/Azure |
| `kube-bench` | Verificador de CIS Kubernetes Benchmark |
### Contenedores y Cadena de Suministro
| Tool | Notas |
|------|-------|
| `trivy` | Escáner de vulnerabilidades de imágenes de contenedor + sistema de archivos |
| `grype` | Comparador de vulnerabilidades de contenedores y paquetes |
---
## Filtrado por Tipo de Objetivo
El orquestador clasifica cada objetivo en uno o más tipos y solo ejecuta herramientas que declaran soporte para ese tipo. Esto elimina ruido, por ejemplo, de herramientas SMB ejecutándose contra URLs web.
| Tipo | Ejemplo | Herramientas que coinciden |
|------|---------|-----------------|
| `HOST` | `example.com` | Herramientas DNS, SSL, web, SMB |
| `IP` | `10.0.0.1` | Herramientas de red, puertos, SMB |
| `CIDR` | `10.0.0.0/24` | Escáneres de red |
| `URL` | `https://app.example.com` | Herramientas web, API, SSL |
| `PATH` | `/src/myapp` | Herramientas SAST, SCA, secretos, IaC |
| `REPO` | `https://github.com/org/repo` | Herramientas de secretos, SAST, SCA |
| `IMAGE` | `myapp:latest` | Escáneres de contenedores |
| `CLOUD` | `aws:profile=prod`, `arn:aws:…` | Herramientas de postura en la nube (prowler, kube-bench, terrascan) |
La clasificación es automática: basta con pasar la cadena del objetivo; el escáner determina el tipo.
Formatos de objetivo en la nube reconocidos:
- AWS ARN: `arn:aws:iam::123456789012:root`
- Abreviatura de perfil con nombre: `aws:profile=production`
- Proyecto GCP: `projects/my-project-id`
- UUID de suscripción de Azure: `00000000-0000-0000-0000-000000000000`
---
## Modos de Escaneo
| Modo | Descripción |
|------|-------------|
| `paranoid` | Máximo sigilo — sondeo pasivo, huella mínima |
| `passive` | Sin ataques activos — solo enumeración y captura de banners **(por defecto)** |
| `active` | Comprobaciones estándar de vulnerabilidades habilitadas |
| `aggressive` | Escaneo completo: todas las plantillas, fuerza bruta, temporización rápida |
---
## Escaneo Autenticado
Las credenciales se reenvían a todas las herramientas web aplicables (nuclei, ffuf, feroxbuster, gobuster, nikto, sqlmap, dalfox, wpscan, wapiti, katana, hakrawler, arjun, wfuzz, corscanner, kiterunner, httpx).
### Credenciales globales
Se aplican a cada objetivo a menos que exista una configuración específica por objetivo.
**Vía configuración:**```toml
[scan.auth]
bearer_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
username = "admin"
password = "secret"
[scan.auth.cookies]
session = "abc123"
[scan.auth.headers]
X-API-Key = "my-api-key"
A través de variables de entorno (solo global):```bash VS_AUTH_BEARER_TOKEN=eyJ... VS_AUTH_USERNAME=admin VS_AUTH_PASSWORD=secret
**Mediante CLI** (solo global):```bash
vuln-scanner --targets https://app.example.com \
--auth-bearer eyJ... \
--auth-cookie session=abc123 \
--auth-header X-API-Key=secret
Al escanear múltiples objetivos que requieren diferentes credenciales, define anulaciones por objetivo bajo [scan.auth.targets."<target>"]. Una entrada coincidente reemplaza por completo la configuración global para ese objetivo — no hay fusión. La autenticación por objetivo es solo de archivo de configuración (las variables de entorno y las banderas de CLI solo establecen el valor predeterminado global).```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"
**Resolución:** `per-target config > global config`
---
## Análisis LLM
Cuando hay una clave API presente, la capa LLM se activa automáticamente. Realiza cuatro pasadas sobre los resultados del escaneo:
| Pase | Nombre | Qué hace |
|------|------|-------------|
| 1 | **Triaje** | Asigna CWE, confianza, indicador de falso positivo, resumen de explotabilidad y diseña un PoC para cada hallazgo |
| 2 | **Generación de PoC** | Escribe scripts autónomos de Python/Bash que confirman el hallazgo utilizando herramientas ya presentes en el contenedor |
| 3 | **Mitigación** | Produce mitigaciones concretas a corto plazo y remediaciones permanentes, opcionalmente informadas por la evidencia del PoC |
| 4 | **Agrupación** | Agrupa los hallazgos por causa raíz, escribe remediaciones compartidas y produce un resumen ejecutivo |
### Configuración del proveedor
El cliente LLM es compatible con la API de OpenAI — funciona con OpenAI, Azure OpenAI, Ollama, vLLM, LM Studio, OpenRouter y cualquier otro endpoint 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
Ejemplo de Ollama:```toml [llm] base_url = "http://localhost:11434/v1" api_key = "ollama" model = "llama3.2"
**vLLM ejemplo:**```toml
[llm]
base_url = "http://localhost:8000/v1"
api_key = "token-abc123"
model = "meta-llama/Meta-Llama-3-8B-Instruct"
Cada capacidad de LLM es una característica con nombre, activable globalmente y redefinible por herramienta o por categoría.
Configuración global de características:```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
**Precedencia de características:** `tool override > category override > global`
### Prompts personalizados
Todos los prompts de LLM se pueden sobrescribir:```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"]
---
## Generación y Ejecución de PoC
### Generación (siempre segura para el host)
El LLM escribe scripts autocontenidos de Python y/o Bash por cada hallazgo. Los scripts utilizan herramientas ya presentes en la imagen de BlackArch (`curl`, `sqlmap`, `nuclei`, `dalfox`, etc.) y se escriben en `<report>_assets/poc/`. La generación nunca ejecuta código — solo escribe archivos.```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
La ejecución del PoC está controlada por dos protecciones independientes:
execute_poc = true en [llm.features]VS_IN_CONTAINER=1 (integrada en la imagen Docker)El ejecutor se niega silenciosamente si falta cualquiera de las dos protecciones, por lo que no puede ejecutarse en el host. Una lista de denegación estática rechaza scripts que contengan patrones destructivos (rm -rf /, mkfs., fork bombs, etc.) antes de la ejecución.```bash
VS_LLM_FEATURE_EXECUTE_POC=true docker compose ... run --rm scanner ...
---
## Sistema de Plugins
Coloca un archivo `.py` que defina una o más subclases de `AbstractTool` en `./plugins/` (o `~/.vuln-scanner/plugins/`) y se autodetectan automáticamente al inicio, sin necesidad de cambios en el código.
**Orden de detección** (las entradas posteriores sobrescriben en caso de colisión de nombres):
1. `./plugins/` (relativo al CWD)
2. `~/.vuln-scanner/plugins/`
3. Directorios adicionales configurados mediante `[plugins] dirs` o `--plugin-dir`
**Ejemplo 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]:
...
Configuración:```toml [plugins] enabled = true dirs = ["/opt/company-scanners"]
**CLI:**```bash
vuln-scanner --plugin-dir /opt/company-scanners --targets https://app.example.com
Las herramientas de los plugins se registran globalmente, pero el control de tipos del orquestador determina contra qué objetivos se ejecuta realmente cada plugin. Un plugin que declare applicable_targets = frozenset({TargetType.URL}) nunca se activará contra una IP o una ruta del sistema de archivos.
Para restringir un plugin a cadenas de objetivo específicas más allá del control de tipos (por ejemplo, ejecutarlo solo contra un host de ensayo conocido), devuelve ScanStatus.SKIPPED dentro de 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)
No hay un filtro de plugin por objetivo a nivel de configuración — esa lógica pertenece al propio plugin.
---
## Formatos de Informe
Se generan tres formatos en paralelo. Seleccione cualquier combinación:```toml
[report]
formats = ["markdown", "html", "json"]
output_dir = "./reports"
O vía CLI: --formats markdown html json
.md)Informe estructurado profesional que sigue las convenciones de la industria para pentests:
Los hallazgos de múltiples herramientas que reportan el mismo problema en el mismo objetivo se deduplican en una única entrada que muestra todas las herramientas que contribuyen.
.html)Informe autónomo de un solo archivo (sin dependencias externas) con:
.json)Volcado estructurado completo del modelo Assessment — hallazgos, enriquecimiento con LLM, clústeres, estadísticas, registros PoC. Adecuado para la ingesta en pipelines CI/CD y herramientas posteriores.
El script poc.sh inicia DefectDojo, tres objetivos vulnerables y el escáner con un solo comando.
Requisitos previos: docker, plugin docker compose, curl, `python3````bash
./poc.sh
| Paso | Acción |
|------|--------|
| 1 | Comprueba los requisitos previos |
| 2 | Carga `.env` (copia desde `.env.example` si falta) |
| 3 | Inicia el stack de DefectDojo |
| 4 | Espera a que la API de DefectDojo esté lista |
| 5 | Obtiene el token de API mediante credenciales de administrador |
| 6 | Inicia los contenedores de objetivos vulnerables |
| 7 | Espera a que cada objetivo sea accesible |
| 8 | Construye la imagen Docker del escáner |
| 9 | Ejecuta el escáner, genera informes y los envía a DefectDojo |
| 10 | Imprime un resumen con URLs e instrucciones de desmontaje |
**Con análisis de 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
Anular modo de escaneo:```bash SCAN_MODE=active ./poc.sh
**Desglose:**```bash
docker compose down -v
docker compose -f docker-compose.target.yaml down -v
poc.sh)| App | URL | Descripción |
|---|---|---|
| OWASP Juice Shop | http://localhost:3000 | Aplicación moderna de Node.js que cubre el OWASP Top 10 |
Sistemas disponibles públicamente e intencionalmente vulnerables, mantenidos por pentest-ground.com. No se requiere configuración — escanee directamente para validar herramientas y generación de PoC.
---
## scanner.sh — Wrapper de Docker
`scanner.sh` es la interfaz recomendada para el uso diario del escáner. Envuelve `docker compose run` para que nunca necesites escribir la invocación de compose manualmente: solo pasa los objetivos y las banderas directamente.```bash
./scanner.sh [OPTIONS] [-- SCANNER_ARGS...]
Todo lo que aparece después de -- se reenvía tal cual al punto de entrada del escáner, omitiendo toda la lógica del envoltorio.
./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
### Qué hace automáticamente
- Carga `.env` (la copia desde `.env.example` si falta)
- Copia `config.example.toml` → `config.toml` si no existe configuración
- Crea la red Docker `vuln_scanner_network` si no está presente
- Monta un archivo `--config` personalizado en el contenedor en `/app/config.toml`
- Reconstruye la imagen cuando se pasa `--build`
---
## Configuración
Copia la plantilla anotada:```bash
cp config.example.toml config.toml
Referencia completa:```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
**Precedencia de combinación de configuración:** `CLI > env vars > config.toml > defaults`
---
## Variables de entorno
### Núcleo
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `VS_TARGETS` | `--targets` | Lista de objetivos separados por espacios |
| `VS_MODE` | `--mode` | Modo de escaneo |
| `VS_TIMEOUT` | `--timeout` | Tiempo de espera por herramienta (segundos) |
| `VS_RATE_LIMIT` | `--rate-limit` | Límite de tasa (req/s) |
| `VS_MAX_CONCURRENT` | `--max-concurrent` | Espacios paralelos de herramientas |
| `VS_INCLUDE_TOOLS` | `--include-tools` | Lista blanca de herramientas por nombre |
| `VS_EXCLUDE_TOOLS` | `--exclude-tools` | Lista negra de herramientas por nombre |
| `VS_INCLUDE_CATEGORIES` | `--include-categories` | Lista blanca de categorías |
| `VS_EXCLUDE_CATEGORIES` | `--exclude-categories` | Lista negra de categorías |
| `VS_OUTPUT_DIR` | `--output-dir` | Directorio de salida de informes |
### Informes
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `VS_FORMATS` | `--formats` | Formatos de informe: `markdown html json` |
### LLM
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `OPENAI_API_KEY` | — | Clave API (variable de entorno estándar, usada como respaldo) |
| `OPENAI_BASE_URL` | — | URL base de respaldo (para endpoints que no son de OpenAI) |
| `VS_LLM_ENABLED` | `--no-llm` | `auto` \| `true` \| `false` |
| `VS_LLM_MODEL` | `--llm-model` | Nombre del modelo (obligatorio cuando está activo) |
| `VS_LLM_TEMPERATURE` | — | Temperatura de muestreo |
| `VS_LLM_MAX_TOKENS` | — | Máximo de tokens de salida |
| `VS_LLM_FEATURE_<NAME>` | `--llm-feature NAME=on` | Interruptor global de funciones, p. ej. `VS_LLM_FEATURE_GENERATE_POC=false` |
| `VS_LLM_FEATURE_EXECUTE_POC` | `--llm-poc-execute` | Habilitar ejecución de PoC (solo contenedor) |
### Escaneo autenticado
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `VS_AUTH_BEARER_TOKEN` | `--auth-bearer` | Token Bearer (`Authorization: Bearer …`) |
| `VS_AUTH_USERNAME` | `--auth-user` | Nombre de usuario HTTP Basic |
| `VS_AUTH_PASSWORD` | `--auth-pass` | Contraseña HTTP Basic |
| `VS_AUTH_LOGIN_URL` | `--auth-login-url` | URL de inicio de sesión basado en formulario |
Las cookies y cabeceras adicionales deben configurarse mediante el archivo de configuración o las flags CLI `--auth-cookie` / `--auth-header`.
### Plugins
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `VS_PLUGINS_ENABLED` | `--no-plugins` | Habilitar/deshabilitar el auto-descubrimiento de plugins |
| `VS_PLUGINS_DIRS` | `--plugin-dir` | Directorios adicionales de plugins (separados por espacios) |
### DefectDojo
| Variable | CLI flag | Descripción |
|----------|----------|-------------|
| `VS_DEFECTDOJO_URL` | `--defectdojo-url` | URL base de DefectDojo |
| `VS_DEFECTDOJO_API_KEY` | `--defectdojo-api-key` | Token de API |
| `VS_DEFECTDOJO_PRODUCT` | — | Nombre del producto |
| `VS_DEFECTDOJO_ENGAGEMENT` | — | Nombre del engagement |
---
## Estructura del proyecto```
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)
Para herramientas puntuales o privadas, usa el Sistema de Plugins — coloca un archivo .py en ./plugins/ sin necesidad de cambios en el código. Para herramientas que deben distribuirse con el proyecto:
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. Regístralo en `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**Consejos:**
- Para herramientas que escriben a un archivo en lugar de a stdout, usa `OUTPUT_FILE_SENTINEL` en `build_command()` y sobrescribe `run()` para llamar a `self._run_with_tempfile()`.
- Las herramientas con `applicable_targets = frozenset(TargetType)` (el valor predeterminado) se ejecutan contra todos los tipos de objetivo — usa esto solo para herramientas genuinamente universales.
- Binario no encontrado → `ScanStatus.SKIPPED` (oculto del informe). Error de herramienta → `ScanStatus.FAILED` (mostrado en el Apéndice A).
---
## Desarrollo```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 .
Categorías de pruebas:
tests/test_config.py — fusión y validación de configuracióntests/test_target_typing.py — classify_target() y applies_to()tests/test_orchestrator_gating.py — compuerta de tipos con herramientas simuladastests/test_llm.py — funciones LLM, cliente simulado, guarda de contenedor del ejecutor de PoCtests/test_reports.py — los tres generadores de informes (Markdown, HTML, JSON)tests/test_nmap.py — analizador de salida de nmapRegla de seguridad: nunca ejecutes herramientas de escaneo reales en el host. Toda la ejecución de herramientas ocurre dentro del contenedor Docker contra los contenedores objetivo aislados. El PocRunner hace cumplir esta regla: comprueba VS_IN_CONTAINER=1 antes de ejecutar cualquier script de PoC, y la imagen Docker incorpora esta variable.
Los hallazgos se envían automáticamente cuando api_key y product_name están configurados.
Obtén tu clave API:
admin / admin)Envío manual:```bash
VS_DEFECTDOJO_API_KEY=your-key
VS_DEFECTDOJO_PRODUCT="My App"
uv run vuln-scanner --targets 192.168.1.1
| Característica | Por defecto | Descripción |
|---|
logs_analysis | on | Alimentar la salida sin procesar de la herramienta al LLM |
enrich | on | Triaje de CWE / confianza / falso positivo / explotabilidad |
classify | on | Clasificar el tipo de hallazgo y el riesgo |
cluster | on | Agrupar hallazgos por causa raíz |
mitigation | on | Generar mitigación y remediación |
generate_poc | on | Escribir scripts de PoC como activos del informe |
execute_poc | off | Ejecutar PoCs en el contenedor (requiere VS_IN_CONTAINER=1) |
false_positive_filter | on | Suprimir falsos positivos probables del informe |
| WebGoat | http://localhost:8888/WebGoat | Aplicación Java/Spring intencionalmente insegura |
| Sistema | URL | Tipo | Clases de Vulnerabilidad |
|---|
| DVWA | https://pentest-ground.com:4280 | Aplicación web clásica | CSRF, XSS, SQLi |
| DVGQL | https://pentest-ground.com:5013 | API GraphQL | CMDi, XSS, SQLi |
| RestFlaw | https://pentest-ground.com:9000 | API REST | SQLi, Inyección de Código, XXE |
| GuardianLeaks | https://pentest-ground.com:81 | Aplicación web | XSS, SSRF, Inyección de Código |
| 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 |
| Indicador | Descripción |
|---|
-t, --targets HOST... | Uno o más objetivos de escaneo (URL, IP, CIDR, ruta, imagen) |
-m, --mode MODE | Modo de escaneo: passive | active | aggressive | paranoid |
-c, --config FILE | Archivo de configuración a montar (predeterminado: ./config.toml) |
-f, --formats FMT | Formatos de informe, separados por comas: markdown,html,json; repetible |
--no-llm | Deshabilitar el enriquecimiento con LLM |
--llm-model MODEL | Anulación del modelo LLM (p. ej. gpt-4o, claude-sonnet-4-5) |
--llm-min-severity SEV | Severidad mínima para LLM: info|low|medium|high|critical |
--include-tools TOOLS | Lista separada por comas de herramientas a ejecutar |
--exclude-tools TOOLS | Lista separada por comas de herramientas a omitir |
-e, --env KEY=VALUE | Pasar una variable de entorno adicional al contenedor |
-b, --build | Reconstruir la imagen Docker antes de ejecutar |
-n, --no-defectdojo | Omitir la integración con DefectDojo |
--shell | Abrir un shell interactivo dentro del contenedor en lugar de escanear |
-h, --help | Mostrar ayuda |