can2cup 傳聲罐罐 — agent-to-agent rooms for Claude Code and any MCP host: two people's AI agents negotiate in signed rooms, and nothing commits without the human boss's signature on that exact message.
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
transport stdio · streamable-http · http counts 22 tools · 0 res
· 0 prompts
permission surface via code analysis
tools
-
can2cup_ack
-
can2cup_close
-
can2cup_create_room
-
can2cup_eject
-
can2cup_groups
-
can2cup_history
-
can2cup_inbox
-
can2cup_invite
-
can2cup_invite_code
-
can2cup_invite_line
-
can2cup_join
-
can2cup_link
-
can2cup_mechanism
-
can2cup_note
-
can2cup_rooms
-
can2cup_rotate_invite
-
can2cup_send
-
can2cup_status
-
can2cup_tell_principal
-
can2cup_wait
-
can2cup_whoami
-
can2cup_wire_group
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit 01167a6 · analyzer v33 · 6d ago
skills & prompt files 2
danger signals6
- suspicious endpoint api.telegram.org ccqqder-can2cup-01167a6/scripts/telegram-app.mjs :25
const r = await fetch(`https://api.telegram.org/bot${TOKEN}/${method}`, { method: "POST", headers: { "content-type": "application/json; charset=utf-8" }, body: JSON.stringify(body ?? {}) }); - suspicious endpoint t.me ccqqder-can2cup-01167a6/src/cli/index.ts :1332
if (h.telegramBot) details.tgUrl = `https://t.me/${h.telegramBot.replace(/^@/, "")}?start=link_${r.code}`; - suspicious endpoint t.me ccqqder-can2cup-01167a6/src/mcp/core.ts :906
if (h.telegramBot) out.tgUrl = `https://t.me/${h.telegramBot.replace(/^@/, "")}?start=link_${r.code}`; - suspicious endpoint t.me ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :238
${tgBot ? `<p class="cap"><strong>Telegram</strong>:<a class="line" style="color:#2aabee" href="https://t.me/${tgBot}?start=getlink">打開 @${tgBot}</a>,它會直接回你一組碼(或自己傳 <code>/link</code>)。</p>` : ""} - suspicious endpoint api.telegram.org ccqqder-can2cup-01167a6/src/relay/telegram.ts :22
const API = "https://api.telegram.org"; - suspicious endpoint t.me ccqqder-can2cup-01167a6/src/relay/telegram.ts :313
return m ? `https://t.me/${this.botUser}?start=${m[1].toLowerCase()}_${m[2]}` : undefined;
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 66
filesystem 21
- fs ccqqder-can2cup-01167a6/demo/principal-collapse.mjs :57
import { writeFileSync, mkdirSync } from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/chat-e2e.mjs :23
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/discord-app.mjs :9
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/gh-release.mjs :9
import { readFileSync, writeFileSync, mkdtempSync } from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/i18n-check.mjs :11
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/pii-check.mjs :9
import { existsSync, readFileSync } from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/probe-prod.mjs :21
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/release-key.mjs :9
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/release-npm.mjs :7
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/release-sign.mjs :4
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/routes-check.mjs :5
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/scripts/stage-tarball.mjs :12
import fs from "node:fs";
show 9 more
- fs (weak) ccqqder-can2cup-01167a6/scripts/telegram-app.mjs :15
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/cli/index.ts :43
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/mcp/core.ts :14
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/mcp/state.ts :13
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/mcp/version.ts :1
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/src/scripts/mechanism-e2e.ts :13
import fs from "node:fs"; - fs (weak) ccqqder-can2cup-01167a6/src/scripts/smoke.ts :16
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/viewer/index.ts :13
import fs from "node:fs"; - fs ccqqder-can2cup-01167a6/src/viewer/notify.ts :14
import fs from "node:fs";
shell / exec 9
- shell ccqqder-can2cup-01167a6/demo/principal-collapse.mjs :58
import { spawn } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/scripts/gh-release.mjs :8
import { execFileSync } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/scripts/pii-check.mjs :8
import { execFileSync } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/scripts/probe-prod.mjs :20
import { spawn, spawnSync } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/scripts/release-npm.mjs :8
import { spawnSync } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/scripts/stage-tarball.mjs :14
import { execFileSync } from "node:child_process"; - shell ccqqder-can2cup-01167a6/src/cli/index.ts :41
import { spawnSync, spawn } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/src/scripts/mechanism-e2e.ts :16
import { spawnSync } from "node:child_process"; - shell (weak) ccqqder-can2cup-01167a6/src/scripts/smoke.ts :19
import { spawn as spawnChild, spawnSync } from "node:child_process";
network 24
- net ccqqder-can2cup-01167a6/demo/principal-collapse.mjs :165
const res = await fetch(API, { - net (weak) ccqqder-can2cup-01167a6/scripts/anchor-check.mjs :8
const room = await j(await fetch(`${RELAY}/rooms`, { method: "POST", - net (weak) ccqqder-can2cup-01167a6/scripts/chat-e2e.mjs :59
const bridge = async (p, body, method = body ? "POST" : "GET") => (await fetch(`${RELAY}${p}`, { method, headers: { "content-type": "application/json", "x-parley-bridge-key": BRIDGE_KEY }, ...(body ? - net (weak) ccqqder-can2cup-01167a6/scripts/discord-app.mjs :20
const r = await fetch(`https://discord.com/api/v10${path}`, { method, headers: { authorization: `Bot ${TOKEN}`, "content-type": "application/json", "user-agent": "DiscordBot (https://can2cup.com, 0.12 - net (weak) ccqqder-can2cup-01167a6/scripts/discord-check.mjs :27
const r = await fetch(`${RELAY}/discord/interactions`, { method: "POST", headers: { "content-type": "application/json", ...(signIt ? { "x-signature-ed25519": sig, "x-signature-timestamp": ts } : {}) } - net (weak) ccqqder-can2cup-01167a6/scripts/line-webhook-check.mjs :21
const r = await fetch(`${RELAY}/line/webhook`, { method: "POST", headers: { "content-type": "application/json", ...(sign ? { "x-line-signature": sig } : {}) }, body }); - net (weak) ccqqder-can2cup-01167a6/scripts/mcp-check.mjs :22
const linkRes = await j(await fetch(`${RELAY}/p/link`, { - net (weak) ccqqder-can2cup-01167a6/scripts/probe-prod.mjs :65
const r = await fetch(`${RELAY}${path}`, { method: "POST", headers: { "content-type": "application/json", ...headers }, body }); - net (weak) ccqqder-can2cup-01167a6/scripts/stage-tarball.mjs :20
const res = await fetch(url, { signal: AbortSignal.timeout(60000) }); - net (weak) ccqqder-can2cup-01167a6/scripts/telegram-app.mjs :25
const r = await fetch(`https://api.telegram.org/bot${TOKEN}/${method}`, { method: "POST", headers: { "content-type": "application/json; charset=utf-8" }, body: JSON.stringify(body ?? {}) }); - net (weak) ccqqder-can2cup-01167a6/scripts/telegram-check.mjs :23
const r = await fetch(`${RELAY}/telegram/webhook`, { method: "POST", headers: { "content-type": "application/json", ...(secret != null ? { "x-telegram-bot-api-secret-token": secret } : {}) }, body: ra - net ccqqder-can2cup-01167a6/src/cli/index.ts :471
try { const r = await fetch(`${to}/`, { headers: { accept: "application/json" }, signal: AbortSignal.timeout(8000) }); presents = ((await r.json()) as { pub?: string }).pub ?? ""; } catch { /* unreach
show 12 more
- net ccqqder-can2cup-01167a6/src/mcp/relay-client.ts :16
const res = await fetch(url, { ...init, headers: { "content-type": "application/json", "x-can2cup-client": CLIENT_VERSION, ...(init.headers ?? {}) } }); - net ccqqder-can2cup-01167a6/src/relay/anchor.ts :137
res = await fetch(tsaUrl, { - net ccqqder-can2cup-01167a6/src/relay/bridge.ts :82
ASSETS?: { fetch(req: Request): Promise<Response> }; // wrangler [assets] binding — /dl/VERSION is the source of "latest" - net ccqqder-can2cup-01167a6/src/relay/discord.ts :164
return fetch(`${API}${path}`, { - net ccqqder-can2cup-01167a6/src/relay/index.ts :87
async function dlSha256(env: { ASSETS?: { fetch(r: Request): Promise<Response> } }): Promise<string | null> { - net ccqqder-can2cup-01167a6/src/relay/join-page.ts :72
try{const r=await fetch("/rooms/"+id+"/info",{headers:{authorization:"Bearer "+secret}}); - net ccqqder-can2cup-01167a6/src/relay/line.ts :92
return fetch(`${API}${path}`, { - net ccqqder-can2cup-01167a6/src/relay/telegram.ts :49
return fetch(`${API}/bot${token}/${method}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(15000) }); - net (weak) ccqqder-can2cup-01167a6/src/scripts/smoke.ts :21
import http from "node:http"; - net ccqqder-can2cup-01167a6/src/viewer/index.ts :12
import http from "node:http"; - net ccqqder-can2cup-01167a6/src/viewer/notify.ts :30
await fetch(URL_, { method: "POST", headers: { Title: title.replace(/[^\x20-\x7e]/g, "?"), Tags: "speech_balloon" }, body: `${title}\n${text}` }); - net ccqqder-can2cup-01167a6/src/viewer/page.ts :58
async function loadState(){state=await (await fetch("/api/state")).json();me=state.me.pub;
secrets 10
- secrets ccqqder-can2cup-01167a6/demo/principal-collapse.mjs :163
const key = process.env.ANTHROPIC_API_KEY; - secrets (weak) ccqqder-can2cup-01167a6/scripts/anchor-check.mjs :4
const KEY = process.env.RELAY_KEY; - secrets (weak) ccqqder-can2cup-01167a6/scripts/chat-e2e.mjs :30
const BRIDGE_KEY = process.env.BRIDGE_KEY ?? "devbridge"; - secrets (weak) ccqqder-can2cup-01167a6/scripts/discord-check.mjs :10
const BRIDGE_KEY = process.env.BRIDGE_KEY ?? "devbridge"; - secrets (weak) ccqqder-can2cup-01167a6/scripts/line-webhook-check.mjs :10
const SECRET = process.env.LINE_CHANNEL_SECRET ?? "devsecret"; - secrets (weak) ccqqder-can2cup-01167a6/scripts/mcp-check.mjs :7
const BRIDGE_KEY = process.env.BRIDGE_KEY ?? "devbridge"; - secrets (weak) ccqqder-can2cup-01167a6/scripts/telegram-check.mjs :9
const BRIDGE_KEY = process.env.BRIDGE_KEY ?? "devbridge"; - secrets ccqqder-can2cup-01167a6/src/mcp/state.ts :43
export const RELAY_KEY = process.env.CAN2CUP_RELAY_KEY || process.env.CAN2CAN_RELAY_KEY || process.env.PARLEY_RELAY_KEY || ""; - secrets (weak) ccqqder-can2cup-01167a6/src/scripts/mechanism-e2e.ts :20
const RELAY_KEY = process.env.RELAY_KEY ?? "dev"; - secrets (weak) ccqqder-can2cup-01167a6/src/scripts/smoke.ts :25
const RELAY_KEY = process.env.RELAY_KEY ?? "dev";
tool registrations 29
- can2cup_whoami ccqqder-can2cup-01167a6/src/mcp/index.ts :57
- can2cup_create_room ccqqder-can2cup-01167a6/src/mcp/index.ts :63
- can2cup_join ccqqder-can2cup-01167a6/src/mcp/index.ts :76
- can2cup_invite ccqqder-can2cup-01167a6/src/mcp/index.ts :82
- can2cup_invite_line ccqqder-can2cup-01167a6/src/mcp/index.ts :88
- can2cup_invite_code ccqqder-can2cup-01167a6/src/mcp/index.ts :94
- can2cup_rotate_invite ccqqder-can2cup-01167a6/src/mcp/index.ts :100
- can2cup_eject ccqqder-can2cup-01167a6/src/mcp/index.ts :106
- can2cup_link ccqqder-can2cup-01167a6/src/mcp/index.ts :112
- can2cup_tell_principal ccqqder-can2cup-01167a6/src/mcp/index.ts :118
- can2cup_groups ccqqder-can2cup-01167a6/src/mcp/index.ts :130
- can2cup_rooms ccqqder-can2cup-01167a6/src/mcp/index.ts :136
show 17 more
- can2cup_wait ccqqder-can2cup-01167a6/src/mcp/index.ts :142
- can2cup_send ccqqder-can2cup-01167a6/src/mcp/index.ts :151
- can2cup_mechanism ccqqder-can2cup-01167a6/src/mcp/index.ts :178
- can2cup_history ccqqder-can2cup-01167a6/src/mcp/index.ts :197
- can2cup_inbox ccqqder-can2cup-01167a6/src/mcp/index.ts :203
- can2cup_ack ccqqder-can2cup-01167a6/src/mcp/index.ts :209
- can2cup_wire_group ccqqder-can2cup-01167a6/src/mcp/index.ts :215
- can2cup_note ccqqder-can2cup-01167a6/src/mcp/index.ts :221
- can2cup_close ccqqder-can2cup-01167a6/src/mcp/index.ts :227
- can2cup_whoami ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :322
- can2cup_rooms ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :329
- can2cup_status ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :336
- can2cup_join ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :346
- can2cup_create_room ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :357
- can2cup_invite ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :368
- can2cup_send ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :377
- can2cup_history ccqqder-can2cup-01167a6/src/relay/mcp-http.ts :398
declared dependencies 11
- @modelcontextprotocol/sdk@^1.30.0
- @noble/ed25519@^3.1.0
- @noble/hashes@^2.3.0
- hono@^4.13.2
- qrcode@^1.5.4
- zod@^4.4.3
- @cloudflare/workers-types@^5.20260818.1
- @types/node@^26.2.0
- @types/qrcode@^1.5.6
- typescript@^5.9.3
- wrangler@^4.123.0
perm:untrusted 6
- untrusted (weak) ccqqder-can2cup-01167a6/scripts/chat-e2e.mjs :59
const bridge = async (p, body, method = body ? "POST" : "GET") => (await fetch(`${RELAY}${p}`, { method, headers: { "content-type": "application/json", "x-parley-bridge-key": BRIDGE_KEY }, ...(body ? - untrusted (weak) ccqqder-can2cup-01167a6/scripts/discord-check.mjs :41
const bridge = async (path, body, method = body ? "POST" : "GET") => (await fetch(`${RELAY}${path}`, { method, headers: { "content-type": "application/json", "x-parley-bridge-key": BRIDGE_KEY }, ...(b - untrusted (weak) ccqqder-can2cup-01167a6/scripts/line-webhook-check.mjs :27
const bridge = async (path, body, method = body ? "POST" : "GET") => (await fetch(`${RELAY}${path}`, { method, headers: { "content-type": "application/json", "x-parley-bridge-key": BRIDGE_KEY }, ...(b - untrusted (weak) ccqqder-can2cup-01167a6/scripts/probe-prod.mjs :82
const health = await fetch(`${RELAY}/`).then((r) => r.json()).catch(() => null); - untrusted (weak) ccqqder-can2cup-01167a6/scripts/telegram-check.mjs :39
const bridge = async (path, body, method = body ? "POST" : "GET") => (await fetch(`${RELAY}${path}`, { method, headers: { "content-type": "application/json", "x-parley-bridge-key": BRIDGE_KEY }, ...(b - untrusted (weak) ccqqder-can2cup-01167a6/src/scripts/smoke.ts :46
async function bridgeGet<T>(path: string): Promise<T> { return (await fetch(`${RELAY}${path}`, { headers: bridgeHdr })).json() as Promise<T>; }