Investigación académicaPythonTesis en coautoría · USB Bogotá · 2026

Detector de phishing por homógrafos IDN

Un dominio que cambia letras por caracteres Unicode casi idénticos no se distingue del original a simple vista, así que quien recibe el correo no tiene cómo notarlo.

Qué hace: Analiza una URL o un correo cuando la persona lo pide y responde si es phishing, con las razones y qué hacer. El equipo de seguridad ve cada incidente y cómo votó cada señal.

Resumen

Proyecto de grado de Ingeniería de Sistemas en la Universidad de San Buenaventura, en coautoría con Juan Sebastián Fandiño Novoa.

Un dominio homógrafo cambia letras por caracteres Unicode casi idénticos, como una «а» cirílica en lugar de una «a» latina. El sistema combina cinco señales en un puntaje de riesgo y explica cada veredicto. Se usa desde una extensión de navegador y un complemento de Outlook, que analizan el correo abierto solo cuando la persona pulsa Analizar, y desde un dashboard para los administradores de seguridad de la universidad.

La necesidad

A simple vista, un dominio homógrafo no se distingue del original. Un filtro que solo diga «peligroso» tampoco ayuda a decidir: la persona necesita la razón y el paso siguiente. Y el equipo de seguridad de la universidad necesita ver qué llegó y por qué se marcó.

Restricciones

  • Los servicios externos de reputación pueden fallar o no tener llaves, y sin ellos el sistema no puede empezar a marcar todo como phishing.
  • Son correos de personas: la Ley 1581 de 2012 limita qué se guarda, y los datos personales no pueden salir hacia el LLM.
  • La extensión no lee la bandeja en segundo plano: solo analiza el mensaje que la persona abre y pide analizar.
  • Los datasets públicos revisados no traían homógrafos IDN reales.
  • El sistema recomienda; no bloquea correos ni los pone en cuarentena. La respuesta al incidente la da una persona.

La solución

Una API que recibe una URL, un correo o un archivo .eml y devuelve un veredicto con su puntaje de riesgo, las razones y los pasos a seguir. La usan una extensión para Chrome, Edge y Firefox, un complemento de Outlook y un dashboard donde los administradores ven los incidentes, el puntaje de cada agente y los permisos de cada usuario.

Cómo funciona

services/orchestrator.py reúne cinco señales y agents/fusion_agent.py calcula el riesgo final. Se despliega con Docker Compose en Coolify: backend, PostgreSQL, Redis, ChromaDB y Ollama para los embeddings.

Flujo de datos
  1. Entrada: una URL, un correo o un archivo .eml (/api/v1/analyze, /analyze_email, /analyze_eml)
  2. Agente IDN: normaliza a NFC y Punycode, busca confundibles del catálogo Unicode TR#39 y mide la similitud con los dominios más visitados usando un BK-tree
  3. Threat intelligence: VirusTotal, URLScan.io, Google Safe Browsing y WhoisXML en paralelo, con caché de una hora en Redis
  4. Agente LLM: analiza el contenido por un gateway compatible con OpenAI, quita los datos personales antes de enviar y agrega como contexto casos parecidos recuperados de ChromaDB (RAG)
  5. Clasificador de URL (modelo ONNX de Hugging Face) y sondeo de la página con un cliente protegido contra SSRF, más SPF y DKIM del correo
  6. Fusión: PHISHING si el riesgo llega a θ = 0,30; el incidente y sus razones se guardan en PostgreSQL

Decisiones técnicas

  • El umbral θ = 0,30 queda por encima del piso de degradación (0,25): si los servicios externos fallan y sus señales caen al valor neutral, el sistema no marca todo como phishing. Un umbral más bajo daba más recall en la evaluación, pero dejaba abierta esa falla (docs/EVAL-T4-T7.md, core/constants.py).
  • El backend dejó de depender de un modelo local (Ollama y LlamaStack) y llama a un proveedor remoto por un gateway compatible con OpenAI, con reintentos y un modelo de respaldo (core/llm_gateway.py).
  • La IP de origen, el Message-ID y los encabezados se cifran con AES-256-GCM, y el cuerpo del correo no se guarda por defecto (STORE_EMAIL_CONTENT=false, Ley 1581 de 2012).

Retos de ingeniería

  • Una revisión integral del 25 de septiembre de 2026 encontró 17 problemas: sesiones, caché de threat intelligence, réplicas de ChromaDB y PostgreSQL, y la metodología de evaluación. Cada corrección quedó con su prueba de regresión (docs/correcciones-revision-integral-2026-09-26.md).
  • Rotación de tokens de refresco atómica en Redis: con cinco renovaciones simultáneas del mismo token, solo una se acepta.

Cómo se valida

  • pytest con marcadores unit, integration, system, regression, smoke, sanity y acceptance; verify.sh exige 90 % de cobertura.
  • Las pruebas de integración levantan PostgreSQL y ChromaDB efímeros en lugar de usar mocks.
  • Suite adversaria para los agentes y el RAG (tests/security/): inyección de prompts, fuga de información, envenenamiento del RAG y salidas maliciosas, según las categorías LLM01, LLM02, LLM04 y LLM05 del OWASP Top 10 para aplicaciones con LLM.
  • Última corrida documentada en el repositorio (26 de septiembre de 2026): 972 pruebas aprobadas y 28 omitidas, con 92,6 % de cobertura.

Límites y próximos pasos

  • La comparación contra un clasificador monolítico se está repitiendo: la revisión encontró URLs duplicadas y casos compartidos entre calibración y evaluación, así que no publico esas métricas hasta tener la corrida nueva.
  • Los datasets públicos revisados no traían homógrafos IDN reales; el corpus de homógrafos de la evaluación es sintético.
  • Sin llaves de API, las señales de threat intelligence quedan en cero.

Mi parte

Proyecto de grado hecho entre Juan Sebastián Fandiño Novoa y yo. Entre los dos construimos el backend que describe esta página, la extensión de navegador con el complemento de Outlook, el dashboard de administración y la infraestructura local y de laboratorio con Docker Compose y Kubernetes.

¿Te interesa este tipo de trabajo?

Busco trabajo remoto como Full Stack Engineer. Si quieres hablar de este proyecto o de tu equipo, escríbeme.

Otros proyectos