
Observatorio de inteligencia de amenazas que agrega fuentes de CISA KEV, ThreatFox, URLhaus y MalwareBazaar con búsqueda, seguimiento de cambios y exportación STIX/CSV/JSONL.
Un sistema de observación de amenazas centrado en la evidencia que mantiene semánticamente separados el estado actual de la fuente, los eventos de cambio material y la telemetría operativa de obtención. Los datos faltantes, obsoletos, deshabilitados o no disponibles permanecen visiblemente ausentes. La interfaz nunca sustituye registros de demostración ni atribución inferida.
La versión actual refuerza las fechas de evidencia y el estado de reconocimiento local del dispositivo, hace que todos los fallos de lectura importantes sean visiblemente distintos de los estados exitosos de cero resultados, estabiliza las solicitudes de correlación y fortalece el panel de evidencia, los filtros de investigación acotados, la interpretación de fuentes, los controles móviles y la contabilidad de exportación. Cada marca de reproducción animada sigue correspondiendo a un evento NEW, UPDATED o REMOVED retenido; no es tráfico de red decorativo.

Pulse — relaciones entre fuentes, salud de las fuentes y análisis del estado actual.

Replay — reconstrucción acotada a la página de las transiciones NEW, UPDATED y REMOVED retenidas.
Otras superficies en vivo incluyen la geografía aproximada de infraestructura de IP pública y las vistas de evidencia de primera parte de URLhaus / MalwareBazaar. Esas superficies no están representadas intencionalmente mediante capturas de pantalla de marcador de posición o duplicadas en este README.
Las capturas de producción son capturas de pantalla que preservan la fuente, tomadas del Observatorio v1.2.0 en vivo. Están recortadas y redimensionadas/comprimidas para su presentación; la evidencia mostrada, las marcas de tiempo, los recuentos, los valores de IOC y los estados de la interfaz no se regeneran ni se sustituyen.
El Worker de producción está respaldado por Cloudflare D1. Las credenciales de los feeds permanecen como secretos de Cloudflare Worker solo de servidor y nunca se requieren en el navegador.
1.2.022.13.0 o posteriorEste despliegue se ejecuta en modo demand-driven. El repositorio ahora apunta directamente a Cloudflare Workers estándar; los disparadores programados no están habilitados intencionalmente en v1.2.0, por lo que la aplicación no afirma recolección continua. Un programador futuro puede llamar a la misma operación runIngestionCycle() después de una verificación separada de corrección y operativa.
El navegador realiza una solicitud de mantenimiento acotada explícita en el primer uso y cada cinco minutos mientras está abierto:
POST /api/ingest
↓
runIngestionCycle()
↓
configuration → TTL → backoff → D1 lease → fetch → normalize → validate
↓
snapshot cache + current observations + material events + cycle statistics
Las lecturas ordinarias son separadas y locales:
GET /api/observations → D1 current state, scoped before pagination
GET /api/search → D1 current state, scoped before pagination
GET /api/kev → D1 current CISA catalog
GET /api/events → D1 material change ledger
GET /api/geo → local observations + bounded cached IP enrichment
Ninguna de esas rutas GET llama a un adaptador de fuente. Si este proyecto obtiene más adelante un programador genuinamente compatible, puede llamar a la misma operación runIngestionCycle() sin crear una segunda implementación de actualización.
La cobertura se muestra por fuente. Las API acotadas nunca se presentan como catálogos completos.
El enlace DB posee conjuntos de datos distintos:
threat_source_cache y threat_source_cache_chunks: la instantánea validada más reciente por fuente, almacenada en fragmentos con clave por generación.observations: el estado actual normalizado más reciente por identidad de fuente estable. Conserva la primera ingesta, la última aparición en la fuente, el último cambio material, el hash actual, el recuento de revisiones y el último resultado de ingesta.observation_events: eventos de evidencia significativos NEW, UPDATED y REMOVED defendibles. Los payloads normalizados anterior y actual, los hashes y los diffs deterministas de campos hacen que los estados previos sean reconstruibles.source_fetch_log: telemetría acotada de intentos de obtención, sin cuerpos de respuesta ni credenciales.source_ingest_cycles: recuentos acotados por actualización de registros obtenidos, válidos, rechazados, nuevos, actualizados, sin cambios y eliminados.source_refresh_lease: arrendamientos cortos respaldados por D1 por fuente que evitan que isolates simultáneos dupliquen las actualizaciones upstream.Las definiciones de esquema en tiempo de ejecución se encuentran en db/schema.ts. La inicialización agrega las nuevas columnas de estado actual a una tabla de observaciones existente antes de crear los índices dependientes.
Estas preguntas son intencionalmente diferentes:
observations y la instantánea de fuente validada responden a esto./api/observations?window=... filtra las observaciones actuales por el observedAt upstream.observation_events y /api/revisions responden a esto.El estado actual no se describe incorrectamente como una tabla de historial de siete días. El libro mayor de eventos materiales se retiene durante siete días. La telemetría de obtención y de ciclos se retiene durante dos días y está limitada a 200 filas por fuente. Las observaciones actuales que no son de catálogo y que no han reaparecido durante siete días se eliminan. CISA permanece actual porque cada respuesta correcta es un catálogo completo; las filas eliminadas de ese catálogo permanecen disponibles durante 30 días antes de su eliminación. Solo la ausencia en CISA puede crear actualmente un evento REMOVED porque su adaptador recupera un catálogo actual completo. La ausencia en los resultados acotados de ThreatFox, URLhaus o MalwareBazaar no se trata como eliminación.
Una aparición sin cambios actualiza los valores actuales lastObservedInSnapshotAt/lastIngestedAt, pero no crea un evento ni incrementa revisionCount. lastChangedAt sobrevive a apariciones posteriores sin cambios.
La vista Exploited separa:
dateAdded de CISA con granularidad diaria cae dentro de un rango explícito TODAY, 7D o 30D. Las ventanas del Observatorio inferiores a un día nunca se presentan como precisión de CISA.El catálogo actual admite búsqueda del lado del servidor y filtros por proveedor, producto, añadidos recientemente, asociación con ransomware y fecha de adición, así como paginación opaca por cursor. Muestra CVE, proveedor, producto, nombre de la vulnerabilidad, fecha de adición, fecha límite, asociación con ransomware y acción requerida. No inventa puntuaciones CVSS.
Los hashes de contenido cubren los campos de evidencia normalizados, no la contabilidad del Observatorio. Un hash cambiado produce un evento UPDATED con el payload normalizado anterior, el payload normalizado nuevo, los hashes anterior/nuevo y un diff determinista sobre:
El panel de procedencia consulta /api/revisions?id=... y expone el hash actual, el último cambio material, el recuento de revisiones, los eventos retenidos y los diffs a nivel de campo. Las marcas de tiempo volátiles de ingesta no aparecen en los diffs de contenido.
El panel también expone un rastro de evidencia versionado para cada registro aceptado: campos normalizados aceptados, campos opcionales que permanecieron ausentes, transformaciones solo de visualización, la base de clasificación y la base de identidad estable. Este rastro describe solo la evidencia retenida. Los valores upstream rechazados no se retienen y nunca se les asignan identidades sintéticas del Observatorio. Los rechazos se representan por separado como recuentos agregados por ciclo con códigos de campo y motivo acotados; los ciclos antiguos recopilados antes de ese esquema se etiquetan como carentes de desglose en lugar de reconstruirse.
Eventos recientes muestra solo cambios materiales. No emite cientos de filas SEEN sin cambios después de una actualización completa de CISA. Esas apariciones se resumen en las estadísticas de ciclo de la fuente.
La vista Briefing predeterminada compara el libro mayor de eventos materiales retenido con un cursor de reconocimiento versionado almacenado solo en el navegador actual. El primer uso y el almacenamiento borrado se etiquetan como una línea base inicial en lugar de actividad nueva. Si un cursor guardado es anterior al libro mayor retenido, la interfaz indica que no se puede probar un delta completo.
El reconocimiento nunca muta ni elimina eventos del servidor. El cursor se puede exportar e importar como JSON para una transferencia deliberada entre dispositivos; no se presenta como un estado sincronizado con una cuenta y el identificador de dispositivo generado nunca se envía al servidor.
Los totales de Briefing describen la página del libro mayor devuelta actualmente y están etiquetados como acotados a lo mostrado/página. No se presentan como totales del libro mayor completo retenido.
Las marcas de tiempo de reconocimiento importadas se validan estrictamente y se canonizan a UTC ISO-8601 antes de almacenarse o compararse. El almacenamiento del navegador se trata como opcional: el almacenamiento local bloqueado o con fallos produce un error en línea compacto y nunca hace fallar Briefing.
El banco de trabajo Export formatea la página visible validada ya cargada como CSV, JSONL, STIX 2.1, texto desarmado o un manifiesto de evidencia que contiene la política aplicada y los hashes de registro disponibles. La búsqueda local activa y el ámbito de fuentes se trasladan a Export. Una lista de permitidos de fuentes vacía exporta cero registros. STIX representa los CVE de CISA como objetos Vulnerability y los hashes de archivo validados —incluidos los valores SHA-256 de MalwareBazaar— como objetos Indicator. Los recuentos de seleccionados, emitidos y no admitidos son distintos; los registros no admitidos se revelan en los metadatos del paquete en lugar de descartarse silenciosamente. Export no realiza recolección upstream. La confianza ausente permanece ausente, los desacuerdos entre fuentes permanecen como registros separados y los eventos eliminados del libro mayor nunca entran silenciosamente en las exportaciones del estado actual. Estos artefactos son transportes de evidencia, no recomendaciones de bloqueo de cortafuegos.
Las fuentes caducadas usan demoras de reintento acotadas de 1, 2, 5, 15 y 30 minutos. Un Retry-After válido mayor se respeta hasta una hora. Durante el retroceso, una instantánea válida anterior se sirve como obsoleta; una fuente vacía que ha fallado permanece fuera de línea.
Antes de obtener datos, una fuente elegible adquiere un arrendamiento condicional corto de D1. Otro isolate no puede reemplazar a un titular no caducado, por lo que solo se realiza una actualización. Si D1 no está disponible, el sistema informa explícitamente del modo degradado solo de instantánea y de un arrendamiento de memoria de isolate; esa alternativa no se describe como distribuida.
Las observaciones actuales, los espacios de trabajo específicos de fuentes, la búsqueda local, el catálogo de CISA, los eventos materiales y las revisiones de registros usan consultas de cursor acotadas del lado del servidor. Las restricciones de fuente y tipo se aplican antes del ordenamiento y la paginación. Los cursores codifican la tupla de ordenación estable, se validan por longitud/caracteres/esquema y fallan de forma segura con HTTP 400 cuando están malformados. El navegador nunca recibe el conjunto de datos completo de siete días solo para paginar localmente.
El limitador de la API es un contador de ventana fija en memoria con ámbito de isolate de Worker. Se informa con precisión como protección de mejor esfuerzo local al isolate, no como un límite de velocidad de Cloudflare autoritativo a nivel global. Las lecturas ordinarias están limitadas a 120 solicitudes por minuto por IP de cliente informada; la ingesta tiene un depósito separado de seis solicitudes por minuto y la geografía tiene un depósito separado de doce solicitudes por minuto. No se añaden escrituras de D1 a cada lectura solo para exagerar este control.
POST /api/ingest — ciclo de mantenimiento explícito impulsado por demanda; respeta TTL, retroceso y arrendamientos de D1.GET /api/observations?window=24h&scope=urlhaus&limit=100&cursor=... — ventana paginada local del estado actual; los ámbitos validados son all, urlhaus, malwarebazaar e infrastructure.GET /api/search?q=indicator&window=24h&scope=urlhaus&limit=100&cursor=... — búsqueda local acotada y paginada; cero llamadas upstream.GET /api/kev?limit=50&q=...&vendor=...&product=...&ransomware=known&addedSince=YYYY-MM-DD&cursor=... — catálogo CISA actual completo.GET /api/events?limit=50&cursor=... — libro mayor de eventos materiales.GET /api/revisions?id=...&limit=50&cursor=... — registro actual más revisiones retenidas.GET /api/correlations?id=... — pares exactos de indicadores del estado actual a nivel de conjunto de datos.El desarrollo local de Cloudflare lee las credenciales solo de servidor desde .dev.vars. Copia .dev.vars.example a .dev.vars y completa solo los feeds que estás autorizado a usar:
THREATFOX_AUTH_KEY=
URLHAUS_AUTH_KEY=
MALWAREBAZAAR_AUTH_KEY=
Las credenciales de producción deben almacenarse como secretos de Cloudflare Worker, nunca como código fuente confirmado ni variables de GitHub expuestas al cliente. La aplicación accede a ellas solo a través de la superficie de enlaces del runtime de Workers. Nunca deben aparecer en NEXT_PUBLIC_*, componentes de cliente, HTML, registros, fixtures ni archivos confirmados.
El repositorio apunta directamente a Cloudflare Workers estándar. wrangler.jsonc es la fuente de verdad de la configuración del Worker y declara un enlace D1 preliminar llamado DB. Wrangler 4 aprovisiona automáticamente ese recurso D1 en el primer despliegue autenticado y mantiene el enlace vinculado en despliegues posteriores. No se confirma ningún identificador D1 específico de cuenta.
Comandos de desarrollo y producción:
npm ci
npm run dev
npm run build
npm run preview
# authenticated Cloudflare session / CI only
npm run deploy
La verificación de GitHub Actions se ejecuta en cada pull request y push a main. El despliegue de producción es deliberadamente manual a través del flujo de trabajo deploy production y requiere secretos de repositorio llamados CLOUDFLARE_API_TOKEN y CLOUDFLARE_ACCOUNT_ID. Esto impide que una rama no revisada o una configuración de credenciales incompleta se publique automáticamente.
npm ci
npm audit --omit=dev --audit-level=high
npm audit --audit-level=high
npm test
npm run lint
npm test es el punto de entrada de pruebas compatible: realiza una compilación de producción completa antes de la suite determinista para que el aislamiento de secretos de cliente a nivel de artefacto pueda inspeccionar dist/client. Ejecutar node --test directamente contra un checkout limpio omite intencionalmente ese artefacto de compilación requerido. Las pruebas cubren el análisis estricto de marcas de tiempo de calendario y de reconocimiento, el almacenamiento opcional del dispositivo, las dependencias estables de correlación, la evidencia normalizada, el hash canónico de etiquetas, la creación de eventos materiales, la re-ingesta sin cambios, la preservación de payloads anteriores, la durabilidad del último cambio, los diffs de campos, la retención de eventos y las lagunas del libro mayor, los rastros de evidencia, la política de exportación con fuente vacía, la integridad de representación/recuento de STIX, la elegibilidad de TTL/retroceso, los arrendamientos de actualización, el cableado de ámbito-antes-de-paginación del lado del servidor, las consultas dedicadas de GEO/Recent-KEV, la validación de cursores, el aislamiento de la ruta de lectura, la cobertura de fuentes, la política de referencias externas, la precisión de la limitación de velocidad, el aislamiento de fallos de fuentes y el aislamiento de secretos de cliente.
El modo GEO grafica solo observaciones válidas de IPv4/IPv6 públicas. Una consulta D1 dedicada selecciona los registros de IP elegibles en la ventana de estado actual solicitada en lugar de reutilizar la página genérica de observaciones. La respuesta informa los totales de registros candidatos y si se alcanzó su límite de seguridad de 2000 registros. Los llamadores no pueden proporcionar destinos upstream arbitrarios ni listas de IP. GeoJS es el proveedor principal fijo y FreeIPAPI es la alternativa fija; las URL upstream arbitrarias son imposibles. La aplicación limita el trabajo externo mediante un tope de solicitudes de 12 direcciones, una caché de éxito D1 de 30 días, una caché de reintento de cinco minutos y un limitador de ruta dedicado. Cada punto graficado conserva la procedencia real de su proveedor y puede abrir su registro local subyacente.
Publicado bajo la Licencia MIT. Consulta LICENSE.
Seleccionar el modo GEO hace que el servidor envíe cada candidato de IP pública validado, junto con metadatos ordinarios de solicitud HTTPS, a GeoJS y luego a FreeIPAPI cuando se requiere la alternativa. Por lo tanto, esos proveedores pueden observar qué direcciones públicas se consultan. Las direcciones privadas, reservadas, de documentación y proporcionadas por el cliente nunca se envían; el modo de relaciones no realiza solicitudes de geolocalización.
El espacio de trabajo Replay reconstruye la página actual de transiciones del libro mayor material en el orden de tiempo de detección del Observatorio. El movimiento NEW, UPDATED y REMOVED se impulsa exclusivamente por eventos almacenados. Está explícitamente acotado a la página y no afirma reconstruir una instantánea histórica completa ni el volumen de tráfico de red.
El paquete world-atlas, derivado de Natural Earth, proporciona el mapa base local. El mapa agrupa las IP colocalizadas, admite detalles al pasar el cursor y clic para ir a la procedencia, e informa recuentos de geolocalizadas, excluidas, no disponibles y pendientes. Los rangos privados, reservados, de documentación, multicast y demás no públicos se excluyen antes de cualquier llamada al proveedor.
La geolocalización de IP se presenta explícitamente como ubicación aproximada de infraestructura. No es una ubicación de actor, origen de evento, nacionalidad, hallazgo de propiedad ni afirmación de atribución. El enriquecimiento fallido permanece ausente; la aplicación nunca genera coordenadas sustitutas.
La visualización predeterminada sigue siendo un campo interactivo dirigido por fuerzas de observaciones individuales vinculadas a su fuente y a la familia de malware explícitamente proporcionada. El canvas admite arrastre de nodos, desplazamiento del campo, zoom, tráfico de enlaces animado e inspección directa de procedencia. GEO es una superficie de evidencia separada con su propia semántica de procedencia y de fallos.
| Fuente | Credencial | TTL | Cobertura real |
|---|
| CISA KEV | Ninguna | 30 minutos | Catálogo actual validado completo |
| ThreatFox | THREATFOX_AUTH_KEY | 15 minutos | Ventana de IOC de 24 horas solicitada |
| URLhaus | URLHAUS_AUTH_KEY | 15 minutos | Los 500 registros más recientes devueltos por el endpoint recent |
| MalwareBazaar | MALWAREBAZAAR_AUTH_KEY | 15 minutos | Los 100 registros de metadatos más recientes devueltos por el endpoint |
ingestion_runtime: la salud más reciente del ciclo general de ingesta.geo_ip_cache: resultados validados de geolocalización aproximada de IP y entradas acotadas de caché negativa. Los resultados correctos caducan después de 30 días; las búsquedas fallidas se reintentan después de cinco minutos. Las filas D1 caducadas se eliminan de forma oportunista durante las solicitudes GEO, y la alternativa de isolate está limitada a 2000 entradas.GET /api/geo?window=24h — deriva candidatos solo de observaciones locales válidas de IP pública, recupera como máximo 12 resultados de proveedor no almacenados en caché por solicitud y devuelve puntos WGS84 aproximados en caché con procedencia.GET /api/status — semántica de fuente, estado actual, frescura, modo de ingesta, ciclo, arrendamiento y limitación de velocidad.