driftnet@r1
CAUTION· install onlyPublisher claims: "A local catalogue of the AI tools people share in group chats: search it, save links, vote out junk, and file items into your own folders. Works with any model or none." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Nothing executable in the bundle ran; the trace covers the install step only.- Tested
- every file read, file written and host contacted by what ran
- Not tested
- use of the skill by an agent
What this means for the label: Caution here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
ANTHROPIC_API_KEYDRIFTNET_DIGEST_TOKENSDRIFTNET_EMBED_API_KEYDRIFTNET_LLM_API_KEYDRIFTNET_TOKENDRIFTNET_VERTEX_CREDENTIALSDRIFTNET_WEBHOOK_ALLOW_LOCALDRIFTNET_WEBHOOK_SECRETDRIFTNET_WEBHOOK_URLGEMINI_API_KEYGITHUB_TOKENGOOGLE_APPLICATION_CREDENTIALSOPENAI_API_KEYTYPESAFE_API_KEYConfiguration, not credentials: AWS_DEFAULT_REGION, AWS_REGION, CHROME, DEMO_DB, DEMO_ITEMS, DEMO_LANG, DRIFTNET_ACCESS, DRIFTNET_AGENT, DRIFTNET_ALLOW_PRIVATE_URLS, DRIFTNET_ALLOWED_HOSTS, DRIFTNET_BLOCK_DOMAINS, DRIFTNET_CATEGORIES, DRIFTNET_CLI_CONCURRENCY, DRIFTNET_CLI_PATH, DRIFTNET_CLOUDFLARED, DRIFTNET_DB, DRIFTNET_DIGEST, DRIFTNET_DIGEST_AT, DRIFTNET_DIGEST_DAY, DRIFTNET_DIGEST_TO, DRIFTNET_EMBED, DRIFTNET_EMBED_BASE_URL, DRIFTNET_EMBED_FLOOR, DRIFTNET_EMBED_MODEL, DRIFTNET_EMBED_PROVIDER, DRIFTNET_FOLDERS- Where it talks to
- no vendor host named in the codeAlso apple.com, typesafe.ai, youtube.com, githubusercontent.com, facebook.com — not the publisher's domain; check what for before connecting.
- What the honeypot saw
- no credential files read · no network
- What we could not test
- use of the skill by an agent
Connect it with a scoped credential, under the guard, and read the third-party hosts first. The code names apple.com, typesafe.ai, youtube.com, githubusercontent.com, facebook.com as well as its own vendor. The guard injects ANTHROPIC_API_KEY, DRIFTNET_DIGEST_TOKENS, DRIFTNET_EMBED_API_KEY, DRIFTNET_LLM_API_KEY, DRIFTNET_TOKEN, DRIFTNET_VERTEX_CREDENTIALS, DRIFTNET_WEBHOOK_ALLOW_LOCAL, DRIFTNET_WEBHOOK_SECRET, DRIFTNET_WEBHOOK_URL, GEMINI_API_KEY, GITHUB_TOKEN, GOOGLE_APPLICATION_CREDENTIALS, OPENAI_API_KEY, TYPESAFE_API_KEY only into requests to the host you bind (and its subdomains) and refuses the rest.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is driftnet@r1 safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (1 scenario; nothing executable in the bundle ran; the trace covers the install step only) on 2026-11-13 and scored it 63/100 (Caution). It is not known to be malicious, but it has behaviour or code a security policy should decide on before install. Notable findings: Access to sensitive file paths; Access to sensitive file paths; Access to sensitive file paths. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 0 s · 1 scenarios · 0 deviationsStatic findings
const where = `settings: ${c.envFile ?? `none (${join(home, ".env")} not created yet)`}\ndata: ${c.env.DRIFTNET_DB ?? join(home, "driftnet.db")}`;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."start": "tsx --env-file-if-exists=../../.env src/main.ts",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* machine can already read ~/.driftnet/.env, so it may set or reset the adminFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…ied (${keys.join(", ")}). Add the ones you want to ${join(driftnetHome(c.env), ".env")}${flags["print-settings"] ? "" : "; --print-settings shows them"}.`); i…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const merged: NodeJS.ProcessEnv = { ...env };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."mcp": "tsx --env-file-if-exists=../../.env src/mcp-stdio.ts"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary><b>Other ways to run it: from source, Docker</b></summary> From source, to hack on it or run it as a login service: ```bash git clone https://github.coFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.if (!existsSync(file)) return { env: { ...env } };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const m = await writeBackupFile({ dbPath: dbFileOf(c.env), envFile: join(driftnetHome(c.env), ".env"), version: currentVersion(c.env), secrets }, out);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** The environment with ~/.driftnet/.env merged under it (shell wins). */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** Real environment first, then DRIFTNET_HOME/.env: the same precedence the server uses. Never mutates `env`. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."dev": "tsx watch --env-file-if-exists=../../.env src/main.ts",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* network (and could pick up a different version). Not a global install: that may need sudo andFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.const file = join(driftnetHome(env), ".env");Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.writeFileSync(join(home, ".env"), [`PORT=${port}`, "DRIFTNET_JUDGE=off", `DRIFTNET_LANGUAGE=${lang === "zh-TW" ? "Traditional Chinese (Taiwan)" : "English"}`].join("\n") + "\n");Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* Not `npx driftnet`: the npx cache can be cleaned at any time, and re-fetching at login needs theFix: Pin versions and sources; vendor anything fetched at install time.const MARK = "managed by `driftnet service`; change it with `npx driftnet service install|uninstall`";Fix: Pin versions and sources; vendor anything fetched at install time.* Load DRIFTNET_HOME/.env into `env`. Variables already set win, so a shellFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.throw new UsageError(`driftnet service supports macOS, Linux and Windows (this is ${e.platform}); run \`npx driftnet\` from your own startup script instead`);Fix: Pin versions and sources; vendor anything fetched at install time.this.file = join(driftnetHome(env), ".env");Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.Settings: ${home}/.env, or ⚙ Settings on the page. Data: ${home}/driftnet.db.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.console.error(`Port ${PORT} is already in use. Is driftnet already running? Open http://localhost:${PORT}, or set PORT in ${driftnetHome(env)}/.env.`);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const via = remote ? (client === "claude-desktop" ? "remote via mcp-remote bridge" : `remote ${remote.url}`) : "local, npx -y driftnet mcp";Fix: Pin versions and sources; vendor anything fetched at install time.const file = join(driftnetHome(env), ".env");Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.` Set DRIFTNET_TOKEN=<a long password> in ${driftnetHome(env)}/.env (or in the environment), or keep DRIFTNET_HOST on 127.0.0.1.`,Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.- Data lives in ~/.driftnet/ (driftnet.db is the catalogue, .env the settings). DRIFTNET_HOME moves it.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.npx driftnet --version print the version (also -v)Fix: Pin versions and sources; vendor anything fetched at install time.DRIFTNET_LLM_API_KEY, DRIFTNET_LLM_BASE_URL. See .env.example. Without a model, links are savedFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.Settings, or to edit ~/.driftnet/.env themselves: DRIFTNET_LLM_PROVIDER (anthropic, openai for anyFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.Tell them to enter it in Settings or edit ~/.driftnet/.env themselves.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.`tip: Ollama is running locally. To summarise without any cloud model, add to ${driftnetHome(env)}/.env:\n` +Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** Wires everything from environment variables. See .env.example. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.3. Connect this agent: `npx -y driftnet init --yes`. It detects Claude Code, Claude Desktop, Cursor,Fix: Pin versions and sources; vendor anything fetched at install time.if (cmd === "service") console.log("\n install also updates: `npx driftnet@latest service install`. --dry-run prints what would be written and run.");Fix: Pin versions and sources; vendor anything fetched at install time.3. Run: `npx -y driftnet init --remote <URL> --token <TOKEN> --yes`. It writes an HTTP entryFix: Pin versions and sources; vendor anything fetched at install time.- To stop: press Ctrl+C in the terminal running it, or kill the `npx driftnet` process.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.for (const f of ["LICENSE", ".env.example"]) cpSync(join(root, f), join(out, f));Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.client: "claude-code", state: "add", detail: `claude mcp add driftnet --scope user (${remote ? `remote ${remote.url}` : "local, npx -y driftnet mcp"})`,Fix: Pin versions and sources; vendor anything fetched at install time.npx driftnet mcp run as a local MCP server for agents (Claude Code, pi, Hermes…)Fix: Pin versions and sources; vendor anything fetched at install time.// `npx driftnet` — one command, no clone: the web page, chat bots and MCP.Fix: Pin versions and sources; vendor anything fetched at install time.const head = src.replace(/^/, "").trimStart();Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.if (!env.DRIFTNET_SERVICE && process.stdout.isTTY) console.log("Tip: `npx driftnet service install` starts driftnet at login");Fix: Pin versions and sources; vendor anything fetched at install time.files: ["dist", "public", "examples", "skills", ".env.example", "README.zh-TW.md"],Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.npx driftnet start the web page (http://localhost:8787) and any chat bots you set upFix: Pin versions and sources; vendor anything fetched at install time.- To stop: press Ctrl+C in the terminal running it, or kill the `npx driftnet` process.Fix: Pin versions and sources; vendor anything fetched at install time.`npx -y driftnet search <word>`. An empty result is fine; an error is not.Fix: Pin versions and sources; vendor anything fetched at install time.* U+200D (zero-width joiner) is kept: emoji such as 🙅🏻♀️ are built with it.Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.? this.db.prepare("UPDATE notes SET title = ?, body = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id = ? RETURNING *").get(title, body, input.id)Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.client: "codex", state, detail: `${file} (${remote ? `remote ${remote.url}` : "local, npx -y driftnet mcp"})`,Fix: Pin versions and sources; vendor anything fetched at install time.console.log(`settings: ${envFile ?? `none (create ${driftnetHome(env)}/.env, or open the page's ⚙ Settings)`} data: ${env.DRIFTNET_DB ?? defaultDbPath(env)}`);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.2. Start driftnet in the background: `npx -y driftnet@latest`. (Or ask the human to run it in aFix: Pin versions and sources; vendor anything fetched at install time.this.db.prepare("INSERT INTO agent_tokens (id, name, scope, hash) VALUES (?, ?, ?, ?)").run(id, name, input.scope, hashToken(token));Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.const DOWN_HINT = "no driftnet server answered. Start it with `npx driftnet` (or point at one with --url / DRIFTNET_URL).";Fix: Pin versions and sources; vendor anything fetched at install time.…?|secrets?|credentials|conversation|chat history|memory|environment variables?|\.env)\b/i, /\b(do not|don'?t|never) (tell|inform|mention|reveal|show|let)\b.{0,30}…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const old = this.db.prepare("SELECT id, title, summary, category, user_placed FROM items WHERE url = ?").get(input.url) as Record<string, unknown> | undefined;Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.ctx.out(`not running at ${c.url} (start it with \`npx driftnet\`)\n${where}`);Fix: Pin versions and sources; vendor anything fetched at install time.if (changed.size && !remote) ctx.out("The local MCP server opens ~/.driftnet directly; run `npx driftnet` too for the web page and chat bots.");Fix: Pin versions and sources; vendor anything fetched at install time.writeFileSync(join(home, ".env"), `PORT=${port}\nDRIFTNET_JUDGE=off\nDRIFTNET_LANGUAGE=${t.language}\n`);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const p = spawn(tsx, ["--eval", code], { cwd: SERVER, stdio: ["ignore", "ignore", "inherit"], env: { ...process.env, DEMO_DB: join(home, "driftnet.db"), DEMO_LANG: lang, ...env } });Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* Updating is `npx driftnet@latest service install` (re-install replaces everything).Fix: Pin versions and sources; vendor anything fetched at install time.const s = src.replace(/^/, "");Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent./** Rewrite only the changed lines of ~/.driftnet/.env; comments and other settings stay. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.</style><div><div class=logo>${logoSvg}</div><h1>driftnet</h1><div class=tag>${t.tagline}</div><div class=cmd><i>$</i> npx driftnet</div><div class=ag>${t.agent}</div></div>`;Fix: Pin versions and sources; vendor anything fetched at install time.// node scripts/build-npm.mjs && (cd dist/npm && npm pack) # try it: npx ./driftnet-x.y.z.tgzFix: Pin versions and sources; vendor anything fetched at install time.Phone triptych for the README. Run apps/server/e2e/web.mjs with SCREENSHOTS=<dir>, put this file in that dir, replace LANG and CAP1-3, screenshot at 1240x900 @2Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.can write the summaries ([Agents](docs/agents.md)). To connect the AI apps on this computer (Claude Code,Fix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.Composes the README extension screenshot. Run apps/chrome-extension/e2e.mjs with SCREENSHOTS=<dir> (and SHOT_LANG), replace SHOTS and LANG below, then screenshoFix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.this.db.prepare("INSERT INTO pair_codes (hash, name, scope, expires_at) VALUES (?, ?, ?, ?)").run(hashToken(code), name, input.scope, expiresAt);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.Cost to the agent
Tokens estimated at four characters each. Skills load their instruction text when triggered; the figure is what that costs.
Known vulnerabilities
Vulnerability advisories (OSV) cover npm and PyPI packages; this registry has no advisory database.
What would make this Verified
17 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Unclaimed publisher≈ +8 on the totalClaim kevinchu1110: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- Hidden instructions≈ +6 on the totalRemove HTML comments, zero-width characters and white-on-white text that carry instructions. Everything the agent is meant to read should be visible to the person reading the file.
- Access to sensitive file paths≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Privileged sudo command≈ +4 on the totalBuild commands from fixed arguments; do not interpolate untrusted strings into a shell.
- Hidden zero-width characters detected≈ +4 on the totalKeep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.
- npx invocation of non-well-known package≈ +2 on the totalPin versions and sources; vendor anything fetched at install time.