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:

  1. Ejecuta un spider tradicional durante un minuto de forma predeterminada.
  2. Envía solicitudes reales al objetivo.
  3. Observa las respuestas HTTP.
  4. Espera a que termine el análisis pasivo.
  5. 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.
  • curl para el preflight.
  • jq para 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
    ;;
esac

Verifica 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 -version

Prepara el directorio de trabajo:

install -d -m 0750 zap-work
printf '%s\n' "$ZAP_IMAGE" > zap-work/zap-image.txt

Comprueba 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 -g y -c sean 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 resultados PASS en 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.json

Comprueba además:

  • que el log mencione el objetivo esperado;
  • que el resumen contenga PASS, WARN, FAIL o IGNORE;
  • 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 sin WARN ni FAIL efectivos.
  • 1: existe al menos una regla tratada como FAIL.
  • 2: existe al menos un WARN y no hay ningún FAIL.
  • 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
    ;;
esac

No 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.conf

Cada 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ódigo 2 si no hay FAIL.
  • FAIL: bloquea la política y produce código 1.

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 -e

Despué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.txt

Despué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"
    ;;
esac

Este 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:

  1. Produce al menos un WARN.
  2. Confirma el código 2.
  3. Cambia temporalmente esa regla a FAIL.
  4. Confirma el código 1.
  5. Simula un fallo de conectividad.
  6. Confirma el tratamiento del código 3 o del error Docker.
  7. Verifica que los artefactos se publiquen en todos los casos.

No realices estas pruebas en producción.

Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting