Skip to content

Latest commit

Β 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

README.md

 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—
β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•
β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•
β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—  β•šβ–ˆβ–ˆβ•”β•
β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘
 β•šβ•β•β•β•β•β•β•šβ•β•  β•šβ•β•β•šβ•β•  β•šβ•β•β•β•β•šβ•β•  β•šβ•β•β•šβ•β•  β•šβ•β•   β•šβ•β•

Cybersecurity Projects Go React PostgreSQL Redis License: AGPLv3 Docker MITRE Engage

Live Demo

Self-hosted honeytoken generator. Mints seven kinds of tripwire artifacts β€” invisible web bugs, booby-trapped PDF/DOCX files, fake .env and kubeconfig credentials, and a real MySQL wire-protocol decoy β€” then alerts you on Telegram or a webhook the moment an attacker touches one.

This is a quick overview β€” security theory, architecture, and full walkthroughs are in the learn modules.

What It Does

  • Seven token types, each disguised as something an attacker would actually try to use: webbug, slowredirect, pdf, docx, envfile, kubeconfig, and a real mysql listener that speaks the MySQL v10 handshake
  • Per-token Telegram or webhook alerts the instant a token fires (HMAC-signed for webhooks)
  • Async notification worker pool with per-channel timeouts and dedup gating (15-minute Redis silence window per {token, source_ip} so a curious attacker reloading the page doesn't spam you)
  • GeoIP enrichment via MaxMind GeoLite2 (country, region, city, ASN, ASN org) attached to every event
  • Browser fingerprint capture for slowredirect tokens via a 3-second JS-collection interstitial before the redirect resolves
  • Public manage URL (UUID-gated) so you can share a single link with a teammate to view triggers without exposing operator credentials
  • Operator-only admin API (constant-time bearer comparison) for global stats, token listing, and force-disable
  • Cloudflare Turnstile on token creation, dual-window rate limiting (per-minute + per-hour) keyed by browser fingerprint
  • Optional Cloudflare Tunnel overlay β€” expose the service publicly without opening a port or maintaining a TLS cert
  • Defense-grade observability: OpenTelemetry traces, slog structured logs, /healthz liveness, graceful shutdown with load-balancer drain delay

Quick Start

just init       # generates .env, .env.development, randomised ports, operator token
just dev-up     # launches nginx + Vite HMR + Go (Air hot-reload) + Postgres + Redis + Jaeger

Open the URL printed by just init (typically http://localhost:22784). Mint a token, watch the manage page, then trigger it from another tab and refresh. or the live demo at iglowinthedark.com

Tip

This project uses just as a command runner. Type just to see every available recipe grouped by area.

Install: curl -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin

Token Types

Type Artifact Trigger Mechanism Where You'd Plant It
webbug URL to a 1x1 JPEG Any HTTP GET on the URL HTML emails, internal wikis, "do-not-touch" docs
slowredirect URL with a delayed redirect Click-through; runs fingerprint JS before redirecting to a real destination Phishing-bait links in honeyfile chat threads, fake admin panel URLs
pdf Patched PDF Acrobat opens, fires /AA /O /URI page-open action payroll-q3.pdf on a shared drive, vpn-creds.pdf on a workstation
docx Patched Word doc Word/LibreOffice loads the footer, which contains a remote URI customer-list.docx, passwords.docx in Documents/
envfile Plain-text .env Attacker curls the fake INTERNAL_METRICS_ENDPOINT baked into the file Repository roots, ~/.config/, container /app/ directories
kubeconfig YAML kubeconfig Attacker runs kubectl --kubeconfig=stolen.yaml ... and our server logs the bearer token ~/.kube/config, ops engineer laptops, CI runner home dirs
mysql mysql://... connection string Attacker connects with mysql CLI; our TCP listener replies with a real MySQL v10 handshake and an Access denied packet .env files, database.yml, internal wiki snippets

The envfile generator is the densest of the bunch. It picks recipes from aws.go, db.go, github.go, and stripe.go, shuffles the resulting sections, and buries a single canary line (INTERNAL_METRICS_ENDPOINT=https://your-host/c/{tokenID}) among plausible production config. The attacker harvesting the file gets a fistful of fake secrets to chase and trips the wire as soon as one of those secrets is touched.

HTTP API

Token creation, manage view, and admin are mounted under /api/. Trigger routes live at the root so artifacts can carry short URLs.

Method Path Auth Purpose
POST /api/tokens Turnstile + rate limit Mint a new token (type, memo, alert_channel, channel config, type-specific metadata)
GET /api/tokens/types Public List available token types and their metadata schemas
GET /api/m/{manageId} Manage UUID Token details + paginated event feed + dedup silence counter
DELETE /api/m/{manageId} Manage UUID Soft-disable the token (events stop, history retained)
GET /api/admin/stats Bearer Tokens count, events count, breakdowns by type and alert channel
GET /api/admin/tokens Bearer All tokens (offset paginated)
POST /api/admin/tokens/{id}/disable Bearer Force-disable any token
GET /healthz Public Liveness + readiness probe (used by Docker healthchecks)
GET /c/{tokenID} Public Trigger route. Records event, fires notification, returns artifact body (pixel, GIF, HTML interstitial, etc.)
POST /c/{tokenID}/fingerprint Public Receives JSON fingerprint payload from the slowredirect interstitial
* /k/{tokenID}[/*] Public Kubeconfig trigger β€” matches kubectl's wildcard API paths

The MySQL listener does not run on HTTP. It's a separate TCP server bound to a configurable address; an attacker using the connection string from the artifact will speak the MySQL wire protocol with our protocol.go handshake builder before getting denied.

Stack

Backend: Go 1.25, chi router, pgx + sqlx, goose migrations, koanf config, slog, validator/v10, OpenTelemetry, pdfcpu, MaxMind GeoLite2, miniredis (tests), testcontainers (integration)

Frontend: React 19, TypeScript, Vite, TanStack Query, Zod, Axios, Biome, Stylelint

Storage: PostgreSQL 18 (tokens, events tables; INET + JSONB columns), Redis 7 (dedup gate + rate-limit token buckets)

Infra: Docker Compose (dev: nginx + Vite HMR + Air + Postgres + Redis + Jaeger; prod: nginx + Go binary + Postgres + Redis), optional cloudflared overlay

Project Layout

canary-token-generator/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ cmd/canary/                main.go β€” wiring, signal handling, MySQL listener spawn, retention loop
β”‚   └── internal/
β”‚       β”œβ”€β”€ token/                 Service, repository, handler, generator interface
β”‚       β”‚   └── generators/
β”‚       β”‚       β”œβ”€β”€ webbug/        Embedded JPEG pixel
β”‚       β”‚       β”œβ”€β”€ pixel/         Shared 1x1 GIF helper used by every "visited" response
β”‚       β”‚       β”œβ”€β”€ pdf/           Byte-exact PDF placeholder substitution (76-byte URL window)
β”‚       β”‚       β”œβ”€β”€ docx/          ZIP-aware footer rewrite
β”‚       β”‚       β”œβ”€β”€ envfile/       Recipe shuffler + canary line injection
β”‚       β”‚       β”‚   └── recipes/   aws.go, db.go, github.go, stripe.go
β”‚       β”‚       β”œβ”€β”€ kubeconfig/    text/template renderer + wildcard /k/ handler
β”‚       β”‚       β”œβ”€β”€ mysql/         protocol.go (handshake + auth + err packets), server.go (TCP), handler.go
β”‚       β”‚       └── slowredirect/  HTML interstitial + fingerprint POST handler
β”‚       β”œβ”€β”€ event/                 Event entity, service (geo enrich β†’ insert β†’ dedup β†’ notify), repository
β”‚       β”œβ”€β”€ notify/                Worker pool, queue, status writer
β”‚       β”‚   β”œβ”€β”€ webhook/           HMAC-signed POSTs with exponential backoff
β”‚       β”‚   └── telegram/          Bot API client
β”‚       β”œβ”€β”€ middleware/            request_id, logging, recovery, realip, fingerprint, ratelimit, turnstile, operator_bearer, headers
β”‚       β”œβ”€β”€ geoip/                 MaxMind MMDB lookup wrapper (nop when no DB present)
β”‚       β”œβ”€β”€ turnstile/             Cloudflare Turnstile siteverify
β”‚       β”œβ”€β”€ admin/                 Stats, listing, force-disable
β”‚       β”œβ”€β”€ core/                  DB pool, Redis client, migrations, telemetry, errors, validation, response envelopes
β”‚       β”œβ”€β”€ health/                /healthz handler with readiness/shutdown flags
β”‚       └── server/                chi router shell with graceful shutdown + drain delay
β”œβ”€β”€ frontend/
β”‚   └── src/
β”‚       β”œβ”€β”€ pages/landing/         Token creation form (type-aware metadata, Turnstile widget, artifact reveal)
β”‚       └── pages/manage/          Token detail + event table (cursor paginated, GeoIP cells, dedup silence)
β”œβ”€β”€ infra/
β”‚   β”œβ”€β”€ nginx/                     prod.nginx, dev.nginx (Vite proxy)
β”‚   └── docker/                    Dockerfiles for prod binary, Air hot-reload, Vite HMR
β”œβ”€β”€ compose.yml                    Production stack
β”œβ”€β”€ dev.compose.yml                Dev stack with Jaeger
β”œβ”€β”€ cloudflared.compose.yml        Tunnel overlay
β”œβ”€β”€ justfile                       Recipes grouped by frontend / backend / lint / compose / tunnel / dev / util
└── learn/                         You are here

Learn

This project includes step-by-step learning materials covering deception theory, token mechanics, system design, and a code walkthrough.

Module Topic
00 - Overview Prerequisites, quick start, project structure
01 - Concepts Honeytokens, deception defense, Thinkst Canary, MITRE Engage, real breaches
02 - Architecture System design, request lifecycle, schema, dedup gate, notification pipeline
03 - Implementation Code walkthrough: generators, trigger handler, event service, MySQL protocol
04 - Challenges Extension ideas β€” new token types, alert channels, evasion-resistance

License

AGPL 3.0