Honeytokens

Honeytokens are fake credentials embedded in the honeypot’s fake responses. When an attacker steals them and later reuses them — even from a different IP, days later — the honeypot detects and alerts on the reuse.

Table of contents

  1. What are honeytokens?
  2. Token format
  3. Where tokens are embedded
  4. Detection
  5. What happens on detection
  6. n8n routing for honeytoken events
  7. Prometheus metric

What are honeytokens?

A honeytoken is a fake credential that looks real enough to fool automated tools, but is unique to the honeypot and functionally useless. The goal is not to protect anything, but to detect post-theft behaviour: did the attacker actually try to use what they stole?

This is high-signal detection. A scanner blindly hitting your honeypot is background noise. An attacker sending back a token they received from your honeypot means:

  • They collected credentials from your fake endpoint
  • They tried to authenticate with them somewhere
  • You now know their attack IP, user agent, and timing

Token format

Every token follows the pattern:

hp_live_{md5(ip + "-" + trap_name)[:20]}

Examples:

  • hp_live_a1b2c3d4e5f6789012ab (from /.env for IP 1.2.3.4)
  • hp_live_f09e8d7c6b5a432109de (from /actuator/env for the same IP)

The hp_live_ prefix is recognizable at a glance. The 20-hex suffix is deterministic per IP + trap, so if an attacker from 1.2.3.4 steals your fake AWS key and then 5.6.7.8 sends it back, you can trace the token back to the original theft.


Where tokens are embedded

Unless the table says otherwise, the “field” is a field in the response body.

Trap Field Token used as
/actuator/env AWS_SECRET_ACCESS_KEY AWS secret key
/.env STRIPE_SECRET_KEY Stripe live key
/.aws/credentials aws_secret_access_key AWS secret key
/api/v*/users/{id} api_key REST API key
/api/v1/api_key api_keys[].api_key Langflow API key
/api/v1/auto_login access_token Langflow SUPERUSER JWT (CVE-2026-9198)
/api/session/properties setup-token Metabase setup token (CVE-2023-38646 chain)
/api/database data[].details.password Password of a connected database (CVE-2026-72898 target)
/p/u/doAuthentication.do <InitialValue> NetScaler session material in fake leaked memory
/global-protect/getconfig.esp <portal-userauthcookie> GlobalProtect portal auth cookie
/.claude/mcp.json and friends env.GITHUB_PERSONAL_ACCESS_TOKEN GitHub PAT in an MCP server config
/.claude/.credentials.json claudeAiOauth.accessToken AI assistant OAuth token
/api/auth/authenticate tokens.access.token N-central admin bearer token
/access/api/v1/tokens access_token Artifactory admin access token (CVE-2026-82329)
/key/generate key LiteLLM virtual key
/key/info keys[].token LiteLLM key listing
/model/info litellm_params.api_key Upstream model-provider key
/api/v4/projects/*/repository/commits gitlab_rails['initial_root_password'] inside the leaked gitlab.rb GitLab root password (CVE-2026-85706)
/api/fmc_platform/v1/auth/generatetoken response header X-auth-access-token Cisco FMC API access token (CVE-2026-20079)
/api/fmc_platform/v1/auth/generatetoken response header X-auth-refresh-token Cisco FMC API refresh token
/api/…/configs (not /api/v1/configs) taskRunList[].outputs.vars.KESTRA_API_TOKEN Kestra worker environment leaked by the injected command (CVE-2026-49869)
/api/v1/*/namespaces/*/kv/* value Kestra namespace KV secret
/ers/config/networkdevice authenticationSettings.radiusSharedSecret Cisco ISE RADIUS shared secret (CVE-2026-76460 target)
/ers/config/internaluser, /ers/config/adminuser password Cisco ISE internal identity-store password
/j_security_check Set-Cookie: JSESSIONID Cisco SD-WAN Manager session (CVE-2026-76504)
/dataservice/client/token response body Cisco SD-WAN Manager CSRF token
/client-registration/* clientSecret WSO2 consumer secret (CVE-2026-5430 target)
/api/am/* endpoint_security.production.password WSO2 backend endpoint password
/~/api/loginSrp1 Set-Cookie: hfs_$id Rejetto HFS session cookie (CVE-2026-61500 target)
/~/api/get_config upload_token Rejetto HFS config credential read with a forged admin session
/app?service=…Setup… Set-Cookie: JSESSIONID PaperCut session after the setup-wizard bypass

They all mimic the format of real credentials that automated scanners and credential-harvesting tools look for specifically.

The Langflow, Metabase, N-central, Artifactory, LiteLLM, FMC, Kestra, ISE, SD-WAN, WSO2, HFS and PaperCut carriers sit on endpoints an attacker reaches through an authentication bypass. The bypass appears to succeed, the attacker replays the token on the next request, and detectHoneytokenInRequest catches it — so the whole chain is observable end to end.

Cisco FMC is the first carrier that lives in a response header rather than a body, because that is where a real FMC puts the credential: the token endpoint answers 204 No Content and returns nothing else. It gets two distinct tokens — one for X-auth-access-token, one for X-auth-refresh-token — so a replayed access token can be told apart from a replayed refresh token when the honeytoken_used event fires.


Detection

The honeypot scans every incoming request for honeytoken reuse:

  1. All request headers — including Authorization: Bearer hp_live_..., X-Api-Key: hp_live_..., Cookie: NSC_AAAC=hp_live_..., and any custom header
  2. Query parameters — e.g. ?api_key=hp_live_...
  3. POST/PUT body — scanned after the standard 8 KB body read
  4. Already-captured API key — from captureAPIKey() which reads X-Api-Key and Authorization

Header, cookie and query values are split on every delimiter that can surround a credential (whitespace, =, &, ;, ,, :, quotes, brackets), so a token pasted into a cookie or a JSON field is still found.

Detection is prefix-based (hp_live_) plus exact length check (28 characters total), so false positives are essentially impossible.


What happens on detection

When a token is detected, the honeypot immediately (before path routing):

  1. Sets attack_tag = "honeytoken-used" and is_honeytoken_use = true
  2. Fires a honeytoken_used webhook event — a separate event type from "attack"
  3. Increments http_honeytokens_used Prometheus counter
  4. Adds the IP to the blacklist log
  5. Reports to AbuseIPDB (if configured)
  6. Logs HONEYTOKEN USED by {ip}: {token} to stdout
  7. Still responds normally — the attacker has no indication they were detected

n8n routing for honeytoken events

Filter on the event field:

Webhook node
  └─ Switch on event
       ├─ "honeytoken_used"  → 🚨 Slack #security-critical + PagerDuty + block IP
       ├─ "attack"           → Normal processing
       └─ "country_notify"   → Pushover (already sent)

To correlate original theft with reuse:

// In n8n Code node
const token = $json.api_key_used;  // e.g. "hp_live_a1b2c3d4e5f6789012ab"
const thiefIP = $json.ip;
// Search your logs for the original request that returned this token
// (it will have the same token in the response body)

Prometheus metric

# Total honeytoken reuse events
http_honeytokens_used

# Rate over last hour
rate(http_honeytokens_used[1h]) * 3600