honeycrawlpot · Documentation

Deception middleware for AI crawlers

honeycrawlpot answers scanner-style probes (/.env, AWS credentials, SSH keys, openapi.json…) with convincing decoys containing fabricated secrets, canary tokens and prompt-injection payloads aimed at LLM-driven agents.

  • Version 0.2.1
  • TypeScript
  • Bun or bundler
  • MIT

Install

bun add honeycrawlpot
# or
npm install honeycrawlpot

No runtime dependencies. Express and Hono are optional peers. The package is ESM-only.

Node support

Fixed in 0.2.1: the 0.2.0 tarball kept extensionless relative imports, so a native Node ESM import failed with ERR_MODULE_NOT_FOUND. The build now emits explicit .js specifiers and CI runs a Node import smoke test. Bun and bundlers were never affected.

Quick start

Hono

import { Hono } from 'hono';
import { honoHoneypot } from 'honeycrawlpot';

const app = new Hono();

app.get('/health', (c) => c.json({ ok: true }));

// after your real routes, before the 404 handler
app.use('*', honoHoneypot({
  onHit: (hit) => console.log('probe', hit.path, hit.category, hit.canary),
}));

app.notFound((c) => c.json({ error: 'not found' }, 404));

Express

import { expressHoneypot } from 'honeycrawlpot';

app.get('/api/health', (_req, res) => res.json({ ok: true }));
app.use(expressHoneypot());
app.use((_req, res) => res.status(404).json({ error: 'not found' }));

Framework-agnostic

import { handleProbe } from 'honeycrawlpot';

const outcome = handleProbe({ method: 'GET', path: '/.env' });
// { status: 200, headers: {...}, body: '…', category: 'env', canary: 'LF-HONEYPOT-…' }

handleProbe only uses the path; method and headers are accepted but ignored. It always answers 200 with X-Honeypot: true, X-Robots-Tag: noindex and the decoy content type.

API

SymbolPurpose
createHoneypot(config)Build an isolated instance with its own canary, brand, domains and secrets.
resolveDecoy(path, options)Return a Decoy (category, contentType, content) or null.
handleProbe(ctx, config?)Decoy plus HTTP status and headers.
honoHoneypot(options) / expressHoneypot(options)Middleware adapters with onHit and extra excludePaths.
HONEYPOT_CANARYCanary of the default instance.

Decoy catalogue

Thirteen categories: env, firebase, aws, sshkey, openapi, graphql, jsonconfig, yamlconfig, pyconfig, jsconfig, php, csv and a generic fallback.

Classification is substring-based on the decoded path, in a fixed order. It covers realistic scanner traffic (/.env.bak, /@fs/.env, /.ssh/id_rsa, /serviceAccountKey.json, /.aws/credentials, /appsettings.Production.json, /wp-config.php, /dashboard, /metrics, /__debug__, /proc/self/environ) but not everything:

Canary tokens

Every decoy body contains a canary such as LF-HONEYPOT-AB12CD34. Search your logs, tickets, model outputs and incident reports for the LF-HONEYPOT- prefix; a hit proves the decoy was ingested.

Pin the value for stable alerting:

export HONEYPOT_CANARY="LF-HONEYPOT-MYSITE-01"
# or per instance
const hp = createHoneypot({ canary: "LF-HONEYPOT-MYSITE-01" });

Without a pinned value, each instance — and each handleProbe call that builds one implicitly — gets a fresh random canary.

Configuration

KeyDefaultNotes
canaryrandomOverrides HONEYPOT_CANARY
excludePaths["health", "api/v1/health"]Exact match, no leading slash, no globs
brand, deploymentAcme, 2.4.1Appear in decoy bodies
domains*.example.comapp, api, pgbouncer, redis, minio, smtp, Firebase project
secretsstatic fake valuesAWS, Stripe, PostgreSQL, JWT, SMTP; inert
databaseapp/app_userUsed in connection strings
extraKeywords[]Lowercase substrings routed to the generic decoy
extraInjections[]Extra prompt-injection blocks

Limitations