Analizar un sitio web o una API: comprobación de exposición y DAST pasivo (experimental)
Pitangus puede revisar un sitio web o una API en funcionamiento que controles y reportar lo que le muestra a cualquier visitante: cabeceras de seguridad que faltan, cookies débiles, archivos expuestos, fugas de información, una configuración TLS anticuada, librerías con vulnerabilidades conocidas. Esto es DAST (pruebas dinámicas de seguridad de aplicaciones: revisar la aplicación mientras corre, desde fuera), y en Pitangus es pasivo: las herramientas navegan y leen respuestas, nunca atacan. Cada resultado es un hallazgo que confirmas antes de actuar.
Esta página cubre el camino completo: activar los análisis web, añadir y verificar un dominio, elegir qué analizar, iniciar sesión con usuarios de prueba, lanzar o programar un análisis y leer lo que devuelve.
Dos comprobaciones: la de exposición y el análisis completo (experimental)
Sección titulada «Dos comprobaciones: la de exposición y el análisis completo (experimental)»- Comprobación de exposición (siempre disponible para administradores, sobre un dominio verificado): solo la raíz de
cada host y rutas conocidas, por HTTPS y por HTTP sin cifrar en el puerto 80, sin rastreo y sin ZAP. httpx (qué
ejecuta el servidor y el estado de cada ruta que comprueba), testssl.sh (TLS) y las plantillas de solo detección de
nuclei (cabeceras de respuesta, archivos expuestos como
.git,.envo copias de seguridad, consolas de depuración y de estado como el actuator de Spring Boot, server-status o una consola de Werkzeug). Las rutas conocidas salen de las plantillas propias de Pitangus (entre ellas/.envy/.git/config), y las rutas donde hubo hallazgos se comprueban de nuevo. Un hallazgo en una ruta que el sitio responde igual que una ruta al azar (el mismo estado y la misma página, aunque repita la ruta: una página comodín o un «soft 404») no se reporta: la coincidencia no dice nada de esa ruta.//.envy/.envson la misma ruta (las herramientas envían las barras repetidas como una). Cada URL se pide con su propio esquema: lo que respondió una URL HTTP nunca es la respuesta de su gemela HTTPS, y el paso solo cuenta como respondidas las páginas que pidió. Mismas reglas que el análisis completo: dominio verificado, direcciones fijadas, cada herramienta responde solo por sus propias respuestas, y un host que rechazó la comprobación la deja incompleta. Un hallazgo de exposición solo lo remedia otra comprobación de exposición, y una comprobación de exposición no remedia ni marca como sin verificar los hallazgos de un análisis completo, ni se los queda cuando ambos reportan la misma página: cada tipo de análisis conserva sus hallazgos y la fecha en que los vio por primera vez. Nuevo análisis → Comprobación de exposición, o el botón de análisis del propio dominio. - Análisis web completo (experimental, apagado hasta que un administrador lo activa en Ajustes → Motores de análisis): todo lo de abajo, con ZAP, katana y subfinder rastreando el sitio. No forma parte del núcleo: apagarlo no remedia nada de lo que encontró, esos hallazgos siguen abiertos hasta que un análisis del mismo tipo pruebe que ya no están.
Pasivo, no activo: qué hace un análisis y qué no
Sección titulada «Pasivo, no activo: qué hace un análisis y qué no»Un análisis pasivo envía el mismo tipo de peticiones que envía un navegador cuando alguien visita el sitio: sigue enlaces, carga páginas y lee las respuestas. Un análisis activo envía ataques (inyecciones, fuzzing, envíos de formularios manipulados) para ver si algo se rompe. Hoy Pitangus solo hace análisis pasivos.
| Un análisis web pasivo en Pitangus | Lo que no hace |
|---|---|
| Sigue enlaces con un crawler y un navegador headless | Enviar formularios (salvo el de login de un usuario de prueba que elegiste) |
| Lee cabeceras, cookies, el contenido de las páginas y la configuración TLS | Pulsar botones, escribir datos al azar ni adivinar contraseñas |
Pide rutas conocidas que delatan archivos expuestos (.git, .env, copias de seguridad) |
Enviar inyecciones, payloads ni fuzzing |
| Pide las operaciones GET y HEAD de una definición de API | Enviar peticiones POST, PUT, PATCH ni DELETE |
Es un análisis, no un pentest. Un pentest (prueba de penetración) intenta explotar los fallos y demuestra su impacto; un informe de Pitangus no reemplaza el pentest que piden SOC 2 o ISO 27001. Como no se ataca nada, pocos hallazgos no significan que la aplicación sea segura: no se prueban inyecciones, control de acceso roto ni fallos de lógica de negocio. Cada análisis lista lo que dejó fuera.
Antes de empezar
Sección titulada «Antes de empezar»Necesitas:
- Una cuenta de administración. Los miembros ven los dominios, su estado, su alcance y sus hallazgos; solo quien administra los añade, verifica, cambia, elimina o analiza, y solo esa persona ve el token de verificación y las cabeceras guardadas.
- El runner de Docker. Las herramientas corren en contenedores. La imagen del worker sin socket de Docker
(
pitangus-worker, ver contenedores.md) no las incluye, y el análisis lo indica. - Solo para el análisis completo: un administrador activa Análisis web completo en Ajustes → Motores de
análisis. Es experimental y viene apagado; la comprobación de exposición no necesita nada.
PITANGUS_DAST_ENABLEDen el entorno del servidor lo fija encendido (1) o apagado (0) por encima del panel; defínela para la API y el worker. Ver configuracion.md. - Las imágenes de los motores.
make engines(que también ejecutamake up) descarga las que faltan, cada una fijada por versión y digest: nuclei, testssl.sh y httpx para la comprobación de exposición siempre, y además ZAP, katana y subfinder si el análisis completo está activado. Solo ZAP ocupa unos 1,2 GB; las demás herramientas web, cerca de 1 GB en total.make engines LIST=1lista lo que descargaría, sin descargarlo. - Un sitio HTTPS público en el puerto 443, con un certificado válido y un nombre DNS público. Las direcciones privadas o internas nunca se analizan.
Para el análisis completo, actívalo en Ajustes → Motores de análisis: el worker descarga sus imágenes (y las de katana) al momento, y la fila dice cuándo están listas. Desde la línea de comandos, fíjalo encendido y descárgalas:
echo 'PITANGUS_DAST_ENABLED=1' >> .envmake upmake enginesLa primera vez, make engines muestra cada imagen que descarga, por ejemplo:
Engines: 3 images missing; the first time can take a while depending on your connection.→ ghcr.io/zaproxy/zaproxy:2.17.0→ projectdiscovery/subfinder:v2.16.0→ projectdiscovery/katana:v1.7.0Engines: ready.Cuando ya están todas, imprime Engines: all images are ready. El primer análisis descarga además, una sola vez y
desde GitHub, la versión de las plantillas de nuclei (con su SHA-256 fijado).
Añadir un dominio
Sección titulada «Añadir un dominio»- Abre Escaneo → Dominios y APIs (
#/domains) y pulsa Añadir dominio. - Escribe la dirección del sitio, por ejemplo
https://app.example.com: HTTPS, un dominio público, sin puerto, query, fragmento ni usuario. Mientras escribes, el panel lo sondea y dice si responde (Responde · HTTPS 200) o aún no. Puedes añadirlo en cualquier caso. - Elige un Tipo: Aplicación web, API o Solo inventario (se lista, nunca se analiza). Si quieres, añade un Contexto (qué hace, cómo inician sesión, qué datos maneja); aparece en los informes.
- Pulsa Añadir dominio. A continuación se abre el diálogo de verificación.
El sondeo comprueba que el nombre resuelve solo a direcciones públicas (si no, no se envía nada) y manda un HEAD por
HTTPS a la dirección recién resuelta, con certificado válido y sin redirecciones. Añadir, sondear y verificar no
prueban nada. Un espacio de trabajo guarda como máximo 20 dominios.
Con los análisis web activados, añadir un dominio también inicia la búsqueda de hosts relacionados.
Verificar que lo controlas
Sección titulada «Verificar que lo controlas»Un dominio no se puede analizar hasta que pruebes que lo controlas. Hay tres métodos, todos con el mismo token. El diálogo de verificación muestra los valores exactos que debes copiar para cada uno (pestañas Registro DNS, Archivo y Meta).
| Método | Qué publicas | Qué cubre |
|---|---|---|
| DNS (recomendado) | Un registro TXT llamado _pitangus.<host> con el valor pitangus-verify=<token> |
El host y sus subdominios |
| Archivo | https://<host>/.well-known/pitangus-verify.txt, que responda 200 con el token en el cuerpo |
Ese host exacto |
| Meta | <meta name="pitangus-verify" content="<token>"> en el <head> de https://<host>/ |
Ese host exacto |
Solo una prueba DNS permite que los análisis incluyan subdominios: quien controla la zona los controla.
Registro DNS
Sección titulada «Registro DNS»Añade el registro TXT en tu proveedor de DNS. Para app.example.com, en formato de archivo de zona, se ve así:
_pitangus.app.example.com. 300 IN TXT "pitangus-verify=3q2-7wEXAMPLEtokenVALUE0abcd1234"Comprueba que está publicado antes de pulsar Verificar ahora:
dig +short TXT _pitangus.app.example.com"pitangus-verify=3q2-7wEXAMPLEtokenVALUE0abcd1234"Pitangus pregunta primero a los servidores de nombres autoritativos de la zona, así que un resolver que guardó en caché «ese registro no existe» no te frena; si la red solo permite DNS a través del resolver local, recurre a él.
Archivo o etiqueta meta
Sección titulada «Archivo o etiqueta meta»Publica el archivo (el diálogo tiene Descargar archivo) o añade la etiqueta a la página de inicio, y compruébalo desde fuera:
curl -sS https://app.example.com/.well-known/pitangus-verify.txtPitangus pide el archivo o la página de inicio una vez, desde la dirección pública ya comprobada del host (nunca una
privada), por HTTPS con certificado válido, sin seguir redirecciones, con 10 segundos y 64 KB como máximo. Sirve la
prueba desde ese host exacto: una redirección a www. o a una página de login hace fallar la comprobación.
Cuánto dura
Sección titulada «Cuánto dura»Una prueba vale 90 días. Cada día Pitangus vuelve a pedir la misma prueba (la del método que lo verificó):
- Sigue ahí: los 90 días empiezan de nuevo.
- Ya no está: el dominio deja de estar verificado en el acto, los análisis programados se pausan y alguien tiene que verificarlo otra vez.
- El DNS o el host no responden: nada cambia hasta que se cumplan los 90 días.
El worker también comprueba la prueba justo antes de cada análisis.
Cuando la verificación falla
Sección titulada «Cuando la verificación falla»| Mensaje | Qué hacer |
|---|---|
Aún no aparece el registro TXT en _pitangus.<host> |
Revisa el nombre del registro (algunos proveedores añaden el dominio por ti y queda _pitangus.app.example.com.example.com), su valor y espera la propagación; reintenta en unos minutos. |
| No se pudo consultar DNS | El servidor no llegó al DNS. Revisa su red y reintenta; no cambia nada. |
<url> respondió con una redirección |
Sirve el archivo o la etiqueta desde ese host exacto, sin redirigir. |
<url> no contiene el token de este dominio |
Publica el archivo con el token y comprueba que responda 200. |
La página principal de <host> no tiene la etiqueta meta pitangus-verify |
Añade la etiqueta al <head> de la página de inicio (no de otra página). |
No se pudo llegar a <host> por HTTPS |
El sitio debe responder en el puerto 443 con un certificado válido. |
| Demasiados intentos con este dominio | Espera los segundos que indica antes de reintentar. |


