OWASP ZAP Baseline permite explorar una aplicación web y analizar pasivamente sus respuestas HTTP sin ejecutar las reglas de ataque de un escaneo activo.
En esta guía aprenderás a ejecutarlo con Docker sobre un objetivo autorizado, generar reportes HTML y JSON, convertir los hallazgos en una política INFO/IGNORE/WARN/FAIL y utilizar correctamente sus códigos de salida en CI.
El resultado será una prueba repetible, con imagen fijada por digest, alcance documentado, reportes verificables y un ciclo de corrección y reanálisis.
Importante: Baseline no ejecuta ataques activos, pero su spider sí envía solicitudes y sigue enlaces. Puede activar acciones si la aplicación utiliza solicitudes GET con efectos laterales. Escanea únicamente sistemas propios o con autorización explícita y utiliza staging como opción predeterminada. La FAQ oficial de ZAP advierte sobre este riesgo.
Qué hace ZAP Baseline
El script zap-baseline.py, incluido en las imágenes oficiales de ZAP:
- Ejecuta un spider tradicional durante un minuto de forma predeterminada.
- Envía solicitudes reales al objetivo.
- Observa las respuestas HTTP.
- Espera a que termine el análisis pasivo.
- Genera alertas y reportes.
No envía los payloads utilizados por las reglas de un escaneo activo. Consulta la documentación oficial de Baseline.
El análisis pasivo no modifica las solicitudes ni las respuestas observadas. Sin embargo, la exploración previa sí interactúa con la aplicación. Por eso “pasivo” no significa “sin tráfico” ni “sin riesgo operativo”. Consulta el funcionamiento del Passive Scanner.
Baseline puede detectar, entre otros problemas:
- cabeceras de seguridad ausentes o débiles;
- cookies sin atributos recomendados;
- divulgación de información en respuestas;
- contenido mixto;
- configuraciones HTTP observables pasivamente.
No sustituye pruebas autenticadas, análisis de lógica de negocio, SAST, revisión manual ni un escaneo activo autorizado.
Requisitos
- Docker Engine o Docker Desktop.
- Bash para los ejemplos de captura de salida.
- Una aplicación accesible desde el contenedor, preferentemente en staging.
- Autorización escrita, propietario y ventana de ejecución.
- Una cuenta y datos descartables si se configura autenticación.
- Una ubicación restringida para los reportes.
curlpara el preflight.jqpara validar el reporte JSON.
La guía utiliza ghcr.io/zaproxy/zaproxy:stable. Esta etiqueta se actualiza con releases completos y también se reconstruye periódicamente con la imagen base y los add-ons vigentes. Por eso obtendremos su digest y usaremos ese valor inmutable. Consulta la guía oficial de imágenes Docker.
1. Define y autoriza el alcance
Antes de ejecutar ZAP, documenta:
- URL y entorno exactos;
- propietario que autoriza la prueba;
- horario y límites de tráfico;
- hostname completo autorizado;
- rutas que no deben explorarse;
- datos que pueden aparecer en los reportes;
- criterio para detener la ejecución;
- contacto responsable ante efectos inesperados.
Configura la URL. Sustituye el dominio reservado por el staging autorizado:
export TARGET_URL="https://staging.example.com"
case "$TARGET_URL" in
https://*) ;;
*)
echo "El objetivo debe usar HTTPS o contar con una excepción aprobada" >&2
exit 1
;;
esacVerifica el valor:
printf 'Objetivo autorizado: %s\n' "$TARGET_URL"No construyas el target desde una entrada no confiable ni reutilices el job para dominios arbitrarios.
Una ruta no es una frontera de autorización
No utilices un prefijo como https://staging.example.com/aplicacion/ para limitar el alcance.
El script puede normalizar el target hacia la raíz del mismo host. Autoriza el hostname completo y no lo uses si aloja otras aplicaciones fuera del alcance.
Para establecer límites por ruta, utiliza un contexto o un plan de Automation Framework probado previamente. Este comportamiento debe comprobarse contra el código oficial de zap-baseline.py correspondiente al digest seleccionado.
2. Comprueba el objetivo
Desde el host:
curl --fail --silent --show-error --location \
--max-time 15 \
--output /dev/null \
--write-out 'URL final: %{url_effective}\n' \
"$TARGET_URL"Revisa la URL final. Una redirección hacia otro hostname necesita autorización independiente y no debe aceptarse de manera implícita.
Esta comprobación confirma disponibilidad HTTP, no cobertura ni autorización.

