0n-decoy
Deception for APIs that AI agents and scanners attack. Zero dependencies.
Real defences keep attackers out. 0n-decoy adds the layer that wastes their time and tells you they came:
| What it does | |
|---|---|
| Honey paths | /secure-keys, /api/vault/export, /.env, /.git/config, /wp-login.php, /api/internal/… (plus robotsLures() for robots.txt, and your own private ones via extraHoney) — no real client asks for these. A hit flags the address for 24 h. |
| Canary tokens | Look exactly like your real tokens. Recognised without a database: the token carries an HMAC tag only your secret can produce. Plant them anywhere (docs, CRM notes, repos); any use is a critical alert naming where it leaked from. |
| Decoy world | Believable JSON and config files full of canary credentials and "internal notes" that lead an automated agent to more honey paths. |
| Tarpit | Flagged addresses get slow answers. Brute force — many different bad tokens — gets the decoy world. One stale token retried forever does not. |
It never feeds fake data to a request with a valid credential, never changes what real users receive, and never hacks back.
import { createDecoy, middleware } from '0n-decoy';
const decoy = createDecoy({
secret: process.env.DECOY_SECRET, // keep it OUT of your database
host: 'api.example.com',
onEvent: (e) => alertMe(e), // { kind, severity, ip, path, ... }
});
app.use(middleware(decoy, { checkToken: async (t) => !!(await lookUp(t)) }));
const { token } = decoy.mint('planted in the Q3 board doc'); // a canary to plant
guarded: (path) => boolean limits the fake world for flagged addresses to the paths that hand out data, so sign-in pages stay real for people sharing an address.
Personal links and permanent bans (1.4). Pass beaconBase (and optionally hopUrl, an offsite page such as a Google Apps Script web app). Every lure then carries links unique to that visitor. Following one from any address ties that address to the visitor, and both are banned. Bans also follow a canary use, a private trap hit, or a high trap score. neverBan(ip) protects addresses you trust, such as ones that recently used a valid token.
Bring your own store (add banned/ban/remember/recall for bans and links) for multi-instance deployments (get(ip), bump(ip, { weight, flagMinutes, distinct })); memoryStore() is included.
Built for and running on 0n3.