An evolving HTTP honeypot, actively maintained by an LLM working off observations from a live honeypot sensor network. Fresh scanner behaviour in the corpus drives new traps; existing traps get tuned or retired as the logs show what's eliciting follow-up and what's being ignored.
Small async Python behind nginx. Python 3.11+; one runtime dep — aiohttp. Async so the tarpit and fake-git drip paths can hold thousands of concurrent slow-drip connections at ~8 KB each instead of one OS thread each.
Experimental — no guarantees about safety or value. Every line was written by an LLM from natural-language prompts, smoke-tested against a live sensor, and continuously reshaped by the same loop. It has not been audited line-by-line by a human. The author makes no claim that flux is safe to run, produces useful intel, or won't do something surprising under load. Before deploying anywhere that matters, read
flux/server.pyend-to-end, run the test suite, and think hard about whatHONEYPOT_WEBSHELL_PATHS_CSVorFAKE_GIT_*hitting a real webroot would do. No warranties.
Each family is independently toggleable via env var; all default to
on (see CONFIG.md). Keyless deployments still 404
the canary-backed rows — dispatch requires TRACEBIT_API_KEY on top
of the master switch. We use Tracebit Community
for the canaries: free tier, sign up and drop the key in the env var.
| Trap | What it does | Key |
|---|---|---|
Fake /.env canary issuer |
Mints a per-request Tracebit Community canary and returns it as a .env-style payload |
yes |
Fake /.git/ repository |
Serves a loose-object git tree whose config/secrets.yml embeds a canary AND whose .git/config [remote "origin"] url embeds the same canary as HTTP Basic userinfo — so scrapers that only fetch .git/config (without cloning) still walk away with a live canary. Matches <prefix>/.git/* (apps deployed at subpaths) and is case-insensitive on the .git segment; ships a minimal-valid /.git/index (DIRC header) so git-dumper-style tools don't bail on a missing index. Per-IP cached so fan-out sees a consistent tree |
yes |
| Canary file traps | Plausible file-format responses for /wp-config.php, /backup.sql, /id_rsa, /.aws/credentials, /api/v4/user, /users/sign_in, /actuator/env, /.vscode/sftp.json, GCP service-account JSON variants (/.config/gcloud/application_default_credentials.json, /firebase-adminsdk.json, …), CI/CD config files, Terraform tfstate (/.terraform/terraform.tfstate, /terraform.tfstate(.backup) — docs), PaaS / .NET / IIS / Docker source-config (/Procfile, /heroku.yml, /app.json, /appsettings.json, /web.config, /auth.json, /Dockerfile — docs), niche cloud-provider CLI configs (OCI, Hetzner, Civo, Exoscale, Scaleway, Fly.io, OVH, OpenStack, Terraform Cloud, Pulumi, DigitalOcean, Linode, s3cmd, s3fs, Cargo, RubyGems, GitHub CLI, 1Password, Cloudflare Tunnel, WireGuard, Headscale — docs), … — full table below |
yes |
| Backup-archive canary — docs | Pattern-match <base>.<ext> backup-archive filenames against a ~95-name base dictionary × 17 compression extensions (tar.gz, zip, sql.gz, 7z, …), plus IP-octet- and date-derived filename synthesis (/65.20.84.180.tar.gz, /84.tar.gz, /2026.zip, /202603.tar.gz). Serves a real archive in the matching format containing .env + backup.sql with embedded Tracebit AWS canary. Catches generic backup hunters plus the per-target filename synthesis pattern from newer scanner tools |
yes |
| AI-credential-file canaries | AI editor / coding-assistant configs (/.claude/{settings,settings.local,config,history.jsonl,.credentials,CLAUDE.md}, /.claude.json, /.codex/auth.json, /.gemini/{oauth_creds,settings}.json, /.cline/{settings,mcp_settings}.json, /.continue/config.json, /.cursor/mcp.json, /.cursor/User/globalStorage/state.vscdb, /.cursorrules, /.windsurfrules, /.clinerules, /.aider.conf.yml, /.sourcegraph/cody.json, /.config/open-interpreter/config.yaml, /AGENTS.md, …) plus per-vendor LLM API-key files (/.anthropic/api_key, /.dashscope/api_key, /.deepseek/config.json, /.kimi/, /.moonshot/settings.json) plus AI infrastructure / proxy configs (/litellm_config.yaml, /langsmith.env, /.huggingface/token, /.streamlit/secrets.toml, /baseten.yaml, generic MCP configs, /.bito/, /.codeium/, /.roost/, /cohere_config.json, …) and niche coding-agent tooling (/.openclaw/, /root/.config/opencode/, /root/.config/vastai/, /root/.nerve/, /root/.spawnrc, /root/.config/moltbook/) — listed in the same table; broken out in the footnote because Tracebit has no LLM canary type yet |
yes |
| Fake webshell | Plausible File Manager on known *.php shell probe paths plus shell-jacking regex families (/.well-known/<name>.php, /.trash<N>/*, /.tmb/, /.dj/, /.alf/, …); simulates id / whoami / uname -a / cat /etc/passwd on follow-up commands — docs |
no |
| Fake file-upload responder | Prefix-tolerant matchers for the legacy PHP file-upload libraries scanners walk (<prefix>/kcfinder/upload.php, <prefix>/jquery.filer/php/upload.php, <prefix>/jquery-file-upload/server/php/); GET returns presence-detection-friendly HTML/JSON/README, POST parses multipart parts and returns the per-family "uploaded OK" envelope. Logs fileUploadFamily / filenames / per-part content-types / fileUploadHasPhpShell so payload-bearing uploads are easy to triage. (CVE-2018-15706 / CVE-2018-9206 bait) — docs |
no |
| Modular tarpit + fingerprinting | Slow-drip response plus six fingerprinting modules (cookie, ETag, redirect chain, variable drip, Content-Length mismatch, DNS callback); fires on .env variants and on configurable first-contact paths (/, /index.html, /robots.txt, …) |
no |
| Fake LLM-API endpoint | Ollama / OpenAI / Anthropic-proxy JSON on /v1/models, /v1/chat/completions, /anthropic/v1/messages, /api/chat, … ; returns native SSE / NDJSON streaming when the client sets "stream": true so SDK-based callers read through to completion; logs model, prompt prefix, bearer / x-api-key token (sha256 + first-12 + last-4 preview) for cross-IP key-replay grouping — docs |
no |
| Fake OpenAPI / Swagger spec | OpenAPI 3.0.3 JSON/YAML document on the SpringDoc / FastAPI / Swashbuckle / drf-yasg / NSwag canonical paths (/swagger.json, /v3/api-docs, /openapi.json, /openapi.yaml, /swagger/v1/swagger.json, /api-docs, /webjars/swagger-ui/index.html, …) plus Swagger UI / ReDoc bootstrap HTML; embeds the canary in securitySchemes.{bearer,apiKey}Auth.x-example, servers[].variables.adminApiKey.default, and the info.description text so credential scrapers that grab any of those slots get a replay-fireable key — docs |
yes |
| Fake GraphQL endpoint | GraphiQL HTML on GET /graphql (+ /api/graphql, /graphql/api, /api/gql, /v1/graphql, /query, …). POST body is classified: __schema / IntrospectionQuery returns a plausible schema listing User.apiToken / awsAccessKeyId / secretKey / refreshToken / webhookSecret fields. Follow-on data query against any credential-shaped field returns a per-hit Tracebit AWS canary in apiToken / accessToken / awsAccessKeyId / awsSecretAccessKey / secretKey slots (per-hit-random refreshToken and webhookSecret). Auth mutations (login, signIn, signUp, register, createUser, authenticate, resetPassword) return AuthPayload with the canary as token, capture the submitted username from inline literals or variables, and log graphqlHasPassword without storing the value. Unknown queries return a plausible Syntax Error / permission denied error envelope so the scanner keeps probing — docs |
yes |
| Fake SonicWall SSL VPN | SonicOS 7 JSON responses on the three paths in the CVE-2024-53704 auth-bypass chain; logs submitted username, body sha + preview, and replayed session cookies — docs | no |
| Fake Cisco WebVPN endpoint | Cisco SSL VPN landing page + launcher assets on /+CSCOE+/... and /+CSCOL+/...; also recognizes AnyConnect config-auth XML POSTs to / and logs submitted usernames without storing passwords — docs |
no |
| Fake Ivanti Connect Secure / Pulse Secure VPN | Ivanti SSL VPN welcome + login POST + HostChecker installer assets on /dana-na/... and /dana-cached/hc/...; mints a per-request DSID cookie, logs username + has-password, and flips ivantiHasCmdInjection on shell-meta payloads aimed at /dana-ws/namedusers (CVE-2023-46805 / CVE-2024-21887 / CVE-2025-22457 chain bait) — docs |
no |
| Fake FortiGate SSL VPN | FortiOS SSL VPN login + /remote/logincheck credential POST (mints per-request SVPNCOOKIE) plus /api/v2/cmdb/system/{admin,status,global} and /api/v2/monitor/router/policy REST stubs; flips fortigateHasCmdInjection on shell-meta payloads aimed at the REST surface (CVE-2024-21762 / CVE-2023-27997 / CVE-2024-48887 bait) — docs |
no |
| Fake Palo Alto GlobalProtect | GlobalProtect portal + gateway prelogin XML on /global-protect/prelogin.esp and /ssl-vpn/prelogin.esp, login form + credential POST on /global-protect/login.esp (mints per-request PHPSESSID), gateway config on /global-protect/getconfig.esp; Server: PanWeb Server/ matches real appliance fingerprint (CVE-2024-3400 bait) — docs |
no |
| Fake Sophos XG SSL VPN | Sophos XG Firewall SSL VPN login portal on /svpn/index.cgi and /userportal/webpages/myaccount/login.jsp; credential POST captures username + has-password, mints per-request JSESSIONID cookie (CVE-2022-1040 bait) — docs |
no |
| Fake Barracuda SSL VPN | Barracuda Networks VPN tunnel negotiation on /myvpn (returns CONNECT + ipv4/ipv6 flags) and login portal on /cgi-mod/index.cgi (CVE-2023-7102 / CVE-2023-7101 reconnaissance surface) — docs |
no |
| Fake F5 BIG-IP APM / TMUI | BIG-IP Access Policy login on /my.policy (mints per-request MRHSession cookie), TMUI Configuration Utility on /tmui/login.jsp (prefix-matches /tmui/* to catch CVE-2020-5902 path-traversal), SSL VPN client negotiation on /sslvpnclient; flags f5HasPathTraversal on /../ indicators, Server: BigIP header (CVE-2023-46747 / CVE-2022-1388 bait) — docs |
no |
| Fake Docker Registry V2 API | Docker Distribution Registry HTTP API V2 surface: version check (/v2/), catalog listing (/v2/_catalog), tag enumeration (/v2/<name>/tags/list), manifest retrieval (/v2/<name>/manifests/<ref>), blob download (/v2/<name>/blobs/<digest>); logs Authorization headers, mutation attempts (PUT/PATCH/POST/DELETE), and repo/tag/digest per request. Multi-step protocol reveals scanner sophistication — docs |
no |
| Fake Docker Engine API (daemon on 2375) | Docker Engine API surface: /version, /info, /_ping, /containers/json, /images/json, plus the takeover chain POST /containers/create → POST /containers/<id>/start → POST /containers/<id>/exec → POST /exec/<id>/start. Mints a fake 64-hex container/exec ID per create so the scanner ships its follow-up /start against the same trap. Strips a /vX.Y API-version prefix and a :2375 / %3a2375 / %253a2375 SSRF colon-port shim from the path before dispatching, and flags the SSRF shape as dockerDaemonHasSsrfPrefix. Parses the create body for Image / Cmd / Entrypoint and flips dockerDaemonHasPrivileged / dockerDaemonHasHostMount / dockerDaemonHasHostPid / dockerDaemonHasHostNetwork / dockerDaemonHasDangerousCap / dockerDaemonHasShellPayload for fast triage of cryptominer / host-takeover payloads — docs |
no |
| Fake Citrix NetScaler / Gateway portal | NetScaler ADC / Gateway login HTML on /vpn/index.html, /logon/LogonPoint/index.html, /Citrix/XenApp/auth/login.aspx; credential POST sinks at /cgi/login and /p/u/doAuthentication.do mint a per-request NSC_AAAC session cookie (CVE-2023-4966 "CitrixBleed" leak shape — never a fixed literal). Flips citrixHasCmdInjection on shell-meta and CVE-2019-19781 path-traversal indicators (Shitrix); also covers CVE-2023-3519 / CVE-2022-27510 / CVE-2023-24486 fingerprint chains — docs |
no |
| Fake Microsoft RDWeb (RD Web Access) | RDWeb login page + /RDWeb/Pages/en-US/login.aspx credential POST (mints per-request TSWAAuthHttpOnlyCookie) plus /RDWeb/Pages/en-US/Default.aspx post-auth resource list. After a "successful" landing-path POST (and on direct Default.aspx fetches), the resource list ships a single Cloud Console RemoteApp tile whose RDPFileContents HTML comment embeds a per-hit Tracebit AWS canary — credential-scrapers walking post-auth content harvest a key that fires on AWS replay. Logs DomainUserName / UserPass-presence so password-spraying credential rotations land in the access log; advertises Server: Microsoft-IIS/10.0 to match real Server 2019 RDWeb — docs |
no |
| Fake Microsoft Exchange (OWA / ECP / autodiscover / PSRemoting) | Multi-step Exchange surface: OWA login on /owa/auth/logon.aspx (mints per-request cadata cookie), ECP login on /ecp/ (mints msExchEcpCanary), eDiscovery exporttool ClickOnce manifest on /ecp/Current/exporttool/microsoft.exchange.ediscovery.exporttool.application (build version stamped in <assemblyIdentity> for fingerprint diff), autodiscover JSON on /autodiscover/autodiscover.json (per-request MailboxGuid + Bearer literal), and a 401 + WWW-Authenticate: Negotiate, Kerberos, NTLM on /powershell/. Flips exchange-autodiscover-proxyshell-ssrf on the literal ?@<spoof> query shape, logs exchangeXRpsCatPresent + exchangeHasPowershellCmdlet on PSRemoting POSTs, captures OWA / ECP usernames (username / j_username / UserName variants) without storing passwords. Headers pin Server: Microsoft-IIS/10.0 + X-OWA-Version (CVE-2021-34473 / CVE-2021-34523 / CVE-2021-31207 ProxyShell bait) — docs |
no |
| Fake IBM Aspera Faspex portal | Aspera Faspex login/logout/relay surfaces on /aspera/faspex/...; emits plausible HTML/JSON, logs follow-on payload previews on logout/relay endpoints, and keeps scanner chains alive past initial fingerprinting (CVE-2022-47986 bait) — docs |
no |
| Fake Hikvision IP camera | Hikvision ISAPI surface (/SDK/webLanguage, /ISAPI/Security/userCheck, /ISAPI/System/deviceInfo); returns plausible XML with Server: App-webs/ and a CVE-2021-36260-window firmware banner, flips hikvisionHasCmdInjection on shell-meta indicators in body/query so language-parameter command-injection payloads are easy to triage — docs |
no |
| Fake ONVIF device_service | ONVIF SOAP banner at /onvif/device_service (/onvif/services, /onvif/device, bare /device_service); returns a Dahua-class <GetDeviceInformationResponse> envelope with Server: lighttpd/ and a firmware version sitting in the public-disclosure window for the Dahua-class CVEs (CVE-2024-7029 auth-bypass cmd-injection, CVE-2023-43261, CVE-2021-33044). Logs onvifSoapActionHeader/onvifSoapActionBody and flips onvifHasCmdInjection on shell-meta or FirmwareUpgrade / UpgradeUrl sink-element indicators — docs |
no |
| Fake D-Link / Linksys HNAP1 router | SOAP-over-HTTP HNAP1 control endpoint at /HNAP1; GETs return a <DeviceSettings> envelope with vendor / model / Server: Mathopd/ banner, POSTs return a generic SOAP OK whose response element name tracks the SOAPAction header. Logs the raw SOAPAction value and flips hnap1HasCmdInjection on shell-meta indicators in the header / query / body so CVE-2015-2051 dropper payloads are easy to triage — docs |
no |
| Fake GeoServer admin / OGC | GeoServer 2.x admin shell + About page + OGC *_Capabilities on /geoserver/...; flags OGNL/expression-language indicators in query string + body so CVE-2024-36401 payloads are easy to triage — docs |
no |
| Fake ColdFusion admin / component browser | ColdFusion public .cfm anchors plus /CFIDE/componentutils/, Administrator, and AdminAPI surfaces; logs method, auth/session hints, and exploit payload indicators — docs |
no |
| Fake Atlassian Confluence | Confluence 7.x login surface on pages/createpage-entervariables.action, pages/doenterpagevariables.action, templates/editor-preload-container, users/user-dark-features, login.action (bare, /confluence/, /wiki/ prefixes); also matches URL-encoded ${@...} OGNL injections in the request path itself; extracts the OAST/Interactsh callback hostname from the payload (CVE-2022-26134 bait) — docs |
no |
| Fake SAP NetWeaver Visual Composer MetadataUploader | NetWeaver Visual Composer servlet at /developmentserver/metadatauploader (plus /irj/, /nwa/, /sap/ webroot prefixes); GET returns the SAP-formatted XML error envelope, POST parses the multipart body, logs filename / content-type / sapMetadataUploaderHasJspShell / sapMetadataUploaderHasXxe, and returns the plaintext "OK: stored …" receipt with the uploaded filename echoed back (CVE-2025-31324 unauth file-upload + CVE-2017-9844 XXE bait) — docs |
no |
Fake Drupal /user/register + settings.php |
Drupalgeddon2 trigger surface at /user/register (also /?q=user/register, /drupal/, /cms/ prefixes); GET returns a Drupal 8/9 user-registration form with per-request form_build_id / form_token, POST captures the mail[#post_render] / element_parents chain and flags drupalHasDrupalgeddon2 / drupalHasRcePayload for triage. Twin canary at /sites/default/settings.php (+ .bak / .swp / ~ / %00 / %20 / default.settings.php / /sites/all/ / /drupal/ / /cms/ variants) ships a fully shaped Drupal config with per-hit synthetic DB password + Tracebit AWS canary in the s3fs.settings block (CVE-2018-7600 bait) — docs |
yes (settings.php only) |
| Fake Spring Cloud Gateway Actuator extension | /actuator/gateway/routes, /actuator/gateway/routes/{id}, /actuator/gateway/refresh, /actuator/gateway/globalfilters, /actuator/gateway/routefilters, /actuator/gateway/routepredicates (plus /manage/gateway/, /management/gateway/, /api/actuator/gateway/ reverse-proxy aliases); GET returns a fake route list with the Tracebit AWS canary embedded in metadata.adminApiKey + metadata.adminApiSecret and inside an AddRequestHeader filter named X-Admin-Api-Key. POST to a route id captures the SpEL body, flips springGatewayHasSpel on #{T(…) / T(java.lang.*) / getRuntime / ProcessBuilder indicators, and returns 201 Created. /refresh returns 200 (matches real CVE-2022-22947 chain step); Server: Spring Cloud Gateway/3.1.0 banner pinned inside the public-disclosure window — docs |
yes |
| Fake Next.js + SSJS-injection responder | Empty page-data JSON on /_next/data/<buildId>/*.json and Next.js-conventional /api/* routes; on a ?cmd=<base64> payload that decodes to a JS-eval shape (require('child_process').execSync(cmd)), extracts the inner var cmd = "echo X" literal and reflects the simulated output back, falling back to the scanner's own ERROR catch-block sentinel for unrecognised commands. Also covers the dev-mode internal endpoints (/__nextjs_action, /__nextjs_launch-editor, /__nextjs_error_overlay, /__nextjs_original-stack-frame, /__nextjs_stack_frame) with shape-appropriate responses: empty RSC for Server Actions (POST body captured), {"opened":true} for the IDE-launch endpoint (with file=/line= query args captured), and a per-hit HTML stack frame for the overlay endpoints. URL-encoded leading-slash bypasses (/%2f__nextjs_action, /%252f__nextjs_action%2f) normalise back to the same dispatch — docs |
no |
| Cmd-injection / printenv responder | /admin/config?cmd=… and /admin/config.php?cmd=… (admin-shell exploit shape) plus /printenv, /cgi-bin/printenv, /cgi-bin/test-cgi; classifies the cmd value, returns a plausible cat /etc/passwd / id / uname body, and mints a per-request Tracebit AWS canary when the cmd asks for ~/.aws/credentials or env vars — docs |
yes |
| PHP/body-RCE responders | Body-driven exploit responders for PHPUnit eval-stdin.php, PHP-CGI auto_prepend_file=php://input (CVE-2024-4577), and Apache CGI path-traversal /bin/sh; logs request-body payloads and decoded base64 command hints. Bare GET/HEAD against /cgi-bin/php, /cgi-bin/php-cgi, /cgi-bin/php{5,7,8}{,-cgi,.cgi}, /cgi-bin/, and /cgi-bin returns the canonical <br />\n<b>No input file specified.</b> 200 page with Server: Apache/2.4.41 (Win64) … PHP/7.4.33 + X-Powered-By: PHP/7.4.33 so the gated CVE-2024-4577 scanner population (the one that liveness-probes before sending the exploit) follows up with the exploit POST, which then lands in the body-RCE handler above — docs |
no |
| Web-app form responder | Plausible HTML forms on /login, /signin, /signup, /register, /checkout, /cart, /contact, /subscribe, /newsletter, /dashboard, /profile, /settings, /admin, /auth/*, /api/{login,signup,contact,…}; GET returns the form with a per-request hidden CSRF token, POST returns a 302 back to the form (auth-failure shape) with a per-request session_id cookie. Logs extracted username/email, has-password/email flags, the submitted field-name list, and the body preview/sha256 so credential-stuffing payload rotations land in the access log — docs |
no |
| Framework dev-mode debug surfaces | Symfony Web Profiler phpinfo (/_profiler/phpinfo, /app_dev.php/_profiler/phpinfo, /symfony/_profiler/phpinfo, /frontend_dev.php/_profiler/phpinfo) plus profiler dashboard (/_profiler/latest, /_profiler/search, /_profiler/ with the same /app_dev.php/, /symfony/, /frontend_dev.php/ prefixes) returns a phpinfo-shaped page with $_ENV carrying the AWS canary + per-hit APP_SECRET / DATABASE_URL / MAILER_DSN; Symfony parameters.yml (/parameters.yml, /config/parameters.yml, /app/config/parameters.yml) and the dev-mode /_profiler/open local-file-read endpoint return a YAML body with the canary in aws_* keys plus per-hit database_password / mailer_password / secret; Yii2 debug toolbar (/debug/default/view, /web/debug/default/view, /frontend/web/debug/default/view, /backend/web/debug/default/view, /sapi/debug/default/view, /debug/default/db-explain) returns an HTML page mimicking yii\debug\Module ConfigPanel with $_ENV and components.db.* / components.mailer.* carrying the same canary set; Django debug toolbar (/__debug__/render_panel/, /__debug__/sql_select/, /__debug__/sql_explain/, /__debug__/sql_profile/, /__debug__/template_source/) returns SECRET_KEY + DATABASE_URL + AWS canary in a SettingsPanel-shaped page; Laravel facade/ignition error page (/_ignition/execute-solution plus /api/_ignition/... / /backend/_ignition/... reverse-proxy aliases, /_ignition/health-check, /_ignition/scripts/ignition.js, /_ignition/styles/ignition.css) returns an Ignition stack-trace HTML page whose "Environment" panel carries APP_KEY / DB_PASSWORD / REDIS_PASSWORD / MAIL_PASSWORD (per-hit) + the AWS canary triple; CVE-2021-3129 POST exploit bodies captured via bodySha256 — docs |
yes |
| Fake WordPress wp-login.php canary | WordPress 6.x login page on /wp-login.php with per-hit _wpnonce hidden field + wordpress_test_cookie; POST captures log/pwd and checks whether the submitted nonce matches one previously issued to the same IP (nonce-harvesting vs blind-POST attribution); /wp-admin/* paths redirect to the login page. Logs wpLoginUsername, wpLoginNonceMatch, wpLoginTestcookiePresent — docs |
no |
| Fake Vite dev-server env-leak | /@vite/env returns a Vite client-module body whose context.define flat-key block exposes VITE_* env vars — VITE_AWS_ACCESS_KEY_ID / VITE_AWS_SECRET_ACCESS_KEY / VITE_AWS_SESSION_TOKEN / VITE_API_KEY carry the per-hit Tracebit AWS canary, so frontend-env scanners that grep raw bytes for VITE_ / AKIA patterns harvest a replay-fireable key. Per-hit-unique VITE_SENTRY_DSN public key / VITE_S3_BUCKET suffix / VITE_APP_ID keep the body from acting as a fleet fingerprint. Companion /@fs/ arbitrary-file-read entries (under bash-history / zsh-history) cover the FS-walk pivot scanners chain after the env probe — docs |
yes |
All traps log one JSON line per event to the configured log path. See
LOGS.md for the schema.
pip install .Or in place (needs aiohttp on the path):
pip install aiohttp
python -m fluxFlux listens on 127.0.0.1:18081 by default. The expected deployment puts
nginx in front and proxies a set of trap paths (e.g. /.env, /.git/*,
/shell.php, etc.) to it; nginx handles TLS, X-Forwarded-* headers, and
all non-trap routing.
export TRACEBIT_API_KEY=... # optional — enables canary-backed traps (/.env, /.git/*, etc)
python -m fluxDocs: CONFIG.md (env vars) ·
LOGS.md (JSONL schema + result tags) ·
BENCH.md (throughput + tarpit saturation numbers).
A trap renderer that ships a fixed literal credential (hardcoded DB password, hardcoded API key) provides no detection value — a replay triggers nothing — and ships the same string across every sensor in the fleet, which becomes a cross-sensor fingerprint. Every secret-shaped field in a rendered response must therefore be per-hit unique. We back it with Tracebit when that adds detection value (replay against AWS STS, the Tracebit-hosted gitlab URL, the Tracebit sshIp); when there's no matching canary type we fall back to a per-hit random synthetic. Concretely, every secret-shaped field is either:
- A per-request Tracebit canary —
_aws(r)or_gitlab_creds(r, ...). Fires when replayed against the matching target (AWS STS globally, the Tracebit-hosted gitlab URL for u/p and cookie, the Tracebit sshIp for ssh). - A per-hit random synthetic —
_fake_db_password()or similar. Does not fire (no Tracebit path exists for the cred type, e.g. MySQL/Postgres), but is unique per rendering so the rendered body can't be fingerprinted across the fleet.
Hardcoded literals in the "plausible filler" around the canary are
fine when the value isn't credential-shaped — usernames like
wp_prod, host names like db.internal, bucket names, comments.
What must never be fixed is anything that looks like a password,
token, or key.
When the canary type doesn't exist in Tracebit Community yet (LLM API keys, Google service accounts), the trap must either (a) dress an AWS canary in plausible shape so a field-name-keyed harvester still exfils a live canary value (see the AI-credential traps below) or (b) emit a per-hit random synthetic so the response isn't fingerprintable — never a fixed literal.
All gated on TRACEBIT_API_KEY, with per-IP TTL caching to protect quota.
Toggle the whole category with CANARY_TRAPS_ENABLED. Paths are
case-insensitive exact matches.
| Trap | Paths | Canary type | Log tag |
|---|---|---|---|
| AWS credentials file (INI) | /.aws/credentials |
aws |
aws-credentials-file |
| AWS SDK config (INI) | /.aws/config |
aws |
aws-config-file |
AWS Python SDK / gsutil boto config |
/.boto, /.boto3, /root/.boto, /home/.boto |
aws |
boto-config |
| AWS Amplify CLI project config | /.amplifyrc |
aws |
amplifyrc |
| Terraform tfstate (JSON) — docs | /.terraform/terraform.tfstate, /terraform.tfstate, /terraform.tfstate.backup |
aws |
terraform-tfstate |
| Terraform tfvars (HCL + JSON) — docs | /terraform.tfvars, /.terraform/terraform.tfvars, /terraform.tfvars.json, /.terraform/terraform.tfvars.json |
aws |
terraform-tfvars, terraform-tfvars-json |
| GCP service-account JSON (generic webroot aliases) — docs | /gcp-credentials.json, /config/gcp-credentials.json, /private/gcp-credentials.json, /api/credentials.json, /private/credentials.json, /backend/credentials.json, /app/credentials.json |
aws |
gcp-credentials-json |
| Niche cloud CLI configs — docs | OCI (/.oci/config, /.oci/oci_api_key.pem), Hetzner (/.config/hcloud/cli.toml), Civo, Exoscale, Scaleway, Fly.io, OVH, OpenStack, Terraform Cloud (/.terraform.d/credentials.tfrc.json, /.terraformrc), Pulumi, DigitalOcean doctl, Linode, s3cmd, s3fs, Cargo, RubyGems, GitHub CLI, 1Password, Cloudflare Tunnel, WireGuard, Headscale |
aws |
oci-config, hcloud-cli, civo-cli, exoscale-cli, scaleway-cli, fly-cli, ovh-conf, openstack-clouds-yaml, terraform-credentials-tfrc, terraformrc, pulumi-credentials, doctl-config, linode-cli, s3cfg, passwd-s3fs, cargo-credentials, gem-credentials, gh-hosts-yml, 1password-config, cloudflared-config, wireguard-conf, headscale-config |
| Azure CLI credential / profile cache — docs | /.azure/azureProfile.json, /.azure/accessTokens.json, /.azure/msal_token_cache.json, /.azure/service_principal_entries.json, /.azure/config, /.azure/clouds.config |
aws |
azure-cli-profile, azure-cli-access-tokens, azure-cli-msal-cache, azure-cli-service-principal, azure-cli-config, azure-cli-clouds-config |
| Postgres pgpass | /.pgpass |
gitlab-username-password |
pgpass |
Apache .htpasswd — docs |
/.htpasswd |
gitlab-username-password |
htpasswd |
| WordPress config | /wp-config.php plus editor-leftover suffix variants (.bak, .save, .swp, .swo, .old, .orig, .txt, ~, ::$DATA) and short/relocation forms (/wp-config.bak, /wp-config.old, /wp-config.txt, /wp-config-backup.php, /backup/wp-config.php); also matches the observed double-encoded .bak form |
aws |
wp-config |
| Drupal settings.php — docs | /sites/default/settings.php plus editor-leftover suffix variants (.bak, .save, .swp, .swo, .old, .orig, .txt, ~), short/null-byte/space-truncation forms (/sites/default/settings.bak/.old/.txt, /sites/default/settings.php%00, /sites/default/settings.php%20), the unconfigured-template name (/sites/default/default.settings.php), the multisite /sites/all/settings.php shape, and webroot-prefix /drupal/, /cms/ variants |
aws |
drupal-settings-php |
| SQL dump | /backup.sql, /db.sql, /dump.sql, /database.sql, /backup/db.sql, /sql/backup.sql |
aws |
sql-dump |
| Generic JSON config | /config.json, /settings.json, /credentials.json, /secrets.json |
aws |
config-json |
| SFTP deploy config | /.vscode/sftp.json, /sftp-config.json, /sftp.json, /.ftpconfig |
gitlab-username-password |
sftp-config |
| Firebase / GCP SA | /firebase.json, /google-services.json, /serviceaccount.json, /service-account.json, /firebase-adminsdk.json, /gcp-service-account.json, /.config/gcloud/application_default_credentials.json |
aws |
firebase-json |
| Docker client | /.docker/config.json, /docker/config.json, /root/.docker/config.json, /home/.docker/config.json |
aws |
docker-config |
| Docker Compose | /docker-compose.yml, /docker-compose.yaml, /compose.yml, /compose.yaml, plus .prod, .production, .dev, .staging, .override variants (both .yml and .yaml) |
aws |
docker-compose |
| GitHub Actions workflows | /.github/workflows/{deploy,main,ci,build,test,docker,release,cd}.yml plus .yaml variants |
aws |
github-actions-workflow |
| GitLab CI config | /.gitlab-ci.yml, /.gitlab-ci.yaml, /.gitlab/.gitlab-ci.yml |
aws |
gitlab-ci |
| Jenkins Pipeline | /Jenkinsfile, /Jenkinsfile.bak |
aws |
jenkinsfile |
| Bitbucket Pipelines | /bitbucket-pipelines.yml, /bitbucket-pipelines.yaml |
aws |
bitbucket-pipelines |
| Generic CI deploy config | /appveyor.yml, /.circleci/config.yml, /azure-pipelines.yml, /deployment.yml, /deploy.yml, /drone.yml, /.drone.yml plus .yaml variants where applicable |
aws |
generic-ci-config |
| Spring properties | /application.properties |
aws |
application-properties |
| Spring YAML | /application.yml, /application.yaml |
aws |
application-yml |
Spring Boot Actuator /env |
/actuator/env, /actuator/env.json, /env, /manage/env, /management/env, /api/actuator/env, /app/actuator/env, /backend/actuator/env |
aws |
actuator-env |
| Spring Boot Actuator surface — docs | /actuator/{heapdump,configprops,health,mappings,threaddump,logfile,trace,httptrace} plus /manage, /management, /api/actuator, /app/actuator, /backend/actuator reverse-proxy aliases |
aws |
actuator-heapdump / actuator-configprops / actuator-health / actuator-mappings / actuator-threaddump / actuator-logfile / actuator-trace |
| Production .env and its sibling rotation/backup/per-env variants | /.env.{production,prod,live,local,dev,development[.local],test[.local],staging,example[.local],ci,save,private,docker,override}, /.env2, /.env_{bak,old,orig,priv,example}, /.environ, plus webroot-prefix /{mailer,opt,srv,var/www,app,backend,api}/.env[.{production,local,dev,…}] |
aws |
env-production |
Mail-service .env — docs |
/{sendgrid,postmark,mailjet,brevo,mailgun,mailing,mail,mailserver}/.env — service-specific API key formats (SendGrid SG.xxx, Postmark token, Mailjet key pair, Brevo xkeysib-, Mailgun key-) alongside AWS canary |
aws |
mail-service-env |
| dotenv-vault file — docs | /.env.vault, /.env.vault.bak, /.env.vault.example |
aws |
env-vault |
| Vite dev-server env-leak — docs | /@vite/env — ES-module body with context.define flat-keys exposing VITE_* env vars; AWS canary lives in VITE_AWS_* and VITE_API_KEY slots |
aws |
vite-env |
| Go pprof debug endpoint — docs | /debug/pprof[/heap|/cmdline|/goroutine|/profile|/symbol|/trace|/threadcreate|/block|/mutex|/allocs] plus /api-prefixed variants |
aws |
pprof-dump |
| phpinfo() | /phpinfo.php, /info.php, /php.php, /test.php |
aws |
phpinfo |
| SSH private key | /id_rsa, /.ssh/id_rsa, /ssh/id_rsa, /ssh/id_rsa.key, /keys/id_rsa, /private.key, /deploy_key, /deploy.key, /.ssh/id_ed25519, /.ssh/id_dsa, /.ssh/id_ecdsa, /id_ed25519, /id_dsa, /id_ecdsa, /root/.ssh/id_rsa, /home/.ssh/id_rsa |
ssh |
ssh-private-key |
| SSH public key | /id_rsa.pub, /.ssh/id_rsa.pub |
ssh |
ssh-public-key |
| SSH client config | /.ssh/config |
ssh |
ssh-config |
| known_hosts | /.ssh/known_hosts, /known_hosts |
ssh |
known-hosts |
| authorized_keys | /authorized_keys, /.ssh/authorized_keys, /.ssh/authorized_keys2, /static/.ssh/authorized_keys, /downloads/.ssh/authorized_keys, /blog/.ssh/authorized_keys |
ssh |
authorized-keys |
| .netrc | /.netrc, /_netrc |
gitlab-username-password |
netrc |
| git credential store | /.git-credentials, /root/.git-credentials, /home/.git-credentials; fake-git also serves /.git/credentials |
gitlab-username-password |
git-credentials / fake-git |
| .npmrc | /.npmrc, /root/.npmrc, /home/.npmrc |
gitlab-username-password |
npmrc |
| Node.js dependency manifests — docs | /yarn.lock(.bak|.old), /package-lock.json(.bak|.old), /var/backups/npm/package-lock.json.old, /package.json, /.yarnrc, /.yarnrc.yml |
gitlab-username-password |
yarn-lock / package-lock-json / package-json / yarnrc / yarnrc-yml |
| .pypirc | /.pypirc |
gitlab-username-password |
pypirc |
| GitLab API user | /api/v4/user |
gitlab-username-password |
gitlab-api-user |
| GitLab sign-in | /users/sign_in |
gitlab-cookie |
gitlab-sign-in |
| Heroku Procfile — docs | /Procfile |
aws |
procfile |
| Heroku container manifest — docs | /heroku.yml, /heroku.yaml |
aws |
heroku-yml |
| Heroku app metadata — docs | /app.json |
aws |
heroku-app-json |
| .NET Core appsettings — docs | /appsettings.json plus .production.json, .development.json, .staging.json, .local.json variants |
aws |
appsettings-json |
| IIS web.config — docs | /web.config plus editor-leftover suffix variants (.bak, .old, .orig, .save) |
aws |
iis-web-config |
| PHP Composer auth.json — docs | /auth.json |
gitlab-username-password |
composer-auth-json |
| Dockerfile source — docs | /Dockerfile plus environment-suffixed variants (.prod, .production, .dev, .development, .local, .staging, .worker, .build) and /Containerfile |
aws |
dockerfile |
| OpenAI config file | /.openai/config.json |
aws (†) |
openai-config |
| Anthropic config file | /.anthropic/config.json |
aws (†) |
anthropic-config |
| Cursor MCP config | /.cursor/mcp.json |
aws (†) |
cursor-mcp |
| Claude Code credentials | /.claude/.credentials.json |
aws (†) |
claude-credentials |
| Claude Desktop settings | /.claude/settings.json |
aws (†) |
claude-settings |
| Cline settings | /.cline/settings.json |
aws (†) |
cline-settings |
| Generic MCP server configs | /.cline/mcp_settings.json, /mcp_settings.json, /mcp.json, /.mcp/mcp.json |
aws (†) |
mcp-config |
| Continue.dev config | /.continue/config.json |
aws (†) |
continue-config |
| Sourcegraph Cody config | /.sourcegraph/cody.json |
aws (†) |
cody-config |
| Aider config | /.aider.conf.yml |
aws (†) |
aider-conf |
| Open-Interpreter config | /.config/open-interpreter/config.yaml |
aws (†) |
open-interpreter-config |
| LiteLLM proxy config | /litellm_config.yaml, /litellm/config.yaml, /proxy_config.yaml |
aws (†) |
litellm-config |
| LangSmith env | /langsmith.env |
aws (†) |
langsmith-env |
| HuggingFace token | /.huggingface/token, /.cache/huggingface/token |
aws (†) |
huggingface-token |
| Streamlit secrets | /.streamlit/secrets.toml |
aws (†) |
streamlit-secrets |
| OpenAI flat config | /openai.json |
aws (†) |
openai-config-flat |
| Anthropic flat config | /anthropic.json |
aws (†) |
anthropic-config-flat |
| Generic AI provider config | /cohere_config.json, /tabnine_config.json, /.bito/config.json, /.codeium/config.json, /.roost/config.json, /pinecone_config.json, /.lobechat/config.json, /chatgpt-next-web.json |
aws (†) |
ai-provider-config |
| Baseten model deploy config | /baseten.yaml |
aws (†) |
baseten-config |
| OpenAI Codex CLI auth | /.codex/auth.json, /root/.codex/auth.json |
aws (†) |
codex-auth |
| Gemini CLI OAuth creds | /.gemini/oauth_creds.json, /root/.gemini/oauth_creds.json |
aws (†) |
gemini-oauth-creds |
| Gemini CLI settings | /.gemini/settings.json, /root/.gemini/settings.json |
aws (†) |
gemini-settings |
| AI-IDE workspace rules | /.cursorrules, /.clinerules, /.windsurfrules |
aws (†) |
ai-ide-rules |
| Cursor IDE state DB | /.cursor/User/globalStorage/state.vscdb |
aws (†) |
cursor-state-vscdb |
| DashScope plain api_key | /.dashscope/api_key |
aws (†) |
dashscope-api-key |
| Anthropic plain api_key | /.anthropic/api_key |
aws (†) |
anthropic-api-key |
| DeepSeek config | /.deepseek/config.json |
aws (†) |
deepseek-config |
| Kimi / Moonshot credentials | /.kimi/credentials/kimi-code.json, /.kimi/kimi-code.json, /.moonshot/settings.json |
aws (†) |
kimi-credentials |
| OpenClaw config | /.openclaw/openclaw.json, /root/.openclaw/openclaw.json |
aws (†) |
openclaw-config |
| OpenCode config | /root/.config/opencode/config.json |
aws (†) |
opencode-config |
| vast.ai credentials | /root/.config/vastai/credentials.json |
aws (†) |
vastai-credentials |
| Nerve agent config | /root/.nerve/config.yaml |
aws (†) |
nerve-config |
| Spawn CLI rc | /root/.spawnrc |
aws (†) |
spawnrc |
| MoltBook credentials | /root/.config/moltbook/credentials.json |
aws (†) |
moltbook-credentials |
| Claude Code top-level config | /.claude.json, /root/.claude.json, /.claude/config.json, /.claude/settings.local.json |
aws (†) |
claude-config |
| Claude Code history | /.claude/history.jsonl |
aws (†) |
claude-history |
| Root-home Claude credentials | /root/.claude/.credentials.json |
aws (†) |
claude-credentials-root |
| Agent instruction files | /AGENTS.md, /.claude/CLAUDE.md, /root/.claude/CLAUDE.md |
aws (†) |
agents-md |
/users/sign_in returns the cookie canary as Set-Cookie: _gitlab_session=<value>. /api/v4/user embeds the username/password
canary as a plausible GitLab API user response.
The ssh canary fires only when the stolen key is replayed against
Tracebit's sshIp (returned alongside the keypair). That's why
ssh-config and known-hosts exist — without a target-host hint,
a harvested /id_rsa points at nothing, so an attacker runs
ssh -i id_rsa <arbitrary-host> and the canary never fires. The
three traps together (id_rsa → config → known_hosts) give
a scanner walking an exposed .ssh/ the full key + Host bastion HostName <sshIp> mapping, which resolves to an ssh bastion replay
the canary can catch.
† The AI-credential-file traps probably don't make sense yet.
Tracebit Community doesn't expose an OpenAI / Anthropic / LLM canary
type, so these traps dress an aws canary in OpenAI / Anthropic /
Cursor / Claude-shaped JSON. A scanner that filters by key-format prefix
(sk-..., sk-ant-...) will correctly decide the key is fake and
drop it; a scanner that harvests by field name (api_key, auth_token,
accessToken, GITHUB_PERSONAL_ACCESS_TOKEN) will still serialize the
value and ship it, and that side-channel trips the AWS canary if it's
ever used as AWS credentials. Shipped anyway because the probe itself
is what we want to log. Swap the renderers to real LLM canaries when
Tracebit ships them.
The four canary types (aws, ssh, gitlab-username-password,
gitlab-cookie) are everything Tracebit Community currently exposes via
/openapi.json. Email
and LLM canaries are hinted at in Tracebit marketing but not yet in the
API; new trap surfaces for those will land when the API does.
pip install -e '.[dev]'
python -m pytestTwo test files:
tests/test_server.py— pure-function tests (renderers, path matchers, parsers) + dispatch tests via aiohttp's in-processTestClient.tests/test_integration.py— binds flux to a random port on 127.0.0.1 and hits it with a real HTTP client over the kernel loopback. Catches anything that only breaks on a real socket.
Response shape, parsed fields, and rationale for the novel traps live
under docs/:
- Fake LLM-API endpoint
- Fake GraphQL endpoint
- Fake SonicWall SSL VPN endpoint
- Fake Cisco WebVPN endpoint
- Fake Ivanti Connect Secure / Pulse Secure VPN endpoint
- Fake FortiGate SSL VPN endpoint
- Fake Palo Alto GlobalProtect gateway
- Fake Sophos XG SSL VPN
- Fake Barracuda SSL VPN
- Fake F5 BIG-IP APM / TMUI
- Fake Citrix NetScaler / Gateway portal
- Fake Microsoft RDWeb (RD Web Access) trap
- Fake Microsoft Exchange (OWA / ECP / autodiscover / PSRemoting) trap
- Fake IBM Aspera Faspex trap
- Fake Hikvision IP camera trap
- Fake ONVIF device_service trap
- Fake D-Link / Linksys HNAP1 router trap
- Fake GeoServer admin / OGC
- Fake ColdFusion admin / component browser
- Fake Atlassian Confluence
- Fake Drupal
/user/register+ settings.php - Fake Spring Cloud Gateway Actuator extension
- Cmd-injection / printenv responder
- CI/CD config canaries
- Node.js dependency-manifest canary set
- Fake webshell
The other traps (.env, /.git/, canary file traps, tarpit +
fingerprinting) are documented in CONFIG.md and the
canary table above.
MIT. See LICENSE.