
Marco de engaño basado en LLM: "La trampa que responde!™"

Presentamos honeyprompt, un framework de decepción basado en LLM creado por/para desarrolladores web. El proyecto personal de @alectrocute.
Compatible con todos los principales proveedores de LLM en la nube y locales. SSH, HTTP, TLS, TCP, telnet y más. Se distribuye como un contenedor pequeño (y un único binario estático) y mantiene todos los controles en un solo archivo honeyprompt.yaml.
Sin plugins que compilar, sin base de datos que ejecutar, fácilmente extensible y puede implementarse en hardware de gama baja.
Hay una instancia de demostración disponible en 172.233.151.216, con el panel web sin autenticación aquí: http://172.233.151.216:9090. Es una instancia pública de honeyprompt ejecutándose en un VPS barato de Linode, con openrouter/free como único proveedor/modelo de LLM.
Para la configuración más sencilla en 2026, recomendamos Docker y OpenRouter/openrouter/free como proveedor de LLM. Todos los principales proveedores de LLM en la nube y locales son compatibles. Tres archivos y un comando levantan la implementación predeterminada completa: siete señuelos basados en LLM, almacenamiento de eventos duradero y el panel del operador.
1. Obtén la configuración predeterminada, el archivo compose y la plantilla de entorno:
# if you don't have Docker:
# curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh
mkdir honeypot && cd honeypot
wget https://raw.githubusercontent.com/alectrocute/honeyprompt/main/honeyprompt.yaml
wget https://raw.githubusercontent.com/alectrocute/honeyprompt/main/compose.yaml
wget -O .env https://raw.githubusercontent.com/alectrocute/honeyprompt/main/.env.example
(O clona el repositorio y haz cd en él — los mismos tres archivos.)
2. Rellena .env. Se requieren dos valores:
OPENROUTER_API_KEY=sk-or-... # use a dedicated key with a spend limit
HONEYPROMPT_PANEL_PASSWORD=changeme # basic-auth password for the panel
3. Inícialo:
docker compose up -d
4. Pruébalo:
ssh -p 2222 root@localhost # password: root — then type anything
curl http://localhost:2375/v1.54/containers/json # "exposed" Docker API
5. Observa lo que sucede en el panel de solo lectura en http://127.0.0.1:9090 (inicia sesión como admin con la contraseña de tu panel). Cada conexión, credencial y comando se transmite en vivo. Si estás implementado en un host remoto, necesitarás exponer el puerto :9090 en compose.yaml. Esto no se recomienda para implementaciones en producción.
Fija una versión numerada en lugar de
latestpara implementaciones en producción — estableceHONEYPROMPT_IMAGEen.env.
El archivo honeyprompt.yaml que acabas de descargar es una muestra completamente anotada. Incluye perfiles para:
/ sirve la página de bienvenida estándar de nginx al instante, y las rutas más profundas pasan al LLM para páginas completas de intranet HTML/CSS, formularios de inicio de sesión y paneles de administración diseñados para mantener al atacante haciendo clic.[!IMPORTANT] Incluso si estás usando LLMs, determina las rutas más utilizadas y agrega reglas estáticas para ellas. Esto te ahorrará grandes cantidades de tokens de LLM y acelerará las respuestas a solicitudes que no valen el costo de una llamada LLM. Ejemplos aleatorios:
whoami, health checks, favicon, sondeos de versión, etc.
Este honeyprompt.yaml mínimo simula una caja SSH con dos reglas estáticas y sin LLM:
panel:
enabled: true
address: "0.0.0.0:8080"
events:
buffer: 2000
file: /data/events.jsonl # durable attacker activity
services:
- protocol: ssh
address: "0.0.0.0:2222"
description: "Ubuntu 26.04 LTS build runner"
serverName: "gpu-runner-07"
passwordRegex: "^(root|admin|123456)$" # which passwords "work"
commands:
- regex: "^whoami$"
handler: "root"
- regex: "^(.+)$"
handler: "bash: command not found"
docker run --rm \
-p 2222:2222 -p 8080:8080 \
-v "$(pwd)/honeyprompt.yaml:/etc/honeyprompt/honeyprompt.yaml:ro" \
-v honeyprompt-data:/data \
alectrocute/honeyprompt:latest
Para un despliegue persistente, usa el compose.yaml incluido. La guía de despliegue cubre las versiones de Docker Hub, los secretos de GitHub necesarios, la configuración de puertos y cortafuegos, el acceso al panel a través de SSH, las actualizaciones, la reversión, el almacenamiento de eventos y el aislamiento.
Un honeypot solo tiene que hacer bien una cosa: mantenerse convincente el tiempo suficiente para que el atacante siga escribiendo. Cada comando que ejecutan es inteligencia: las herramientas que buscan, las credenciales que reutilizan, los CVE que asumen que no has parcheado. Los honeypots estáticos rompen el personaje en el momento en que alguien ejecuta un comando que el autor no anticipó. honeyprompt entrega ese momento a un LLM, para que el shell responda a dmesg | tail o cat /etc/shadow como lo haría uno real, y la sesión continúe.
Consulta la excelente presentación de Adel Karimi en DEF CON 32 sobre Galah, (¿el primer?) honeypot LLM, que inspiró este proyecto: https://www.youtube.com/watch?v=XGsm4Qcc_Ag
Esta es la parte que vale la pena entender desde el principio, porque los dos se mantienen deliberadamente separados:
Los configuras por separado:
# The honey: attacker activity.
events:
buffer: 2000 # recent events kept in memory for the panel
file: /data/events.jsonl # persist every event as JSON Lines
# The runtime's own diagnostics.
logging:
level: info # debug | info | warn | error
format: text # how it looks on the console: text (human) or json
file: /data/honeyprompt.log # optional; on disk it's always JSON
events.jsonl es un objeto JSON autocontenido por línea, listo para tail -f, enviar a un SIEM o reproducir con jq. Los comandos de Docker anteriores montan el volumen nombrado honeyprompt-data en /data, por lo que los eventos sobreviven al reemplazo del contenedor. Ambos archivos se añaden y se vacían en un apagado limpio.
format solo afecta cómo se muestran los registros operativos en la consola; el archivo de registro operativo, cuando está habilitado, siempre es JSON estructurado para facilitar su análisis.

