{"slug": "honeyprompt-llm-first-honeypot-that-talks-back", "title": "Honeyprompt: LLM-first honeypot that talks back", "summary": "A new open-source deception framework called Honeyprompt uses large language models to power interactive honeypots that engage attackers with realistic responses. Developed by web developers, it supports SSH, HTTP, TLS, TCP, and Telnet, and can be deployed as a small container or single binary on low-end hardware. The tool aims to improve threat detection by making decoys more convincing and reducing the need for manual configuration.", "body_md": "\"The honeypot that talks back!™\"\n\nIntroducing `honeyprompt`\n\n, an LLM-first deception framework made by/for web developers.\n\nSupports all major cloud and local LLM providers. SSH, HTTP, TLS, TCP, Telnet and more. It ships as\na small container (and a single static binary) and keeps every knob in one `honeyprompt.yaml`\n\n.\n\nNo plugins to compile, no database to run, easily extendable and can be deployed on low-end hardware.\n\nA demo instance is available at `172.233.151.216`\n\n, with the unauthenticated web panel here:\n[http://172.233.151.216:9090](http://172.233.151.216:9090). It is a public instance of honeyprompt running on a cheap Linode VPS,\nwith `openrouter/free`\n\nas the sole LLM provider/model.\n\nFor easiest setup in 2026, we recommend Docker and OpenRouter/`openrouter/free`\n\nas the LLM provider.\nAll major cloud and local LLM providers are supported. Three files and one command stand up the full\ndefault deployment: seven LLM-backed decoys, durable event storage and the operator panel.\n\n**1. Grab the default config, compose file, and env template:**\n\n```\n# if you don't have Docker:\n# curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh\n\nmkdir honeypot && cd honeypot\nwget https://raw.githubusercontent.com/alectrocute/honeyprompt/main/honeyprompt.yaml\nwget https://raw.githubusercontent.com/alectrocute/honeyprompt/main/compose.yaml\nwget -O .env https://raw.githubusercontent.com/alectrocute/honeyprompt/main/.env.example\n```\n\n(Or clone the repo and `cd`\n\ninto it — same three files.)\n\n**2. Fill in .env.** Two values are required:\n\n```\nOPENROUTER_API_KEY=sk-or-...            # use a dedicated key with a spend limit\nHONEYPROMPT_PANEL_PASSWORD=changeme     # basic-auth password for the panel\n```\n\n**3. Start it:**\n\n```\ndocker compose up -d\n```\n\n**4. Poke it:**\n\n```\ncurl http://localhost/                # default nginx welcome page (no LLM)\nssh -p 2222 root@localhost            # password: root — then type anything\ncurl http://localhost:2375/v1.54/containers/json   # \"exposed\" Docker API\n```\n\n**5. Watch it happen** in the read-only panel at [http://127.0.0.1:9090](http://127.0.0.1:9090) (sign in as `admin`\n\nwith\nyour panel password). Every connection, credential, and command streams in live. If you are deployed\nto a remote host, you'll need to expose the `:9090`\n\nport in [ compose.yaml](/alectrocute/honeyprompt/blob/main/compose.yaml). This\nis not recommended for production deployments.\n\nPin a numbered release instead of\n\n`latest`\n\nfor production deployments — set`HONEYPROMPT_IMAGE`\n\nin`.env`\n\n.\n\nThe [ honeyprompt.yaml](/alectrocute/honeyprompt/blob/main/honeyprompt.yaml) you just downloaded is a fully annotated showcase. It\nships profiles for:\n\n**A generic corporate web server**— port 80, the widest net;`/`\n\nserves the stock nginx welcome page instantly, and deeper paths fall through to the LLM for full HTML/CSS intranet pages, login forms, and admin panels built to keep the attacker clicking.**MCP / agent gateways**— Streamable HTTP discovery, OAuth metadata, JSON-RPC tool calls, and tempting production tools.** Docker Engine API 29.5**— the unauthenticated port 2375 surface used by real cloud worms.** Kubernetes API v1.36**— namespace, workload, Secret, ConfigMap, and RBAC discovery.** Ubuntu 26.04 AI build infrastructure**— SSH, GPU workloads, Docker, kubeconfigs, CI state, and provider credentials.** Redis 8.8**— common RESP probes used for credential theft, persistence, and lateral movement.** Industrial edge / OT**— an intentionally legacy Telnet management plane, because modern defense still has to catch attacks against old infrastructure.\n\nThe versions are contemporary, but the personas intentionally look useful and slightly exposed. A good decoy should attract interaction, not advertise perfect hardening.\n\nImportant\n\nEven if you're using LLMs, determine the most frequently used paths and add static rules for them.\nThis will save you massive amounts of LLM tokens and speed up responses to requests that are not\nworth the cost of an LLM call. Random examples: `whoami`\n\n, health checks, favicon, version probes,\netc.\n\nThis minimal `honeyprompt.yaml`\n\nfakes an SSH box with two static rules and no LLM:\n\n```\npanel:\n  enabled: true\n  address: \"0.0.0.0:8080\"\n\nevents:\n  buffer: 2000\n  file: /data/events.jsonl # durable attacker activity\n\nservices:\n  - protocol: ssh\n    address: \"0.0.0.0:2222\"\n    description: \"Ubuntu 26.04 LTS build runner\"\n    serverName: \"gpu-runner-07\"\n    passwordRegex: \"^(root|admin|123456)$\" # which passwords \"work\"\n    commands:\n      - regex: \"^whoami$\"\n        handler: \"root\"\n      - regex: \"^(.+)$\"\n        handler: \"bash: command not found\"\ndocker run --rm \\\n  -p 2222:2222 -p 8080:8080 \\\n  -v \"$(pwd)/honeyprompt.yaml:/etc/honeyprompt/honeyprompt.yaml:ro\" \\\n  -v honeyprompt-data:/data \\\n  alectrocute/honeyprompt:latest\n```\n\nFor a persistent deployment, use the included [ compose.yaml](/alectrocute/honeyprompt/blob/main/compose.yaml). The\n\n[deployment guide](/alectrocute/honeyprompt/blob/main/DEPLOYMENT.md)covers Docker Hub releases, required GitHub secrets, port and firewall setup, panel access over SSH, upgrades, rollback, event storage, and isolation.\n\nA honeypot only has to do one thing well: stay convincing long enough that the attacker keeps\ntyping. Every command they run is intelligence — the tools they reach for, the credentials they\nreuse, the CVEs they assume you haven't patched. Static honeypots break character the moment someone\nruns a command the author didn't anticipate. honeyprompt hands that moment to an LLM, so the shell\nanswers `dmesg | tail`\n\nor `cat /etc/shadow`\n\nthe way a real one would, and the session keeps going.\n\nThis is the part worth understanding up front, because the two are deliberately kept apart:\n\n- Deception events: Every attacker interaction: connections, auth attempts, each command or request, the response honeyprompt sent back, which provider and model answered, and how long it took. This is your threat intel. It's held in a bounded in-memory buffer for the live panel and you can persist all of it to disk.\n- Operational logs: Startup, which ports it bound, provider failures, shutdown, internal errors.\nThis is what you read when the\n*runtime*misbehaves. It has nothing to do with attacker activity.\n\nYou configure them separately:\n\n```\n# The honey: attacker activity.\nevents:\n  buffer: 2000 # recent events kept in memory for the panel\n  file: /data/events.jsonl # persist every event as JSON Lines\n\n# The runtime's own diagnostics.\nlogging:\n  level: info # debug | info | warn | error\n  format: text # how it looks on the console: text (human) or json\n  file: /data/honeyprompt.log # optional; on disk it's always JSON\n```\n\n`events.jsonl`\n\nis one self-contained JSON object per line — ready to `tail -f`\n\n, ship to a SIEM, or\nreplay with `jq`\n\n. The Docker commands above mount the named volume `honeyprompt-data`\n\nat `/data`\n\n, so\nevents survive container replacement. Both files are appended to and flushed on a clean shutdown.\n\n`format`\n\nonly affects how operational logs are rendered to the console; the operational log *file*,\nwhen enabled, is always structured JSON so it's easy to parse.\n\nAn optional, read-only dashboard streams deception events as they happen, breaks them down by protocol, and exports everything to JSON with one click:\n\n```\npanel:\n  enabled: true\n  address: \"0.0.0.0:8080\"\n  auth: # optional basic auth\n    username: admin\n    password: \"${HONEYPROMPT_PANEL_PASSWORD}\"\n```\n\nThe dashboard is plain HTML, CSS, and JavaScript ([ src/panel/assets](/alectrocute/honeyprompt/blob/main/src/panel/assets)) embedded\ninto the binary. Leave\n\n`auth`\n\nundefined to disable authentication.Each provider is its own module with its own timeouts, retries, rate limits, and headers. Keys come from the environment. Out of the box:\n\n| Provider | `type` |\nNotes |\n|---|---|---|\n| Ollama | `ollama` |\nLocal models; defaults to `localhost:11434` |\n| llama.cpp | `llamacpp` |\nLocal `server` OpenAI endpoint |\n| OpenAI | `openai` |\n`OPENAI_API_KEY` |\n| Azure OpenAI | `azure` |\nneeds `azure.deployment` + `azure.apiVersion` |\n| OpenRouter | `openrouter` |\n`OPENROUTER_API_KEY` |\n| Anthropic | `anthropic` |\n`ANTHROPIC_API_KEY` |\n| Google Gemini | `google` |\n`GEMINI_API_KEY` |\n| Anything OpenAI-shaped | `openai-compatible` |\npoint `baseUrl` at your gateway |\n\nConfigure providers, pick a `pool.strategy`\n\n(`round-robin`\n\n, `weighted`\n\n, `random`\n\n, or `failover`\n\n),\nand honeyprompt spreads traffic across them. If the chosen provider times out or returns a retryable\nerror, honeyprompt transparently falls over to the next one — a dead backend never takes the\nhoneypot offline. Non-retryable errors (a bad API key, say) stop the cascade so you find out instead\nof silently draining quota.\n\nServices use the global pool unless they name their own provider subset:\n\n```\nllm:\n  enabled: true\n  providers: [local-ollama] # one name: force this service to this provider\n```\n\nList several names to keep load balancing and failover, but only within that subset:\n\n```\nllm:\n  enabled: true\n  providers: [openai-primary, openrouter-backup]\n```\n\nWhen several services should share the same provider group — or a subset needs its own strategy\ninstead of the global one — define a **named pool**. A pool has a name, a strategy, and an ordered\nprovider list, and a service references it by name anywhere it would name a provider:\n\n```\npools:\n  - name: cheap-first\n    strategy: failover # try the local model first, fall back to the paid API\n    order: [local-ollama, openrouter]\n  - name: spread\n    strategy: round-robin\n    order: [openrouter, openai]\n\nservices:\n  - protocol: ssh\n    # ...\n    llm:\n      enabled: true\n      providers: [cheap-first] # a pool name, in place of a provider\n  - protocol: http\n    # ...\n    llm:\n      enabled: true\n      providers: [spread]\n```\n\nA pool name must be the only entry in `providers`\n\n— mixing a pool with individual providers in one\nlist isn't allowed, since it would be ambiguous which strategy wins. Pool names live in the same\nnamespace as provider names and can't collide with them.\n\nWhen \"match a regex\" or \"ask the model\" isn't enough, hooks let you splice your own TypeScript into the request and response path. A hook can rewrite the prompt before it reaches the model, or rewrite the reply before it reaches the attacker.\n\n``` js\nimport { registerHook } from \"./src/engine/hooks.ts\";\n\nregisterHook({\n  name: \"fake-latency-notice\",\n  transformResponse(response, ctx) {\n    if (ctx.protocol === \"ssh\" && /rm -rf/.test(ctx.input)) {\n      return \"rm: cannot remove '/': Operation not permitted\\n\";\n    }\n    return response;\n  },\n});\n```\n\nReference it by name from any service's `hooks:`\n\nlist. A built-in `redact-secrets`\n\nhook ships\nenabled in the example config so the model can never echo a real credential back out.\n\nPrometheus metrics are served at `/metrics`\n\non the panel (unauthenticated, so scrapers just work):\n\n```\nhoneyprompt_events_total{protocol=\"ssh\"}                          412\nhoneyprompt_llm_requests_total{provider=\"openai\",protocol=\"ssh\"}  118\nhoneyprompt_auth_attempts_total{protocol=\"ssh\"}                    87\nhoneyprompt_engine_errors_total{protocol=\"http\"}                   0\n```\n\nContributing or want a native binary? You'll need [Deno](https://deno.com) 2.x — the only\ndependency.\n\n```\ndeno task check    # type-check\ndeno task lint\ndeno task fmt\ndeno task test     # unit + integration tests\n\ndeno task start -- --config honeyprompt.yaml    # run locally\ndeno task dev   -- --config honeyprompt.yaml    # run with file watching\ndeno task compile                                # -> ./dist/honeyprompt (self-contained binary)\n```\n\n`deno compile`\n\nbakes the runtime, panel assets, and all into one executable with no dependencies.\nPrebuilt binaries for Linux, macOS, and Windows are attached to every tagged\n[release](/alectrocute/honeyprompt/releases).\n\nCI runs formatting, lint, type-check, tests, config validation, a cross-platform `compile`\n\n, and a\nDocker build on every push. Tagging `vX.Y.Z`\n\ncuts release binaries and publishes the provenance- and\nSBOM-attested multi-arch image to\n[ alectrocute/honeyprompt](https://hub.docker.com/r/alectrocute/honeyprompt).\n\n```\nhoneyprompt run [--config <path>]        start every configured service (default)\nhoneyprompt validate [--config <path>]   parse and validate config, then exit — great for CI\nhoneyprompt version\nhoneyprompt help\n```\n\n`--config`\n\ndefaults to `./honeyprompt.yaml`\n\n, or `$HONEYPROMPT_CONFIG`\n\nif set (the container sets it\nto `/etc/honeyprompt/honeyprompt.yaml`\n\n).\n\nThis is a tool for luring and studying attackers on infrastructure **you own or are authorized to\ntest**. Exposing decoy services still means exposing services; run it on isolated hosts, keep it\npatched, and don't point it at anything you can't afford to have probed. Deception is not a\nsubstitute for actually securing the real thing.\n\nIf you want to contribute to this project and use an AI agent or heavily lean on generative code,\nthat's totally fine—but you *WILL* be personally quizzed on every single line of code you offer and\nif you don't demonstrate immediate, AI-free understanding, your *ENTIRE* contribution will be\nrejected and scrapped.\n\n[MIT](/alectrocute/honeyprompt/blob/main/LICENSE).", "url": "https://wpnews.pro/news/honeyprompt-llm-first-honeypot-that-talks-back", "canonical_source": "https://github.com/alectrocute/honeyprompt", "published_at": "2026-07-12 16:31:47+00:00", "updated_at": "2026-07-12 17:05:53.866587+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "ai-infrastructure", "ai-safety"], "entities": ["Honeyprompt", "OpenRouter", "Docker", "Linode", "Kubernetes", "Redis", "Ubuntu"], "alternates": {"html": "https://wpnews.pro/news/honeyprompt-llm-first-honeypot-that-talks-back", "markdown": "https://wpnews.pro/news/honeyprompt-llm-first-honeypot-that-talks-back.md", "text": "https://wpnews.pro/news/honeyprompt-llm-first-honeypot-that-talks-back.txt", "jsonld": "https://wpnews.pro/news/honeyprompt-llm-first-honeypot-that-talks-back.jsonld"}}