Inspiration

A honeypot only works if attackers believe in it. Most are clones of a real site: they serve what was copied, answer everything else with a 404, and their login forms go nowhere. Scanners notice quickly. And even a good capture leaves a defender with a pile of logs and no rules. My MSc research is on making web-application honeypots more deceptive, so I wanted to test a simple idea: what if a model improvises the parts a clone cannot copy and then helps with the defense afterwards?

What it does

Mirage is a web honeypot that stays consistent while it improvises, plus an analyst agent.

  • A fictional company with a planned attack surface. Nemotron 3 Ultra designs a persona once: company, server stack, staff, database schema, navigation menu, record URL patterns, and a few tempting lure pages (an admin login, a config file, and a backup index). Every response is generated in that style and cached, so a repeat visit shows the same page.
  • Improvisation where a clone fails. Pages that cannot be pre-built, such as the detail page for shipment PRO-48213, a failed login, or a section index, are written on request by Nemotron 3 Nano. Paths that do not belong to the site get the company's own instant 404, with no model call.
  • An analyst agent. Nemotron Ultra labels each recorded session (intent, MITRE ATT&CK technique, severity), the Tavily web search adds CVE leads, and the agent proposes detection rules.
  • Rules that are verified, not just proposed. Each rule is replayed against every logged request and a benign baseline. A rule that blocks legitimate traffic goes back to the model with the exact requests it got wrong and is rejected if it cannot be fixed. Verified rules come out as nginx, ModSecurity, and Sigma, produced by templates rather than by the model.
  • A read-only dashboard of sessions, findings, and rules. All attacker-controlled text is escaped, and the pages contain no JavaScript.

How I built it

Python, FastAPI, and SQLite. Two Nemotron tiers on the Nebius Token Factory, through its OpenAI-compatible API: Nemotron 3 Nano 30B-A3B serves live requests where latency matters, and Nemotron 3 Ultra 550B-A55B does the reasoning offline (persona design, classification, rule proposal, and revision). That split keeps the live path fast while the expensive thinking happens in the background. Tavily is called at runtime by the analyst, for the Apache version the honeypot advertises, and for the probes it observed.

Around the models: a persona-driven site surface, a response cache for consistency, coalescing of simultaneous requests, per-session call budgets, timeouts with a persona-styled fallback, and prompts that fence off attacker text. The nginx, ModSecurity, and Sigma renderers were tested against a real nginx and Apache with ModSecurity.

Challenges

  • My first comparison showed no advantage. Against a static clone, Mirage reached the same 16 pages. Reading the data, I found why: the generated site had no shared navigation and almost no links to deeper pages, and even the lure pages had been generated as 404s. The fix was to give the site a planned surface (persona, menu, record URL patterns, lures) and to refuse to cache a 403 or 404 for a page that must exist.
  • A small model treats instructions as optional. I asked for table rows to link to detail pages and mostly did not get links. Instead of a stronger prompt, I added a deterministic linker that turns record IDs into links, tested on its own.
  • Model-written rules can be too broad. Ultra's first sensitive-file rule matched every .zip path. It passed my first baseline only because the baseline had no zip downloads. Once I added legitimate ones, the replay forced a revision that narrowed it. Another rule ("rapid sequential ID enumeration") caught 78 attack requests but also blocked one legitimate request, and it was rejected after three revisions.
  • Honest measurement. My scripted attackers repeat the same run, so totals count the same pages three times. I report per-run figures and say so.

Accomplishments

Four scripted attacker profiles, run against the same starting site as a static baseline and as Mirage:

  • Distinct pages that returned content, per run: 18 for the static baseline, 48 for Mirage.
  • Attack payloads answered with something other than a 404, over three runs: 0 of 30 for the baseline, 24 of 30 for Mirage.
  • Login attempts answered: 0% against 100%.
  • On Token Factory, 59 live generations had a median of 3.8 s (p90 4.6 s) and no failures across 267 requests per mode.
  • The analyst turned 12 recorded sessions into 4 verified rules and rejected a fifth, with 0 false positives on a 319-request replay. Tavily supplied 36 distinct CVE mentions as leads to check.

These come from scripted attackers of one fictional company. The runs repeat the same traffic, so they confirm repeatability rather than add independent samples, and the crawler hit its request cap, so page counts are lower bounds.

What I learned

Constrain the generation with structure (a persona, a surface, a cache), and check what a model proposes mechanically instead of trusting it. A model asked to write security rules will happily write rules that break normal traffic. Replaying them against logs is what makes the output usable. The caveats matter as much as the numbers: the attackers are scripted, the baseline is simplified, and recall is measured on the traffic the rules came from.

What's next

Real internet traffic on a small Nebius VM and a held-out set of attacks to see how well the rules generalize. Rate-based rules for brute-forcing, which a per-request rule cannot express. Hiding generation latency by pre-generating likely pages. Tests against honeypot-fingerprinting tools and more than one persona.

Built with substantial help from an AI coding assistant (Claude); I directed the design and ran every experiment, and the numbers above come from my runs.

Built With

  • fastapi
  • modsecurity
  • nebius-token-factory
  • nemotron-3-nano
  • nemotron-3-ultra
  • nginx
  • nvidia-nemotron
  • pytest
  • python
  • sigma
  • sqlite
  • tavily
Share this project:

Updates

Submission history