
Framework di inganno basato su LLM: "La honeypot che risponde!™"

Introducing honeyprompt, un framework di deception basato su LLM realizzato da/per sviluppatori web. Il progetto personale di passione di @alectrocute.
Supporta tutti i principali provider LLM cloud e locali. SSH, HTTP, TLS, TCP, telnet e altro. Viene fornito come un piccolo container (e un singolo binario statico) e tiene ogni manopola in un unico honeyprompt.yaml.
Nessun plugin da compilare, nessun database da eseguire, facilmente estendibile e può essere distribuito su hardware di fascia bassa.
Un'istanza demo è disponibile all'indirizzo 172.233.151.216, con il pannello web non autenticato qui:
http://172.233.151.216:9090. È un'istanza pubblica di honeyprompt in esecuzione su un economico VPS Linode, con openrouter/free come unico provider/modello LLM.
Per la configurazione più semplice nel 2026, consigliamo Docker e OpenRouter/openrouter/free come provider LLM. Tutti i principali provider LLM cloud e locali sono supportati. Tre file e un unico comando avviano l'intera distribuzione predefinita: sette esche basate su LLM, archiviazione persistente degli eventi e il pannello operatore.
1. Scarica il file di configurazione predefinito, il file compose e il modello env:
# 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
(Oppure clona il repository e cd al suo interno — gli stessi tre file.)
2. Compila .env. Sono richiesti due valori:
OPENROUTER_API_KEY=sk-or-... # use a dedicated key with a spend limit
HONEYPROMPT_PANEL_PASSWORD=changeme # basic-auth password for the panel
3. Avvialo:
docker compose up -d
4. Provalo:
ssh -p 2222 root@localhost # password: root — then type anything
curl http://localhost:2375/v1.54/containers/json # "exposed" Docker API
5. Guardalo accadere nel pannello di sola lettura all'indirizzo http://127.0.0.1:9090 (accedi come admin con la password del pannello). Ogni connessione, credenziale e comando viene trasmesso in tempo reale. Se sei distribuito su un host remoto, dovrai esporre la porta :9090 in compose.yaml. Questo non è consigliato per distribuzioni in produzione.
Fissa una release numerata invece di
latestper le distribuzioni in produzione — impostaHONEYPROMPT_IMAGEin.env.
Il honeyprompt.yaml che hai appena scaricato è una vetrina completamente annotata. Include profili per:
/ serve immediatamente la pagina di benvenuto standard di nginx, e i percorsi più profondi passano al LLM per pagine intranet complete in HTML/CSS, moduli di login e pannelli di amministrazione progettati per tenere l'attaccante a cliccare.[!IMPORTANT] Anche se stai usando LLM, determina i percorsi più frequentemente utilizzati e aggiungi regole statiche per essi. Questo ti farà risparmiare enormi quantità di token LLM e accelererà le risposte a richieste che non valgono il costo di una chiamata LLM. Esempi casuali:
whoami, health check, favicon, sonde di versione, ecc.
Questo honeyprompt.yaml minimo simula un box SSH con due regole statiche e nessun 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
Per una distribuzione persistente, usa il compose.yaml incluso. La guida alla distribuzione copre le release su Docker Hub, i segreti GitHub richiesti, la configurazione di porte e firewall, l'accesso al pannello via SSH, aggiornamenti, rollback, archiviazione degli eventi e isolamento.
Un honeypot deve fare bene solo una cosa: rimanere convincente abbastanza a lungo da far continuare a digitare l'attaccante. Ogni comando che esegue è intelligence — gli strumenti che cerca, le credenziali che riutilizza, le CVE che presume tu non abbia patchato. Gli honeypot statici perdono il loro personaggio nel momento in cui qualcuno esegue un comando che l'autore non aveva previsto. honeyprompt affida quel momento a un LLM, così la shell risponde a dmesg | tail o cat /etc/shadow come farebbe una vera, e la sessione continua.
Guarda l'eccellente presentazione DEF CON 32 di Adel Karimi su Galah, (il primo?) honeypot LLM, che ha ispirato questo progetto: https://www.youtube.com/watch?v=XGsm4Qcc_Ag
Questa è la parte che vale la pena capire subito, perché i due sono deliberatamente tenuti separati:
Li configuri separatamente:
# 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 è un oggetto JSON autonomo per riga — pronto per tail -f, inviare a un SIEM o riprodurre con jq. I comandi Docker sopra montano il volume denominato honeyprompt-data su /data, quindi gli eventi sopravvivono alla sostituzione del container. Entrambi i file vengono aggiunti e scaricati a un arresto pulito.
format influisce solo sul modo in cui i log operativi vengono visualizzati nella console; il file di log operativo, quando abilitato, è sempre JSON strutturato per essere facilmente analizzabile.