Un panel de control opcional de solo lectura transmite eventos de decepción a medida que ocurren, los desglosa por protocolo y exporta todo a JSON con un solo clic:
panel:
enabled: true
address: "0.0.0.0:8080"
auth: # optional basic auth
username: admin
password: "${HONEYPROMPT_PANEL_PASSWORD}"
El panel es HTML, CSS y JavaScript plano (src/panel/assets) incrustado en el binario. Deja auth sin definir para deshabilitar la autenticación.
Cada proveedor es su propio módulo con sus propios tiempos de espera, reintentos, límites de velocidad y cabeceras. Las claves provienen del entorno. De serie:
Configura proveedores, elige una pool.strategy (round-robin, weighted, random o failover), y honeyprompt distribuye el tráfico entre ellos. Si el proveedor elegido agota el tiempo de espera o devuelve un error reintentable, honeyprompt falla transparentemente al siguiente: un backend muerto nunca desconecta el honeypot. Los errores no reintentables (una clave API incorrecta, por ejemplo) detienen la cascada para que te enteres en lugar de consumir silenciosamente la cuota.
Los servicios usan el pool global a menos que nombren su propio subconjunto de proveedores:
llm:
enabled: true
providers: [local-ollama] # one name: force this service to this provider
Enumera varios nombres para mantener el balanceo de carga y la conmutación por error, pero solo dentro de ese subconjunto:
llm:
enabled: true
providers: [openai-primary, openrouter-backup]
Cuando varios servicios deben compartir el mismo grupo de proveedores, o un subconjunto necesita su propia estrategia en lugar de la global, define un pool con nombre. Un pool tiene un nombre, una estrategia y una lista ordenada de proveedores, y un servicio lo referencia por nombre en cualquier lugar donde nombraría un proveedor:
pools:
- name: cheap-first
strategy: failover # try the local model first, fall back to the paid API
order: [local-ollama, openrouter]
- name: spread
strategy: round-robin
order: [openrouter, openai]
services:
- protocol: ssh
# ...
llm:
enabled: true
providers: [cheap-first] # a pool name, in place of a provider
- protocol: http
# ...
llm:
enabled: true
providers: [spread]
El nombre de un pool debe ser la única entrada en providers; no se permite mezclar un pool con proveedores individuales en una misma lista, ya que sería ambiguo qué estrategia prevalece. Los nombres de los pools viven en el mismo espacio de nombres que los nombres de los proveedores y no pueden colisionar con ellos.
Cuando 'coincidir con una expresión regular' o 'preguntar al modelo' no es suficiente, los hooks te permiten insertar tu propio TypeScript en la ruta de solicitud y respuesta. Un hook puede reescribir el prompt antes de que llegue al modelo, o reescribir la respuesta antes de que llegue al atacante.
import { registerHook } from "./src/engine/hooks.ts";
registerHook({
name: "fake-latency-notice",
transformResponse(response, ctx) {
if (ctx.protocol === "ssh" && /rm -rf/.test(ctx.input)) {
return "rm: cannot remove '/': Operation not permitted\n";
}
return response;
},
});
Referéncialo por nombre desde la lista hooks: de cualquier servicio. Un hook incorporado redact-secrets se envía habilitado en la configuración de ejemplo para que el modelo nunca pueda repetir una credencial real.
Las métricas de Prometheus se sirven en /metrics en el panel (sin autenticación, por lo que los raspadores funcionan sin problemas):
honeyprompt_events_total{protocol="ssh"} 412
honeyprompt_llm_requests_total{provider="openai",protocol="ssh"} 118
honeyprompt_auth_attempts_total{protocol="ssh"} 87
honeyprompt_engine_errors_total{protocol="http"} 0
¿Contribuyes o quieres un binario nativo? Necesitarás Deno 2.x, la única dependencia.
deno task check # type-check
deno task lint
deno task fmt
deno task test # unit + integration tests
deno task start -- --config honeyprompt.yaml # run locally
deno task dev -- --config honeyprompt.yaml # run with file watching
deno task compile # -> ./dist/honeyprompt (self-contained binary)
deno compile empaqueta el runtime, los activos del panel y todo en un solo ejecutable sin dependencias. Los binarios precompilados para Linux, macOS y Windows se adjuntan a cada versión etiquetada.
El CI ejecuta formato, lint, verificación de tipos, pruebas, validación de configuración, una compile multiplataforma y una compilación Docker en cada push. Etiquetar vX.Y.Z genera binarios de versión y publica la imagen multi-arquitectura con procedencia y SBOM atestiguados en alectrocute/honeyprompt.
honeyprompt run [--config <path>] start every configured service (default)
honeyprompt validate [--config <path>] parse and validate config, then exit — great for CI
honeyprompt version
honeyprompt help
--config por defecto es ./honeyprompt.yaml, o $HONEYPROMPT_CONFIG si está configurado (el contenedor lo establece en /etc/honeyprompt/honeyprompt.yaml).
Esta es una herramienta para atraer y estudiar atacantes en infraestructura que posees o estás autorizado a probar. Exponer servicios señuelo aún significa exponer servicios; ejecútalo en hosts aislados, mantenlo parcheado y no lo apuntes a nada que no puedas permitirte que sea sondeado. La decepción no es un sustituto para asegurar realmente lo real.
Si quieres contribuir a este proyecto y usas un agente de IA o te apoyas fuertemente en código generativo, está totalmente bien, pero serás examinado personalmente en cada línea de código que ofrezcas y si no demuestras una comprensión inmediata y libre de IA, tu CONTRIBUCIÓN COMPLETA será rechazada y descartada.
MIT.
| Proveedor | type | Notas |
|---|
| Ollama | ollama | Modelos locales; por defecto en localhost:11434 |
| llama.cpp | llamacpp | Punto final server de OpenAI local |
| OpenAI | openai | OPENAI_API_KEY |
| Azure OpenAI | azure | necesita azure.deployment + azure.apiVersion |
| OpenRouter | openrouter | OPENROUTER_API_KEY |
| Anthropic | anthropic | ANTHROPIC_API_KEY |
| Google Gemini | google | GEMINI_API_KEY |
| Cualquier cosa con forma de OpenAI | openai-compatible | apunta baseUrl a tu puerta de enlace |