Plantilla de Informe de Escaneo de Vulnerabilidades
Una plantilla para resumir hallazgos de escaneos de vulnerabilidades, incluyendo cobertura de activos, distribucion por severidad y seguimiento de remediacion.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Descripcion General
Un Informe de Escaneo de Vulnerabilidades resume los hallazgos de escaneos automatizados de infraestructura, aplicaciones y servicios cloud. Ayuda a equipos de seguridad, gerentes de ingenieria y ejecutivos a comprender la exposicion actual, priorizar la remediacion y rastrear el progreso a lo largo del tiempo. Esta plantilla soporta tanto audiencias tecnicas como ejecutivas.
Cuando Usar
-
For alternatives, see Dependency Vulnerability Report Template.
-
Despues de un escaneo programado de vulnerabilidades en produccion o staging.
-
Antes de un lanzamiento o auditoria de cumplimiento.
-
Durante revisiones de seguridad mensuales o trimestrales.
-
Al incorporar un nuevo activo o servicio al programa de escaneo.
-
Despues de una brecha o incidente para evaluar sistemas expuestos.
Prerequisitos
- Un escaner de vulnerabilidades configurado y ejecutado, como Nessus, Qualys o Tenable.
- Un inventario de activos con duenos, ambientes y clasificaciones de criticidad.
- Un esquema de clasificacion de severidad, como CVSS o tu propia matriz de riesgo.
- SLAs de remediacion definidos por severidad.
Solucion
Plantilla
1. Resumen Ejecutivo
| Campo | Valor |
|---|---|
| Periodo de reporte | 2026-06-01 a 2026-06-30 |
| Activos totales escaneados | 142 |
| Activos con hallazgos | 38 |
| Hallazgos criticos | 3 |
| Hallazgos altos | 12 |
| Hallazgos medios | 47 |
| Hallazgos bajos | 89 |
| Tasa de remediacion | 78% de hallazgos cerrados del periodo anterior |
| Tendencia general | Mejorando |
2. Alcance y Cobertura del Escaneo
| Grupo de Activos | Activos Escaneados | Cobertura % | Tipo de Escaneo | Dueno |
|---|---|---|---|---|
| Servidores de produccion | 54 | 100% | Escaneo de red autenticado | Equipo de plataforma |
| Cargas de trabajo cloud | 36 | 95% | Escaneo basado en agente | Equipo cloud |
| Aplicaciones web | 18 | 100% | DAST | Seguridad de aplicaciones |
| Contenedores | 24 | 80% | Escaneo de registro + runtime | Equipo DevOps |
| Bases de datos | 10 | 100% | Escaneo de configuracion | Equipo DBA |
3. Hallazgos por Severidad
| Severidad | Cantidad | Abiertos | En Progreso | Cerrados | Promedio de Dias para Remediar |
|---|---|---|---|---|---|
| Critico | 3 | 1 | 1 | 1 | 2 |
| Alto | 12 | 4 | 3 | 5 | 7 |
| Medio | 47 | 15 | 12 | 20 | 21 |
| Bajo | 89 | 30 | 25 | 34 | 45 |
4. Principales Hallazgos Criticos
| Hallazgo | CVE | Activos Afectados | Severidad | Exploit Disponible | Remediacion | Dueno | Fecha Limite |
|---|---|---|---|---|---|---|---|
| OpenSSL sin parchear | CVE-2026-XXXX | api-01, api-02 | Critico | Si | Actualizar a 3.0.9 | Equipo backend | 2026-07-02 |
| Servicio RDP expuesto | N/A | jump-host-legacy | Critico | Si | Deshabilitar RDP, usar bastion | Equipo de red | 2026-07-01 |
| Cuenta admin por defecto | N/A | staging-db | Critico | No | Remover o renombrar cuenta | Equipo DBA | 2026-07-03 |
5. Seguimiento de Remediacion
| ID Hallazgo | Titulo | Severidad | Dueno | Abierto | Fecha Limite | Estado | Notas |
|---|---|---|---|---|---|---|---|
| VULN-042 | OpenSSL sin parchear | Critico | Equipo backend | 2026-06-15 | 2026-07-02 | En progreso | Parche en staging para release |
| VULN-043 | Puerto SMB expuesto | Alto | Equipo de red | 2026-06-20 | 2026-07-05 | Abierto | Regla de firewall pendiente de aprobacion |
| VULN-044 | Version TLS obsoleta | Medio | Equipo de plataforma | 2026-06-10 | 2026-07-10 | En progreso | Config probada en staging |
| VULN-045 | Header de seguridad faltante | Bajo | Equipo frontend | 2026-06-25 | 2026-08-01 | Abierto | Programado para el siguiente sprint |
6. Analisis de Tendencias
| Periodo | Critico | Alto | Medio | Bajo | Total | Cerrados | Tasa de Remediacion |
|---|---|---|---|---|---|---|---|
| 2026-03 | 5 | 18 | 62 | 110 | 195 | 160 | 82% |
| 2026-04 | 4 | 15 | 55 | 98 | 172 | 145 | 84% |
| 2026-05 | 2 | 14 | 50 | 92 | 158 | 130 | 82% |
| 2026-06 | 3 | 12 | 47 | 89 | 151 | 120 | 78% |
Explicacion
El informe convierte la salida cruda del escaner en una historia estructurada: que se escaneo, que se encontro, quien lo esta corrigiendo y que tan rapido. El resumen ejecutivo da a la direccion una vista rapida, mientras que las tablas detalladas proporcionan elementos útiles a los ingenieros. El analisis de tendencias muestra si el programa de seguridad esta mejorando o quedando atras.
Variantes
- Informe de dashboard ejecutivo: Resumen de una pagina con graficos y postura de riesgo.
- Informe tecnico de escaneo: Detalles completos de hallazgos con CVSS, paquetes afectados y comandos de remediacion.
- Informe de configuracion cloud: Enfocado en malconfiguraciones cloud de herramientas como Prowler o CloudSploit.
- Informe DAST: Hallazgos especificos de aplicaciones web de escaneres en vivo.
- Informe mensual de cumplimiento: Mapea hallazgos a marcos de control y rastrea cumplimiento de SLA.
Lo que funciona
- Incluye la cobertura de activos para que los interesados sepan que no se escaneo.
- Prioriza por explotabilidad e impacto de negocio, no solo por CVSS.
- Asigna cada hallazgo a un dueno nombrado con fecha limite.
- Rastrea el estado de remediacion semanalmente hasta el cierre.
- Vuelve a probar despues de la remediacion para confirmar la correccion.
- Compara tendencias a traves de periodos para medir mejora.
- Documenta riesgos aceptados con justificacion y vencimiento.
Errores Comunes
- Reportar solo conteos de vulnerabilidades sin contexto.
- No rastrear que activos fueron inalcanzables o no escaneados.
- Asignar hallazgos a equipos sin capacidad o contexto.
- Cerrar hallazgos sin verificar la correccion.
- Ignorar hallazgos medios y bajos hasta que se acumulan.
- No incluir datos de tendencia o comparacion historica.
Soluciones Avanzadas
Pipeline automatizado de escaneo de vulnerabilidades con Trivy y GitHub Actions
Programa escaneos automatizados de imagenes de contenedor y genera reportes estructurados:
# .github/workflows/vuln-scan.yml
name: Vulnerability Scan Report
on:
schedule:
- cron: "0 2 * * 1" # Weekly Monday 2am
workflow_dispatch:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: "myregistry/app:latest"
format: "json"
output: "trivy-report.json"
severity: "CRITICAL,HIGH,MEDIUM"
exit-code: "0" # Don't fail the workflow
- name: Parse and summarize findings
run: |
python scripts/parse_vuln_report.py \
--input trivy-report.json \
--output vuln-summary.md \
--format markdown
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: vulnerability-report
path: |
trivy-report.json
vuln-summary.md
# scripts/parse_vuln_report.py
import json
import argparse
from collections import Counter
from datetime import datetime
def parse_trivy_report(input_file: str, output_file: str) -> None:
"""Parse Trivy JSON report and generate a markdown summary."""
with open(input_file) as f:
data = json.load(f)
severity_counts = Counter()
findings_by_severity = {"CRITICAL": [], "HIGH": [], "MEDIUM": [], "LOW": []}
for result in data.get("Results", []):
target = result.get("Target", "unknown")
for vuln in result.get("Vulnerabilities", []):
severity = vuln.get("Severity", "UNKNOWN")
severity_counts[severity] += 1
if severity in findings_by_severity:
findings_by_severity[severity].append({
"target": target,
"cve": vuln.get("VulnerabilityID", "N/A"),
"package": vuln.get("PkgName", "N/A"),
"installed": vuln.get("InstalledVersion", "N/A"),
"fixed": vuln.get("FixedVersion", "N/A"),
})
with open(output_file, "w") as f:
f.write(f"# Vulnerability Scan Report - {datetime.now().strftime('%Y-%m-%d')}\n\n")
f.write("## Executive Summary\n\n")
f.write(f"| Metric | Value |\n|--------|-------|\n")
f.write(f"| Total findings | {sum(severity_counts.values())} |\n")
f.write(f"| Critical | {severity_counts.get('CRITICAL', 0)} |\n")
f.write(f"| High | {severity_counts.get('HIGH', 0)} |\n")
f.write(f"| Medium | {severity_counts.get('MEDIUM', 0)} |\n")
f.write(f"| Low | {severity_counts.get('LOW', 0)} |\n\n")
for severity in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
findings = findings_by_severity[severity]
if not findings:
continue
f.write(f"## {severity.title()} Findings ({len(findings)})\n\n")
f.write("| Target | CVE | Package | Installed | Fixed |\n")
f.write("|--------|-----|---------|-----------|-------|\n")
for finding in findings[:20]: # Top 20 per severity
f.write(
f"| {finding['target']} | {finding['cve']} | "
f"{finding['package']} | {finding['installed']} | "
f"{finding['fixed']} |\n"
)
if len(findings) > 20:
f.write(f"\n*...and {len(findings) - 20} more*\n")
f.write("\n")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
args = parser.parse_args()
parse_trivy_report(args.input, args.output)
Prowler para escaneo de configuracion AWS
Escanea entornos AWS en busca de malconfiguraciones y genera un reporte alineado con cumplimiento:
#!/bin/bash
set -euo pipefail
# Run Prowler against AWS account
prowler aws \
--output-formats json html \
--output-directory ./prowler-reports \
--quiet
# Extract critical findings
jq '[.Controls[] | select(.Status == "FAIL" and .Severity == "critical")] | length' \
prowler-reports/*.json
# Generate summary by service
jq -r '.Controls[] | select(.Status == "FAIL") | .ControlID + " - " + .CheckTitle' \
prowler-reports/*.json > aws-findings-summary.txt
echo "=== AWS Misconfiguration Summary ==="
echo "Critical failures: $(jq '[.Controls[] | select(.Status == "FAIL" and .Severity == "critical")] | length' prowler-reports/*.json)"
echo "High failures: $(jq '[.Controls[] | select(.Status == "FAIL" and .Severity == "high")] | length' prowler-reports/*.json)"
echo "Medium failures: $(jq '[.Controls[] | select(.Status == "FAIL" and .Severity == "medium")] | length' prowler-reports/*.json)"
Priorizacion basada en riesgo con puntuacion EPSS
Combina CVSS con Exploit Prediction Scoring System (EPSS) para priorizar la remediacion:
import requests
from dataclasses import dataclass
from typing import List
@dataclass
class VulnerabilityPriority:
cve: str
cvss_score: float
epss_score: float
is_exploited: bool
is_internet_facing: bool
has_sensitive_data: bool
@property
def priority_score(self) -> float:
"""Calculate composite priority score."""
base = self.cvss_score * 10 # Scale CVSS to 0-100
epss_boost = self.epss_score * 30 # EPSS probability weight
exploited_boost = 25 if self.is_exploited else 0
exposure_boost = 15 if self.is_internet_facing else 0
data_boost = 10 if self.has_sensitive_data else 0
return round(base + epss_boost + exploited_boost + exposure_boost + data_boost, 1)
@property
def priority_label(self) -> str:
if self.priority_score >= 80:
return "P0 - Immediate"
elif self.priority_score >= 60:
return "P1 - Urgent"
elif self.priority_score >= 40:
return "P2 - High"
elif self.priority_score >= 20:
return "P3 - Medium"
else:
return "P4 - Low"
def get_epss_score(cve_id: str) -> float:
"""Fetch EPSS score from FIRST.org API."""
try:
resp = requests.get(
f"https://api.first.org/data/v1/epss?cve={cve_id}",
timeout=10,
)
data = resp.json()
if data.get("data"):
return float(data["data"][0]["epss"])
except Exception:
pass
return 0.0
# Example: Prioritize a list of vulnerabilities
vulns = [
VulnerabilityPriority("CVE-2026-1234", 9.8, get_epss_score("CVE-2026-1234"), True, True, True),
VulnerabilityPriority("CVE-2026-5678", 7.5, get_epss_score("CVE-2026-5678"), False, False, False),
VulnerabilityPriority("CVE-2026-9012", 6.5, get_epss_score("CVE-2026-9012"), False, True, True),
]
vulns.sort(key=lambda v: v.priority_score, reverse=True)
for v in vulns:
print(f"{v.cve}: {v.priority_label} (score: {v.priority_score})") Preguntas frecuentes
- Que se debe considerar critico mas alla de CVSS 9.0?
- Un hallazgo critico debe considerar tambien la explotabilidad, la exposicion a internet, la sensibilidad de los datos y si existe un exploit publico. Una vulnerabilidad CVSS 7 en un servicio publico...
- Como manejamos hallazgos que no pueden parchearse?
- Documenta un control compensatorio, acepta el riesgo con fecha de vencimiento y monitorea cambios. Ejemplos incluyen reglas de WAF, aislamiento de red o monitoreo adicional.
- Quien debe recibir este informe?
- Equipo de seguridad, gerentes de ingenieria, CISO, oficial de cumplimiento y duenos de activos. El resumen ejecutivo es util para la direccion; las tablas detalladas son para equipos de remediacion.
Recursos Relacionados
Plantilla de Reporte de Vulnerabilidades en Dependencias
Una plantilla para documentar hallazgos de seguridad en dependencias, incluyendo severidad, impacto y pasos de remediacion para equipos de ingenieria.
DocPlantilla de Analisis de Brechas de Cumplimiento
Una plantilla para mapear controles de seguridad actuales a marcos de cumplimiento como SOC 2, ISO 27001 y PCI-DSS.
DocPlantilla de Alcance de Prueba de Penetracion
Una plantilla para definir los limites, objetivos, reglas y entregables de una prueba de penetracion.