@itznotabug/vitepot
v0.0.2
Published
Static-first Vite/VitePress honeypot plugin for serving fake sensitive files to crawlers, scanners, and bots.
Downloads
5,228
Maintainers
Readme
VitePot 🐝
Static-first honeypot plugin for VitePress and other Vite-powered static sites.
VitePot emits realistic-looking sensitive files like /.env, /wp-config.php, /backup.sql, /.git/config,
/vercel.json, and settings.py so noisy crawlers, path probers, and low-effort scanners spend time on bait instead
of your real surface area.
What It Does
- Serves traps from memory in
vitepress dev - Emits real trap files during
vitepress build - Reuses the same trap responses in preview
- Generates syntax-aware fake content for env, PHP, SQL, Git, JSON, JS, YAML, Python, INI, logs, and plain text
- Uses reserved
.testdomains and RFC 5737 test-net IPs so generated data never points to real infrastructure - Supports custom traps with sync content, async content, binary content, and per-trap directory placement
Installation
bun add @itznotabug/vitepotUsage
Quick Start
// .vitepress/config.mts
import { defineConfig } from 'vitepress';
import { vitepot } from '@itznotabug/vitepot';
export default defineConfig({
vite: {
plugins: [
vitepot()
],
},
});That enables the built-in trap set at the site root.
Full Example
import { defineConfig } from 'vitepress';
import { vitepot } from '@itznotabug/vitepot';
export default defineConfig({
vite: {
plugins: [
vitepot({
variants: ['cms-roots', 'archive-roots'],
dirs: ['/legacy'],
custom: [
{
path: '/private.env'
},
{
path: '/secrets.ini', kind: 'ini'
},
{
path: '/credentials.txt',
content: 'admin=disabled\nroot=disabled\n',
},
{
path: '/ai-keys.json',
contentType: 'application/json',
content: async ({ helpers }) =>
JSON.stringify(
{
openai: helpers.fakeOpenAIKey(),
anthropic: helpers.fakeAnthropicKey(),
google: helpers.fakeGoogleAIKey(),
},
null,
2,
),
},
{
path: '/archive.bin',
contentType: 'application/octet-stream',
content: new Uint8Array([0xde, 0xad, 0xbe, 0xef]),
},
],
}),
],
},
});Runtime Model
Dev
During vitepress dev, VitePot registers middleware and serves trap responses directly from memory. No files are
written.
Build
During vitepress build, VitePot generates the trap set and emits static assets into the output bundle. If a trap path
collided with an existing output file, VitePot skips it and logs a warning.
Preview
During preview, the same trap middleware is mounted so local preview behavior stays aligned with the built output.
Built-In Trap Set
The default set includes 43 file traps across:
- leaked env and credential files
- Git and source-control metadata
- WordPress and PHP config files
- SQL dumps and backups
- server config and auth files
- framework and deployment config files
- application logs
Examples:
/.env/.aws/credentials/.git/config/wp-config.php/config.php/backup.sql/web.config/wp-login.php/xmlrpc.php/vercel.json/next.config.js/config/database.yml/settings.py/connectionstrings.config
Placement
Variants
Variants mirror compatible built-in traps into common subpaths.
vitepot({
variants: ['cms-roots'],
});Available presets:
cms-roots→/blog,/site,/wordpressapp-roots→/public,/apiarchive-roots→/backup,/backups,/old
Variant expansion is filtered by trap compatibility. Example: cms-roots expands /wp-config.php, but not /.env.
Explicit Directories
You can also mirror traps into directories you choose:
vitepot({
dirs: ['/legacy', '/staging'],
});API
Plugin Options
interface VitePotOptions {
enabled?: boolean;
variants?: VariantPreset[];
dirs?: string[];
custom?: CustomTrap[];
}enabled
Turns the plugin on or off. Defaults to true.
variants
Adds built-in preset directories for compatible built-in traps.
dirs
Adds explicit extra directories for expansion. Root is always included automatically.
custom
Adds user-defined file traps.
type CustomTrap = {
path: string;
kind?: TrapKind;
content?: string | Uint8Array | Promise<string | Uint8Array> |
((ctx: CustomTrapContext) => string | Uint8Array | Promise<string | Uint8Array>);
contentType?: string;
dirs?: string[];
};Rules:
pathmust start with/- file paths must not end with
/ contentoverrides the built-in generatordirson a custom trap applies only to that trap
Trap Kinds
Built-in generator families map file paths to realistic content shapes:
envwordpressphpsqlgitserverjsonjsyamlpythoninilogtext
If kind is omitted on a custom trap, VitePot infers it from the path.
Fake Data Helpers
Custom content factories receive deterministic helpers:
helpers.fakeDomain() // calmrouter.test
helpers.fakeEmail() // [email protected]
helpers.fakeHostname() // db-3.calmrouter.test
helpers.fakeTestNetIPv4() // 192.0.2.15
helpers.fakeMysqlPassword() // strong fake password
helpers.fakeApiToken() // generic token
helpers.fakePhpSecret() // 64-char hex secret
helpers.fakeJwtLikeSecret() // JWT-like secret
helpers.fakeCloudKey() // AWS-style access key
helpers.fakeTimestamp() // ISO timestamp
helpers.fakeOpenAIKey() // sk-proj-...
helpers.fakeAnthropicKey() // sk-ant-api...
helpers.fakeGoogleAIKey() // AIzaSy...
helpers.fakeHuggingFaceToken() // hf_...
helpers.fakeStripeKey() // sk_live_...
helpers.fakeSupabaseKey() // JWT-like Supabase key
helpers.fakeClerkKey() // sk_live_...
helpers.fakeVercelToken() // Vercel-style token
helpers.fakeSentryDSN() // https://[email protected]/123All generated domains use the reserved .test TLD, and all generated IPs use RFC 5737 test-net ranges.
Development
bun install
bun run check
bun test
bun run typecheck
bun run build