Elegir el alcance: subdominios y hosts relacionados
Sección titulada «Elegir el alcance: subdominios y hosts relacionados»El alcance es el conjunto de hosts a los que puede llegar un análisis. Por defecto, el propio host del dominio. Con una prueba DNS vigente puedes añadir subdominios.
Hosts relacionados que Pitangus encuentra
Sección titulada «Hosts relacionados que Pitangus encuentra»Al añadir un dominio (y cuando pulsas Buscar de nuevo en su pestaña Alcance), Pitangus ejecuta subfinder, una herramienta que busca nombres bajo el dominio solo en fuentes públicas: registros de transparencia de certificados, DNS pasivo y archivos históricos. No usa claves de API y se detiene al minuto. No se envía nada a tus hosts; el nombre de tu dominio sí va a esas fuentes públicas, y por eso la búsqueda solo corre con el análisis web completo activado.
Cada nombre encontrado debe ser un host válido bajo el dominio y resolver solo a direcciones públicas (ni privadas, ni de loopback, ni link-local, ni de metadatos de la nube); el resto se descarta y se cuenta. Los hosts nuevos empiezan excluidos.
Marcar qué analizar
Sección titulada «Marcar qué analizar»En la pestaña Alcance del dominio (#/domain?id=…&tab=scope), o con Incluir subdominios en un análisis nuevo,
quien administra marca cada host como Analizar o Excluir, o añade uno a mano con Añadir host. La elección
se guarda con el dominio, y cada análisis que usa el alcance guardado la lee al empezar: los hosts analizados se
recorren y los excluidos quedan fuera del contexto de ZAP.
| Límite | Valor |
|---|---|
| Hosts analizados además del dominio | 20 |
| Hosts relacionados listados por dominio | 100 |
| Prueba necesaria para incluir cualquier subdominio | Una prueba DNS vigente |
Sin prueba DNS, los hosts se listan pero desactivados, y los análisis llegan solo al host del dominio. Si faltan Docker, la imagen de subfinder o la conexión, la pestaña dice por qué.
Desde la API, un análisis puede listar en su lugar subdominios solo para ese análisis (hosts: hasta 20 nombres o
comodines *.). Un comodín solo amplía el contexto de ZAP: los hosts a los que se llega por él no se resuelven, así que
no se analizan. Lista un host por su nombre para incluirlo.


Llegar a páginas detrás de un login
Sección titulada «Llegar a páginas detrás de un login»Sin credenciales, un análisis solo ve las páginas públicas. Puedes darle acceso de dos formas, ambas opcionales.
Cabeceras de petición
Sección titulada «Cabeceras de petición»Quien administra puede guardar hasta 10 cabeceras por dominio (una API key, un bearer token, una cookie de sesión) en Acceso, dentro del Resumen del dominio. Se guardan cifradas y no se vuelven a mostrar: el panel lista sus nombres, los últimos cuatro caracteres de los valores largos y cuándo se guardaron.
- Un análisis las envía solo si se lo pides (Enviar las cabeceras guardadas), y solo a los hosts del alcance.
- Las envían ZAP, katana y nuclei; testssl.sh y httpx no.
- Los nombres siguen las reglas de token de HTTP; se rechazan
Host,Content-Lengthy las cabeceras hop-by-hop. Los valores son una línea de ASCII imprimible, de 4096 caracteres como máximo. - Los valores nunca llegan al análisis, a su progreso, a los logs, a los hallazgos ni a un archivo en disco.
Una cabecera puede dejar de iniciar sesión sin que nadie lo note (una cookie caduca, un token se revoca), y el análisis
vería entonces solo las páginas públicas. Debajo de las cabeceras, Página de comprobación de sesión recibe una página
HTTPS del dominio (o de uno de sus subdominios) que solo abre con la sesión iniciada, como
https://app.example.com/cuenta. Un análisis que envía las cabeceras la pide con ellas antes de empezar y otra vez al
terminar, desde la dirección fijada del host y sin seguir redirecciones:
- Un 2xx las dos veces: el paso Sesión de las cabeceras guardadas queda completo.
- Una redirección (al login), un 401 o 403, ninguna respuesta, o una página en un host fuera del alcance del análisis: el paso queda Parcial y el análisis Incompleto, así que no marca nada como remediado.
Sin página de comprobación de sesión, nadie prueba que las cabeceras sigan iniciando sesión: el análisis lo dice en sus limitaciones y no marca como remediado nada de lo que encontró con ellas (lo que había tras el login puede simplemente no haberse alcanzado).
Usuarios de prueba
Sección titulada «Usuarios de prueba»Un usuario de prueba es una cuenta de tu aplicación con la que el análisis inicia sesión para ver lo que ve un usuario con sesión. Usa cuentas de prueba dedicadas, no las de personas reales.
En la pestaña Usuarios de prueba del dominio (#/domain?id=…&tab=users), pulsa Añadir usuario y completa:
| Campo | Notas |
|---|---|
| Nombre | Cómo lo vas a reconocer, por ejemplo «Usuario administrador». |
| Método | Usuario y contraseña, o App de autenticación (TOTP) para cuentas con segundo factor. |
| Usuario o correo, Contraseña | Cifrados; la contraseña no se puede volver a leer, solo reemplazar. |
| Clave de la app de autenticación (secreto TOTP) | La clave en base32 que aparece al configurar la app (16 caracteres como mínimo); 6 a 8 dígitos, 15 a 120 segundos, SHA1, SHA256 o SHA512. |
| URL de login (opcional) | Donde empieza el inicio de sesión. En blanco, el análisis abre la página de inicio del host y sigue el enlace de login que encuentre. |
| Comprobar con (opcional) | Una página que solo ve quien inició sesión, como /account. |
| Se aplica a | El host al que pertenece la cuenta: el dominio o uno de sus subdominios. |
| Notas (opcional) | Texto libre. |
Un dominio guarda hasta 10 usuarios de prueba y un análisis inicia sesión con 3 como máximo. No se admiten
códigos por correo ni enlaces mágicos: nadie lee ese buzón. Se rechaza una contraseña, clave o URL que contenga ${.


Cómo se comprueba el inicio de sesión
Sección titulada «Cómo se comprueba el inicio de sesión»Antes de recorrer el sitio, cada usuario de prueba elegido inicia sesión por separado, en un ZAP propio, a través de un Firefox headless (la autenticación por navegador de ZAP; con TOTP, el código va en el campo que sigue a la contraseña). Después:
- Con Comprobar con, ZAP pide esa página como ese usuario. Cualquier respuesta distinta de 200 (una redirección al login, un 401, un 403) es un inicio de sesión fallido.
- Sin ella, decide el informe de autenticación del propio ZAP.
El análisis dice entonces Sesión iniciada como «nombre» o No pudo iniciar sesión como «nombre» con el motivo (en palabras de ZAP cuando las dio).
Cuando falla el inicio de sesión
Sección titulada «Cuando falla el inicio de sesión»No se recorre el sitio como un usuario que no pudo iniciar sesión. El análisis sigue con los demás y de forma anónima, y queda marcado como incompleto con cobertura parcial, junto a sus resultados, en sus limitaciones y en sus informes. Así, pocos o ningún hallazgo detrás de ese login nunca se leen como «limpio». Cada usuario que sí inició sesión tiene su propio recorrido (2 minutos, más 2 de spider AJAX).
Solo ZAP inicia sesión. katana, nuclei, testssl.sh y httpx revisan el sitio de forma anónima.
Los secretos nunca llegan a ZAP por su plan, por una línea de comandos, por un archivo en el host ni por
docker inspect: viajan por la entrada estándar del contenedor y se limpian de lo que devuelve ZAP.
Lanzar un análisis
Sección titulada «Lanzar un análisis»- Pulsa Nuevo análisis (
#/new) y elige Análisis web completo (o Comprobación de exposición, que solo pide la raíz de cada host y rutas conocidas). Si el análisis completo dice No está activado en este servidor, mira Errores frecuentes. - Objetivo: elige un dominio verificado. Activa Incluir subdominios para usar el alcance guardado (los hosts que marques aquí como Analizar se guardan para sus próximos análisis). Para una API, añade su Documentación de la API (ver Modo API).
- Acceso: elige hasta 3 usuarios de prueba y, si el dominio las tiene, Enviar las cabeceras guardadas. No puedes elegir un usuario de prueba que inicia sesión en un host fuera del alcance de este análisis. Sin ninguno de los dos, Pitangus te pide confirmar Solo páginas públicas.
- Revisar y lanzar: revisa el tipo, el objetivo, el alcance y el acceso; si quieres, activa Programar (ver Programarlo); copia las IP de salida si tu sitio filtra por IP. Pulsa Iniciar análisis (o Programar análisis).
El análisis queda en cola y su progreso aparece en Análisis (#/analyses). Solo corre un análisis web a la vez por
instalación; uno nuevo espera a que termine el anterior.




Modo API
Sección titulada «Modo API»Una API tiene pocos enlaces que seguir, así que dale a Pitangus su definición: un archivo OpenAPI 3.x o Swagger 2.0 (JSON o YAML, hasta 5 MB), subido con Subir archivo OpenAPI o como URL en un host del alcance.
- Solo se piden sus operaciones GET y HEAD, 2000 como máximo. POST, PUT, PATCH y DELETE se quitan antes de que ZAP vea la definición, así que no se crea, cambia ni borra nada.
- Las peticiones van al host del dominio (los
serversde la definición se reemplazan). - Se rechazan las referencias a otros documentos (
$reffuera del archivo) y los anclajes de YAML: empaqueta la definición antes. - Una URL se descarga una vez desde la dirección comprobada del host, sin redirecciones.
- El análisis guarda solo el SHA-256 de la definición y su número de operaciones.
- La definición añade los endpoints documentados al recorrido; no lo reemplaza. Con usuarios de prueba, se importa como cada uno de los que iniciaron sesión.
Los análisis programados recorren el sitio y no usan la definición de la API.
Qué hace cada herramienta
Sección titulada «Qué hace cada herramienta»Un análisis ejecuta estas herramientas en este orden. Cada una tiene su paso en el análisis, con un estado (Completado, Parcial u Omitido) y el motivo.
| Herramienta | Versión | Qué hace | Límite fijo |
|---|---|---|---|
| katana | 1.7 | Recorre los hosts del alcance con un navegador headless para encontrar URL | Unos 5 minutos |
| robots.txt y sitemaps | Pitangus | Lee el robots.txt y los sitemaps de cada host para sumar URL | 2 minutos para todos los hosts |
| ZAP | 2.17 | Spider, spider AJAX y reglas pasivas sobre cada respuesta | 15 minutos más extras (Límites) |
| nuclei | 3.11 | Plantillas de solo detección en cada host y en las páginas recorridas | 15 minutos |
| testssl.sh | 3.2 | Protocolos TLS, cifrados, certificado y HSTS de los 3 primeros hosts | 5 minutos por host |
| httpx | 1.12 | Identifica las tecnologías con las que responde cada host | 2 minutos |
| httpx + OSV | OSV-Scanner 2.6 | Busca sin conexión las versiones expuestas de paquetes conocidos | 10 minutos |
Cada herramienta corre en un contenedor endurecido que solo llega a los hosts del alcance, en las direcciones comprobadas justo antes del análisis, con 10 peticiones por segundo como máximo.
ZAP: recorrido y reglas pasivas
Sección titulada «ZAP: recorrido y reglas pasivas»ZAP recorre el dominio hasta 2 minutos (un minuto más por cada host adicional) y luego su spider AJAX abre el sitio
en un Firefox headless hasta 2 minutos (5 niveles, 100 estados de página). El spider AJAX solo hace clic en enlaces
(<a>), nunca en botones ni campos de formulario, se queda dentro del alcance y evita los enlaces de cierre de sesión.
Ambos vuelven a correr como cada usuario de prueba que inició sesión.
Después, las reglas pasivas de ZAP leen cada respuesta: cabeceras de seguridad, cookies, fugas de información, datos
personales (PII), librerías JavaScript desactualizadas, cabeceras que revelan versiones, errores de depuración,
comentarios sospechosos y más. Solo se aplican a los hosts del alcance. Estas reglas se fijan explícitamente para que
una actualización de la imagen no las apague: divulgación de PII (10062), mensajes de error de depuración (10023),
información sensible en URL (10024) y en el Referer (10025), comentarios sospechosos (10027), librerías JavaScript
vulnerables (10003), banners en la página (10009), las cabeceras Server, X-Powered-By, X-Backend-Server,
X-AspNet-Version y de depuración que revelan versiones (10036, 10037, 10039, 10061, 10052, 10056), direcciones IP
privadas (2), IDs de sesión en URL (3), divulgación de hashes (10097) y aplicación web moderna (10109). Los conjuntos de
reglas beta y alpha de la imagen no se instalan.
katana y el inventario de URL
Sección titulada «katana y el inventario de URL»katana recorre los hosts del alcance con un navegador headless (3 niveles, 2 minutos, sin formularios). Pitangus suma las URL del robots.txt y los sitemaps de cada host (sin redirecciones, con tamaño limitado; se rechaza el XML que declara un DOCTYPE o entidades), las rutas GET de la definición de la API y lo que alcanza el spider de ZAP. Todo junto forma el inventario de URL del análisis: solo hosts del alcance, sin query strings, hasta 500 URL, con cuántas aportó cada fuente. ZAP pide hasta 200 de ellas antes de su spider, y nuclei también las lee.
nuclei: plantillas de detección
Sección titulada «nuclei: plantillas de detección»nuclei ejecuta las plantillas de solo detección de nuclei-templates 10.4.9 (unas 2400: archivos expuestos, configuraciones incorrectas, versiones, takeovers, TLS) en la raíz de cada host, y las de página en hasta 100 páginas del inventario. Pitangus conserva solo las plantillas que envían GET o HEAD sin cuerpo, sin payloads y sin fuzzing, sin marcas de ataque en sus rutas y sin etiquetas de ataque o de login. Una plantilla de CVE se conserva solo si lee rutas fijas, así que detecta una versión o un archivo expuesto y nunca explota. Corre sin actualizaciones y sin servidor out-of-band.
Pitangus añade sus propias plantillas (ids pitangus-…), que pasan el mismo filtro: un listado de directorio abierto y
credenciales en una respuesta JSON en cada página del inventario, y en cada host una lista fija de 28 rutas sensibles
(carpetas de copias de seguridad y configuración, actuator de Spring Boot, métricas, server-status, phpinfo, archivos de
credenciales, .env, .git/config…), descripciones de API expuestas y archivos de metadatos de desarrollo. Cada una prueba el contenido, no
solo un 200. Un security.txt publicado aparece junto a las tecnologías del dominio.
Una coincidencia en una ruta que el sitio responde igual que una ruta suya al azar (el mismo estado y la misma página:
una página comodín o un «soft 404») no se reporta, sea cual sea la plantilla: no dice nada de esa ruta. Las páginas se
comparan con un simhash de las palabras del texto (no de las etiquetas) de los primeros 8 KB de cada cuerpo, después de
quitar de los dos cuerpos las dos rutas pedidas (tal como se enviaron, decodificadas, escapadas en HTML o sin la barra
inicial), así que una página comodín que repite la ruta que le pidieron (/_debugbar/open no existe) sigue siendo la
misma página. El cuerpo se lee solo para esta comparación y nunca se guarda.
El texto propio de nuclei (descripción, remediación, referencias, CWE y CVE) se muestra tal como se publicó.
testssl.sh: TLS
Sección titulada «testssl.sh: TLS»testssl.sh lee el TLS de los 3 primeros hosts del alcance: protocolos, cifrados, certificado, forward secrecy, HSTS y otras cabeceras. Sus comprobaciones de vulnerabilidades no corren. Solo lo que califica como bajo o peor se convierte en hallazgo. Sus comprobaciones del certificado (cadena de confianza, revocación, caducidad, vigencia, nombre) son un hallazgo por host con cada comprobación como evidencia. testssl.sh no da texto de remediación, así que sus hallazgos dicen solo lo que reportó.
httpx: tecnologías y versiones expuestas
Sección titulada «httpx: tecnologías y versiones expuestas»httpx identifica las tecnologías con las que responde cada host (frameworks, servidores, librerías). Aparecen en Tecnologías, en la página del dominio; la versión de un servidor es una tecnología ahí, no un hallazgo.
Cuando httpx lee una versión (al menos mayor y menor) de un paquete conocido, OSV-Scanner la busca sin conexión en las mismas bases de OSV que usan los análisis de dependencias: Flask, Django, Werkzeug, Tornado, Gunicorn, aiohttp, Express, Next.js, Nuxt, jQuery, jQuery UI, jQuery Migrate, Bootstrap, AngularJS, Lodash, Moment.js, Underscore, Handlebars, DOMPurify, Vue, React y Axios. Para esto no se envía nada al sitio ni a internet.
Cada producto y versión con avisos se convierte en un hallazgo, como «Flask 2.2.3 tiene vulnerabilidades conocidas»
(herramienta httpx + OSV), con cada CVE, la peor severidad, la versión que los corrige todos, KEV y EPSS. Su
confianza es menor: la versión sale de lo que muestra el sitio, y un parche aplicado por backport conserva el número
antiguo, así que confírmala en el servidor. Una librería JavaScript que ZAP ya reportó en esa versión no se repite. Los
servidores web y runtimes (Apache httpd, nginx, OpenSSL, PHP, IIS…) no se buscan, y el paso los lista como no
buscados.
Leer los resultados
Sección titulada «Leer los resultados»Progreso y cobertura parcial
Sección titulada «Progreso y cobertura parcial»El análisis muestra un paso por herramienta, además de la comprobación del inicio de sesión, el inventario de URL y la unión de duplicados.
- Completado: la herramienta hizo su parte.
- Parcial: falló, se pasó del tiempo o no llegó a un host. El análisis sigue; lo que solo esa herramienta había visto no se marca como remediado, y una herramienta que no terminó (detenida, sin tiempo, con un código de error, con la salida cortada) tampoco abre nada: las coincidencias de media ejecución no son hallazgos.
- Omitido: no corrió (falta la imagen, no hay Docker), con el motivo.
Nada se da por limpio si una herramienta no llegó a un host. Si nuclei descarta un host por no responder, katana o httpx no obtienen respuesta, o testssl.sh no logra conectar, el paso nombra el host y dice que no encontrar nada ahí no prueba nada.
Tampoco si el sitio rechazó el análisis. Cuenta cada respuesta de cada herramienta durante toda la ejecución (ZAP, katana, nuclei y httpx): si al menos el 80 % de las respuestas de un host son rechazos (cualquier estado que no sea un 2xx, un 404, un 410 o una redirección: 401, 403, 406, 418, 429, un 5xx, un 400, un código que nadie definió o ninguno), para la ejecución completa o para una sola herramienta (un WAF que despertó solo durante la fase de nuclei), o al menos 1 de cada 20 es un 429 (un límite de peticiones), los pasos nombran el host y el análisis queda Incompleto, así que no marca nada como remediado. Permite las direcciones desde las que salen los análisis (las lista el asistente de nuevo análisis) y vuelve a analizar.


Un hallazgo por problema
Sección titulada «Un hallazgo por problema»Cuando ZAP, nuclei o testssl.sh reportan el mismo problema en la misma URL, Pitangus guarda un solo hallazgo que lista
cada herramienta que lo vio y qué vio cada una (También lo reportaron, en el detalle). Solo cuentan equivalencias
explícitas: cabeceras de seguridad que faltan, atributos de cookies, HSTS, TLS obsoleto y cifrados débiles, problemas
del certificado, un .git o un .env expuestos. Nada se une solo por título o por CWE.
En Hallazgos y en el informe técnico, el mismo problema en varias URL es una fila que se abre en cada URL, por ejemplo «15 hallazgos en 8 problemas». Cada URL conserva su propio triage e historial, y las cifras las cuentan una a una. Dos excepciones evitan que un solo cambio se convierta en decenas de hallazgos:
- Una cabecera de respuesta que comparte todo el sitio (CSP ausente o mal configurada, HSTS, X-Frame-Options,
X-Content-Type-Options, Permissions-Policy, un
ServeroX-Powered-Byque dice su versión, y las cabeceras de seguridad ausentes de nuclei) es un hallazgo por host, en su raíz, en cuantas páginas lo reporten ZAP o nuclei. Lo mismo pasa con la misma evidencia en muchas páginas cuando suele venir de la plantilla compartida o del servidor: un comentario sospechoso, un valor deCache-Control, un veredicto de cacheabilidad (otro comentario u otro valor es otro hallazgo). - Los hallazgos guardados por página antes de esta agrupación se unen al del host en el siguiente análisis, en vez de marcarse como remediados.
- Un nombre de archivo con hash de compilación (
/_astro/index.CSY8UEx1.js,/assets/app-BkL9x2a1.css) conserva su hallazgo entre despliegues: el hash cambia, el hallazgo y su triage se quedan. El detalle sigue mostrando la URL real.
Las redirecciones (3xx) no entran en el inventario de URL: entra la página a la que apuntan. El detalle de cada hallazgo muestra primero la guía de la herramienta y luego la Guía OWASP. Ver hallazgos.md.


Cuándo se marca remediado un hallazgo web
Sección titulada «Cuándo se marca remediado un hallazgo web»El siguiente análisis web marca como remediado lo que ya no aparece, pero solo entre lo que había visto un análisis como él: mismo modo, misma definición de API, mismo uso de cabeceras y de usuarios de prueba, en un host que de verdad revisó, y solo con pruebas de la herramienta que lo reportó, sobre esa página, en esta ejecución: para un hallazgo de ZAP, un 2xx que el propio ZAP obtuvo para la página (su árbol de sitios); para uno de nuclei, las respuestas que nuclei obtuvo para la página (sus respuestas guardadas y su registro de peticiones), todas de la lista de abajo y ninguna una petición sin respuesta; para testssl.sh, un host que terminó.
Solo cuenta un estado que prueba algo sobre la URL, y un hallazgo sobre una ruta (un .env expuesto, una consola, una
copia de seguridad: todo lo que nuclei encontró fuera de la raíz) solo queda remediado con una respuesta que diga que la
ruta ya no está:
| Estado | Qué prueba | Hallazgo sobre una ruta | Hallazgo sobre la raíz | Detección de bloqueo |
|---|---|---|---|---|
| 2xx | la URL sirve algo | no se remedia (la ruta sigue respondiendo) | se remedia si ya no aparece | no cuenta |
| 404, 410 | la URL no sirve nada | se remedia | se remedia | no cuenta |
| 3xx | nada sobre la URL | no se remedia | no se remedia | no cuenta |
| cualquier otro (400, 401, 403, 405, 406, 418, 429, 5xx, 999, ninguno) | nada: es un rechazo | no se remedia | no se remedia | cuenta |
Una redirección no prueba nada en ningún sentido: no es el archivo ni su ausencia. Tampoco cuenta para detectar un bloqueo, porque los sitios mandan HTTP a HTTPS y las rutas desconocidas a su login todo el tiempo. Un 200 no prueba que un archivo ya no esté aunque la plantilla haya dejado de coincidir: el reto JavaScript de un WAF, una página comodín y otro archivo responden 200, y solo un 404 o un 410 los distingue de un archivo que se fue. La respuesta de otra herramienta nunca cuenta: un 404 que vio httpx no prueba que ya no esté lo que nuclei encontró mientras lo limitaban. Un recorrido anónimo no responde por lo que se encontró con sesión iniciada; un recorrido no responde por los endpoints de una definición de API; ningún análisis responde por un host al que no llegó ni por una herramienta que terminó parcial.
Los hallazgos web usan las mismas huellas que una importación del SARIF de ZAP, así que importar tu propio análisis de ZAP del mismo sitio no duplica nada. Solo se guardan el método, el parámetro y una evidencia breve y redactada, nunca la petición ni la respuesta completas. Volver a verificar un hallazgo web lanza un análisis web nuevo (solo quien administra).
Programarlo
Sección titulada «Programarlo»Quien administra puede repetir un análisis pasivo por dominio: desde el paso de revisión (Programar, con También ahora) o desde la página del dominio.
| Ajuste | Opciones |
|---|---|
| Frecuencia | Diaria, Semanal (eliges días de la semana) o Mensual (días 1 a 28) |
| Hora y Zona horaria | Una hora del día en una zona horaria IANA; por defecto, la de tu navegador |
| Acceso | Hasta 3 usuarios de prueba y las cabeceras guardadas |
La página describe la regla con palabras («Cada lunes a las 09:00 (America/Bogota)») y muestra el próximo análisis. Pitangus busca los análisis pendientes cada 5 minutos y analiza un dominio como máximo una vez al día: si ya se analizó ese día local, la programación pasa a su siguiente fecha. Los análisis programados cubren el host del dominio y su alcance guardado, de uno en uno.
Lo que queda fuera cuando corre un análisis programado:
- Un usuario de prueba borrado desde entonces se quita de la programación.
- Un usuario de prueba que ahora inicia sesión fuera del alcance guardado se deja fuera de ese análisis.
- Las cabeceras que ya no están guardadas no se envían.
- La definición de la API no se usa.
- Un dominio cuya prueba caducó se omite con el motivo (En pausa) hasta que se verifique de nuevo.
El análisis y la página del dominio dicen qué quedó fuera.
Sitios que filtran por IP
Sección titulada «Sitios que filtran por IP»Si un firewall o un WAF delante de tu sitio solo deja pasar direcciones conocidas, permite la dirección desde la que analiza Pitangus. El paso de revisión la muestra en Si tu sitio filtra por IP, permite: con un botón Copiar.
- Defínela con
PITANGUS_EGRESS_IPS(direcciones IP o rangos CIDR separados por comas, 16 como máximo; ver configuracion.md). - Sin ella, quien administra puede pulsar Detectar una vez: el servidor le pregunta a
https://api.ipify.orgdesde qué dirección lo ve y guarda la respuesta (ver seguridad.md). Esa es la dirección de la API: si el worker corre en otra máquina, define la variable con la dirección del worker. - Los miembros, cuando no hay dirección, ven una nota para pedírsela a quien administra.
Desconectar un dominio
Sección titulada «Desconectar un dominio»Desconectar dominio, al final del Resumen del dominio, borra su configuración: cabeceras guardadas, usuarios de prueba (con sus contraseñas y claves TOTP), hosts relacionados y alcance guardado, y su análisis programado. Las credenciales borradas no se pueden recuperar.
Lo que se analizó o importó contra él (análisis, hallazgos, triage, tickets) se queda en Análisis y Hallazgos como evidencia, y se vuelve a enlazar si añades el mismo host otra vez.
Límites y tiempos
Sección titulada «Límites y tiempos»| Qué | Límite |
|---|---|
| Análisis web a la vez | 1 por instalación |
| ZAP | 15 minutos, más 1 por host adicional, 3 por el recorrido de cada usuario de prueba, 3 por cada spider AJAX (el anónimo y uno por usuario de prueba) y 2 segundos por URL del inventario que pide; contenedor con 3 GB y 2 CPU. Comprobación del inicio de sesión: unos 2,5 minutos por usuario de prueba, antes del análisis |
| katana / nuclei / testssl.sh / httpx / versiones expuestas | unos 5 / 15 / 5 por host (3 hosts) / 2 / 10 minutos |
| Peticiones por segundo (katana, nuclei, httpx) | 10 |
| Dominios por espacio de trabajo | 20 |
| Hosts en el alcance además del dominio | 20 (100 listados) |
| Cabeceras / usuarios de prueba por dominio | 10 / 10 |
| Usuarios de prueba por análisis | 3 |
| Definición de API | 5 MB, 2000 operaciones GET y HEAD |
| Inventario de URL | 500 URL |
La mayoría de los análisis tardan entre 15 y 25 minutos.
Lo que las reglas de evidencia no pueden distinguir:
- Una página de reto servida con 200 (la comprobación JavaScript o el captcha de un WAF) parece una página más. Nunca remedia un hallazgo sobre una ruta (solo lo hace un 404 o un 410), pero tampoco cuenta como rechazo: un sitio de una sola página también responde lo mismo en cada ruta, y eso no es un bloqueo. Un reto servido en todas las rutas de un host, la raíz incluida, todavía puede pasar por las cabeceras de la raíz en un hallazgo sobre la raíz.
- Un sitio que responde 200 en una ruta que quitó (el armazón de una aplicación de una sola página, una página comodín) deja el hallazgo abierto y Sin verificar: quita la ruta para que responda 404 o 410, o cierra el hallazgo a mano.
Limitaciones conocidas en la 0.14, medidas durante la validación de la versión:
- Una exposición intermitente (un archivo que se sirve solo a ratos) se descarta cuando las propias peticiones de la comprobación no coinciden.
- Un único error de conexión de testssl.sh o de nuclei en un host deja ese host incompleto: es conservador, no remedia nada ahí, pero basta una conexión inestable.
nginx-eol(y otros hallazgos sobre lo que ejecuta el servidor) sale como un hallazgo por página en el análisis web completo, en vez de uno por host.- Los umbrales de bloqueo (80 % de rechazos, 429 en el 5 % de las respuestas de un host) se calibraron con sitios de prueba locales, todavía no con CDN ni WAF reales.
Referencia de la API
Sección titulada «Referencia de la API»Todas las rutas reciben y devuelven JSON. Las lecturas están abiertas a cualquier usuario con sesión; toda escritura requiere a quien administra.
| Ruta | Qué hace |
|---|---|
GET /api/domains |
Lista los dominios con su prueba, programación, último análisis, tecnologías, dast y egress |
POST /api/domains |
Añade un dominio (url, kind, context) |
POST /api/domains/probe |
Sondea una URL antes de añadirla (/api/domains/check es un alias) |
POST /api/domains/verify |
Pide la prueba una vez (method: dns, file o meta) |
GET /api/domains/scope / POST /api/domains/scope |
Lee o guarda el alcance (set, add, remove, exclude_all); 409 sin prueba DNS |
POST /api/domains/discover |
Vuelve a buscar hosts relacionados (202) |
POST /api/domains/headers |
Guarda o quita una cabecera |
POST /api/domains/test-users |
Guarda o quita un usuario de prueba |
POST /api/domains/scans |
Pone en cola un análisis (mode, use_scope o hosts, use_headers, test_users, spec o spec_url); 202 con run_id |
POST /api/domains/schedule |
Define o quita la programación (frequency, weekdays, month_days, time, timezone, test_users, use_headers) |
POST /api/domains/egress |
Detecta una vez la dirección de salida |
POST /api/domains/remove |
Desconecta un dominio (responde runs_kept) |
Errores frecuentes
Sección titulada «Errores frecuentes»| Lo que ves | Por qué | Cómo resolverlo |
|---|---|---|
| No está activado en este servidor, o «El análisis web completo está desactivado» | El análisis web completo está apagado | Un administrador lo activa en Ajustes → Motores de análisis. Si el mensaje nombra PITANGUS_DAST_ENABLED, el servidor lo fija apagado: defínela en 1 para la API y el worker y reinicia (make up). |
| «La imagen de ZAP no está en este servidor: ejecuta make engines» (u otra herramienta) | No se descargó la imagen | Ejecuta make engines. Un paso marcado Omitido dice cuál. |
| «Los análisis web necesitan el runner de Docker» | El worker no tiene socket de Docker | Usa el runner de Docker (contenedores.md). |
| Aún no aparece el registro TXT | Nombre o valor incorrectos, o el DNS no se ha propagado | Compruébalo con dig +short TXT _pitangus.<host>, espera unos minutos y verifica de nuevo. |
| El archivo o la etiqueta «respondió con una redirección» | La prueba se sirve a través de una redirección | Sírvela desde ese host exacto, sin redirección. |
| El dominio resuelve a una dirección privada o reservada | El nombre apunta a una IP interna | Solo se analizan sitios públicos. Usa el nombre público. |
<host> no tiene una prueba DNS vigente |
Los subdominios necesitan una prueba DNS | Verifica con el registro TXT. |
| No pudo iniciar sesión como «nombre» | Credenciales incorrectas, un login que el navegador no logra completar, una página de comprobación que no responde 200 | Lee el motivo, corrige el usuario de prueba (URL de login y de comprobación, clave TOTP) y vuelve a analizar. Mientras tanto, el análisis tiene cobertura parcial. |
| Un paso de herramienta queda Parcial u Omitido | La herramienta falló, se pasó del tiempo, no llegó a un host o falta su imagen | Lee el motivo del paso. Lo que solo ella había visto no se marca como remediado. |
| Los pasos no llegan a los hosts, pocas URL, muchos 403 | Un WAF o un firewall bloquea el análisis | Permite las IP de salida del paso de revisión (Sitios que filtran por IP). |
| «Ya hay un análisis web en cola o en curso» | Solo corre un análisis web a la vez | Espera a que termine. |
Más en solucion-problemas.md.
Próximos pasos
Sección titulada «Próximos pasos»- hallazgos.md: triage, plazos de corrección y el ciclo de vida de lo que encuentra un análisis.
- integraciones.md: importa el SARIF de tus propios análisis con ZAP, nuclei o Strix contra un dominio verificado.
- seguridad.md: qué sale de tu servidor y cómo se aíslan los contenedores de análisis.
- solucion-problemas.md: cuando algo no funciona.
- glosario.md: los términos de esta página.