Un dashboard opzionale di sola lettura trasmette in streaming gli eventi di deception mentre accadono, li suddivide per protocollo ed esporta tutto in JSON con un clic:
panel:
enabled: true
address: "0.0.0.0:8080"
auth: # optional basic auth
username: admin
password: "${HONEYPROMPT_PANEL_PASSWORD}"
Il dashboard è semplice HTML, CSS e JavaScript (src/panel/assets) incorporato nel binario. Lascia auth non definito per disabilitare l'autenticazione.
Ogni provider è un proprio modulo con i propri timeout, tentativi, limiti di frequenza e intestazioni. Le chiavi provengono dall'ambiente. Pronti all'uso:
Configura i provider, scegli una pool.strategy (round-robin, weighted, random o failover), e honeyprompt distribuisce il traffico tra di loro. Se il provider scelto scade o restituisce un errore recuperabile, honeyprompt passa trasparentemente al successivo — un backend morto non porta mai l'honeypot offline. Gli errori non recuperabili (una chiave API errata, ad esempio) fermano la cascata in modo che tu lo scopra invece di consumare silenziosamente la quota.
I servizi usano il pool globale a meno che non nominino il proprio sottoinsieme di provider:
llm:
enabled: true
providers: [local-ollama] # one name: force this service to this provider
Elenca più nomi per mantenere il bilanciamento del carico e il failover, ma solo all'interno di quel sottoinsieme:
llm:
enabled: true
providers: [openai-primary, openrouter-backup]
Quando più servizi dovrebbero condividere lo stesso gruppo di provider — o un sottoinsieme ha bisogno della propria strategia invece di quella globale — definisci un pool nominato. Un pool ha un nome, una strategia e un elenco ordinato di provider, e un servizio lo riferisce per nome ovunque nominerebbe un provider:
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]
Un nome di pool deve essere l'unica voce in providers — mescolare un pool con provider individuali in una lista non è consentito, poiché sarebbe ambiguo quale strategia vince. I nomi dei pool vivono nello stesso namespace dei nomi dei provider e non possono collidere con essi.
Quando "confronta una regex" o "chiedi al modello" non sono sufficienti, gli hook ti permettono di inserire il tuo TypeScript nel percorso della richiesta e della risposta. Un hook può riscrivere il prompt prima che raggiunga il modello, o riscrivere la risposta prima che raggiunga l'attaccante.
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;
},
});
Riferiscilo per nome dalla lista hooks: di qualsiasi servizio. Un hook integrato redact-secrets viene fornito abilitato nella configurazione di esempio in modo che il modello non possa mai restituire una credenziale reale.
Le metriche Prometheus sono servite su /metrics nel pannello (non autenticato, quindi gli scraper funzionano senza problemi):
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
Vuoi contribuire o vuoi un binario nativo? Avrai bisogno di Deno 2.x — l'unica dipendenza.
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 integra il runtime, gli asset del pannello e tutto in un unico eseguibile senza dipendenze. I binari precompilati per Linux, macOS e Windows sono allegati a ogni release taggata.
CI esegue formattazione, lint, type-check, test, validazione della configurazione, una compile cross-platform e una build Docker a ogni push. Taggare vX.Y.Z produce i binari di release e pubblica l'immagine multi-arch attestata con provenienza e SBOM su 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 predefinito a ./honeyprompt.yaml, o $HONEYPROMPT_CONFIG se impostato (il container lo imposta a /etc/honeyprompt/honeyprompt.yaml).
Questo è uno strumento per attirare e studiare gli attaccanti su infrastrutture di tua proprietà o che sei autorizzato a testare. Esporre servizi esca significa comunque esporre servizi; eseguilo su host isolati, mantienilo aggiornato e non puntarlo verso nulla che non puoi permetterti di vedere sondato. La deception non sostituisce la messa in sicurezza effettiva del sistema reale.
Se vuoi contribuire a questo progetto e usare un agente AI o fare molto affidamento su codice generativo, va benissimo—ma DOVRAI essere personalmente interrogato su ogni singola riga di codice che offri e se non dimostri una comprensione immediata e priva di AI, il tuo INTERO contributo verrà rifiutato e scartato.
MIT.
| Provider | type | Notes |
|---|
| Ollama | ollama | Modelli locali; predefinito localhost:11434 |
| llama.cpp | llamacpp | Endpoint OpenAI server locale |
| OpenAI | openai | OPENAI_API_KEY |
| Azure OpenAI | azure | richiede azure.deployment + azure.apiVersion |
| OpenRouter | openrouter | OPENROUTER_API_KEY |
| Anthropic | anthropic | ANTHROPIC_API_KEY |
| Google Gemini | google | GEMINI_API_KEY |
| Anything OpenAI-shaped | openai-compatible | punta baseUrl al tuo gateway |