El objetivo también debe ser accesible desde la red del contenedor. localhost dentro del contenedor apunta al propio contenedor, no al host.
Si la aplicación se ejecuta en Docker, conecta ambos contenedores a una red dedicada y utiliza el nombre del servicio. No publiques innecesariamente una aplicación en Internet solo para escanearla.
3. Descarga la imagen y fija su digest
export ZAP_TAG="ghcr.io/zaproxy/zaproxy:stable"
docker pull "$ZAP_TAG"
export ZAP_IMAGE="$(
docker image inspect \
--format '{{index .RepoDigests 0}}' \
"$ZAP_TAG"
)"Valida que el digest pertenezca al repositorio esperado:
case "$ZAP_IMAGE" in
ghcr.io/zaproxy/zaproxy@sha256:*) ;;
*)
echo "Digest inesperado: $ZAP_IMAGE" >&2
exit 1
;;
esac
printf '%s\n' "$ZAP_IMAGE"El resultado debería tener esta forma:
ghcr.io/zaproxy/zaproxy@sha256:...Comprueba el script y registra la versión:
docker run --rm "$ZAP_IMAGE" zap-baseline.py -h
docker run --rm "$ZAP_IMAGE" zap.sh -versionPrepara el directorio de trabajo:
install -d -m 0750 zap-work
printf '%s\n' "$ZAP_IMAGE" > zap-work/zap-image.txtComprueba que el usuario del contenedor pueda escribir:
docker run --rm \
-v "$PWD/zap-work:/zap/wrk/:rw" \
"$ZAP_IMAGE" \
sh -c 'test -w /zap/wrk'Si falla, corrige el propietario o grupo según el UID/GID efectivo del contenedor. No amplíes los permisos para todos los usuarios ni uses chmod 777.
Evita actualizaciones durante la ejecución
El digest fija la imagen, pero no garantiza una ejecución comparable si ZAP actualiza add-ons al arrancar.
Los comandos de esta guía utilizan:
-z "-silent"Esto evita actualizaciones y otras solicitudes no solicitadas. Trata cualquier actualización de imagen o add-ons como un cambio controlado y regenera la línea de base. Consulta los parámetros de ZAP.
4. Genera la política inicial
La opción -g genera un archivo con las reglas conocidas configuradas inicialmente como WARN. Esta ejecución también realiza el análisis.
set +e
set -o pipefail
docker run --rm \
-v "$PWD/zap-work:/zap/wrk/:rw" \
"$ZAP_IMAGE" \
zap-baseline.py \
--autooff \
-t "$TARGET_URL" \
-m 2 \
-T 10 \
-g zap-baseline.conf \
-r baseline-inicial.html \
-J baseline-inicial.json \
-s \
-z "-silent" \
2>&1 | tee zap-work/baseline-inicial.log
zap_rc=${PIPESTATUS[0]}
set +o pipefail
set -e
printf 'Código de salida de ZAP: %s\n' "$zap_rc"Las opciones utilizadas son:
--autooff: mantiene el motor clásico para que las ejecuciones con-gy-csean comparables.-t: URL completa del objetivo.-m 2: tiempo del spider tradicional, en minutos.-T 10: límite para el arranque y la finalización del análisis pasivo.-g: genera el archivo de reglas.-r: genera un reporte HTML.-J: genera un reporte JSON.-s: reduce URLs y resultadosPASSen el log.-z "-silent": evita actualizaciones durante el arranque.
El tiempo de -m no representa un límite total estricto. ZAP todavía debe iniciar, procesar las respuestas y completar la cola pasiva.
5. Verifica los artefactos y la cobertura
test -s zap-work/zap-baseline.conf
test -s zap-work/baseline-inicial.html
test -s zap-work/baseline-inicial.json
test -s zap-work/baseline-inicial.log
jq empty zap-work/baseline-inicial.jsonComprueba además:
- que el log mencione el objetivo esperado;
- que el resumen contenga
PASS,WARN,FAILoIGNORE; - que el reporte incluya páginas reales del alcance;
- que no aparezcan dominios ajenos;
- que el spider descubra más que la portada cuando existan enlaces navegables.
Un reporte vacío o limitado a una URL no demuestra que la aplicación esté limpia. Puede significar que el target no era accesible, la navegación depende de JavaScript o las áreas importantes requieren autenticación.
6. Interpreta los códigos de salida
ZAP Baseline utiliza estos códigos:
0: ejecución correcta sinWARNniFAILefectivos.1: existe al menos una regla tratada comoFAIL.2: existe al menos unWARNy no hay ningúnFAIL.3: error de ejecución informado por Baseline.
Docker puede devolver otros códigos, como 125, 126 o 127, antes de que el script llegue a ejecutarse.
Interpreta el estado explícitamente:
case "$zap_rc" in
0)
echo "Baseline completado sin WARN ni FAIL"
;;
1)
echo "La política contiene al menos un FAIL"
;;
2)
echo "Hay WARN para revisión, sin FAIL"
;;
3)
echo "ZAP no pudo completar la ejecución" >&2
;;
*)
echo "Error de Docker o infraestructura: $zap_rc" >&2
;;
esacNo ejecutes el comando sin capturar su estado dentro de un script con set -e.
Una línea de base con alertas predeterminadas puede devolver 2 y detener el job aunque no exista ningún FAIL. PIPESTATUS[0] conserva el código real de Docker detrás de tee.
Insertar aquí la Imagen 2 mostrada arriba: política y códigos de salida.
7. Convierte la línea de base en una política
Abre:
zap-work/zap-baseline.confCada fila contiene el ID de una regla y una acción. ZAP decide por el identificador; el nombre de la regla es informativo.
Las acciones disponibles son:
INFO: conserva el resultado como información y no bloquea.IGNORE: ignora la regla dentro de la política.WARN: requiere revisión y produce código2si no hayFAIL.FAIL: bloquea la política y produce código1.
FAIL no significa automáticamente “vulnerabilidad confirmada” ni “riesgo alto”. Es una decisión de política aplicada a un ID.
ZAP administra por separado el riesgo y la confianza de una alerta, y define una alerta como una vulnerabilidad potencial asociada con una solicitud. Consulta los campos oficiales de las alertas.
Para cada cambio registra:
- ID y nombre de la regla;
- acción anterior y nueva;
- motivo;
- responsable;
- evidencia;
- alcance;
- fecha de revisión o vencimiento;
- enlace al ticket.
No cambies masivamente reglas a IGNORE para obtener un job verde.
Qué significa OUTOFSCOPE
La configuración admite filas OUTOFSCOPE con expresiones regulares.
Estas filas evitan que determinadas coincidencias de alerta afecten al resultado para una URL. No garantizan que el spider deje de solicitar esa URL.
No las utilices como control para endpoints peligrosos. Para controlar la exploración usa un contexto con exclusiones probado o un plan de Automation Framework. Esta diferencia depende del motor y puede comprobarse en el código oficial común de los scripts Docker.
8. Ejecuta con la política aprobada
set +e
set -o pipefail
docker run --rm \
-v "$PWD/zap-work:/zap/wrk/:rw" \
"$ZAP_IMAGE" \
zap-baseline.py \
--autooff \
-t "$TARGET_URL" \
-m 2 \
-T 10 \
-c zap-baseline.conf \
-r baseline.html \
-J baseline.json \
-s \
-z "-silent" \
2>&1 | tee zap-work/baseline.log
zap_rc=${PIPESTATUS[0]}
set +o pipefail
set -eDespués verifica:
test -s zap-work/baseline.html
test -s zap-work/baseline.json
test -s zap-work/baseline.log
jq empty zap-work/baseline.json-s reduce la exposición de URLs en la consola, pero los reportes siguen conteniendo detalles. Deben tratarse como información sensible.
9. Aplica la decisión en CI
Publica siempre como artefactos restringidos:
baseline.html;baseline.json;baseline.log, después de revisarlo;zap-baseline.conf;zap-image.txt;- el código de salida.
printf '%s\n' "$zap_rc" > zap-work/zap-exit-code.txtDespués aplica la política:
case "$zap_rc" in
0)
exit 0
;;
1)
echo "Bloqueado por reglas configuradas como FAIL" >&2
exit 1
;;
2)
echo "WARN registrados para revisión"
exit 0
;;
3)
echo "ZAP informó un error de ejecución" >&2
exit 3
;;
*)
echo "Docker o la infraestructura fallaron con código $zap_rc" >&2
exit "$zap_rc"
;;
esacEste ejemplo mantiene los WARN visibles pero no bloqueantes. Si la política requiere bloquearlos, conserva el código 2 como fallo.
La opción -I también evita que los warnings provoquen fallo, pero capturar el código conserva la diferencia entre 0 y 2.
Configura la publicación de artefactos con una condición equivalente a “siempre”. El reporte es especialmente necesario cuando la ejecución devuelve 1, 2, 3 o un error de Docker.
Prueba la puerta antes de activarla
En un fixture autorizado:
- Produce al menos un
WARN. - Confirma el código
2. - Cambia temporalmente esa regla a
FAIL. - Confirma el código
1. - Simula un fallo de conectividad.
- Confirma el tratamiento del código
3o del error Docker. - Verifica que los artefactos se publiquen en todos los casos.
No realices estas pruebas en producción.