Dashboard¶
The dashboard is the honeypot's live intelligence console: headline counters, a real-time event stream, and a world map of geolocated attackers. It shares the admin's authentication and, in the demo project, lives behind the same obscured prefix — /hd-<ADMIN_URL_SUFFIX>/dashboard/.
KPI cards¶
The headline strip across the top shows:
- Total events — every captured hit, across all decoy types.
- Unique attackers — the number of attacker profiles (one per IP).
- Top decoys — the five most-hit decoy types with their hit counts, a quick read on what attackers are hunting for (a spike in
envhits means secret scanners;wpAdminmeans WordPress brute-forcers).
The strip refreshes itself every 10 seconds via an HTMX poll — no page reload, and the numbers are computed server-side in one place so the full page and the poll can never disagree.
Live event table¶
The event table is WebSocket-powered. On page load it's seeded with the 50 most recent enriched events; from then on, every event that finishes enrichment is pushed to the browser over a Channels WebSocket and prepended to the table in real time — no polling, no refresh.
Each row is a deliberately compact projection (never the full event — bodies and headers stay server-side): IP, method and path, decoy type, country, current threat score, and tags. The tags mix two vocabularies worth reading differently:
- Technique tags (
sql_injection,path_traversal,credential_access, …) — what the request tried to do. - Tool tags (
sqlmap,nikto,curl, …) — what software sent it, inferred from JA3 fingerprints and User-Agents.
If several dashboards are open, they all receive every event — the WebSocket consumer broadcasts to a shared group.
Attack map¶
The map is a Leaflet world map plotting the 500 most recently active attacker profiles that have coordinates. How to read it:
- Each marker is an attacker (an IP), not an event. Clicking one shows the profile summary: IP, country/city, threat score, event count, tags, and last-seen time.
- A pulsing marker is a live hit — when an enriched event carries coordinates, the map drops a pulse at that location in real time over the same WebSocket as the table.
- The base layer refreshes every 30 seconds from a GeoJSON endpoint that is cached server-side for exactly that long, so any number of open dashboards share one database query per cycle.
Empty map?
Coordinates come from MaxMind's free GeoLite2-City database, which you download yourself and point GEOIP_PATH at (see the Quickstart). Without it, events are captured and enriched normally but nothing can be plotted. Profiles that GeoIP can't locate are simply left off the map.
Attacker profile cards¶
Behind every IP on the map or in the table is an Attacker profile — the per-IP dossier the enrichment pipeline builds up event by event, browsable in the admin:
- Identity — IP, ASN/organisation, country, city, coordinates.
- Timeline — first seen, last seen, total event count.
- Threat score (0–100) — cumulative and never decremented: +10 per new attack-technique tag, +20 per threat feed flagging the IP, +30 the first time a known-scanner JA3 fingerprint is seen.
- Tags — the merged technique + tool vocabulary from all of this IP's events.
- Known scanner — set when the client's TLS fingerprint matches a published scanner (sqlmap riding python-requests, nikto, metasploit, …), which survives even a forged User-Agent.
- Events — every hit from this IP, linked from the profile.
A useful triage habit: sort profiles by threat score for who is dangerous, and by last seen for who is here right now.
Exporting¶
The dashboard's export view produces bulk extracts for downstream tooling — CSV (events, filtered by timestamp), JSON (attacker profiles, filtered by last-seen), or a STIX 2.1 bundle (profiles as threat-intel objects for a TIP/SIEM). Ranges are capped at 90 days per request. For quick, small extracts, the HoneyEvent and AttackerProfile admin changelists also have per-selection export actions.