agentchannel@3.27.0
CAUTION· startup onlyPublisher claims: "Hand work between your team's agents (Claude Code, Codex) and follow it in one panel: the ach CLI, MCP server and runner for AgentChannel v2" Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Startup only; authenticated tool behavior not tested.- Tested
- server startup over stdio (initialize sent) · every file read, file written and host contacted by what ran
- Not tested
- the tool list (the server exited before answering) · what the tools do when called with real credentials
- Needs
- ACH_KEY, ACH_RUN_TOKEN, ACH_CF_SECRET, --cf-token — give it to the server where it runs, through vet-skills run --secrets, so the value never enters the server's environment. Never paste a credential into a chat, a ticket or a report.
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
ACH_AUTH_EXIT_CODEACH_CF_SECRETACH_RUN_TOKENKIRO_API_KEYor--cf-token/--cf-secretConfiguration, not credentials: ACH_AGENT, ACH_CF_ID, ACH_CHANNEL, ACH_CODEX_BIN, ACH_CODEX_PRICE, ACH_CODEX_THREAD_ID, ACH_DEBUG, ACH_GH_CLI, ACH_HANDOFF_VERSION, ACH_HUB, ACH_KEY, ACH_KEYSTORE, ACH_KIRO_BIN, ACH_KIRO_REPO, ACH_LARK_CLI, ACH_NO_TRACE, ACH_NOTIFIER, ACH_PUBLIC_URL, ACH_SANDBOX_CHECK, ACH_SERVICE_DIR, ACH_SERVICE_PLATFORM, ACH_SESSION_NOTICES, ACH_SYNC_MIN_MS, ACH_TASK_ID, ACH_THREAD_ID, ACH_TRACE_THINKING, AGENTCHANNEL_HOME, ANTHROPIC_MODEL, CLAUDE_CONFIG_DIR, CODEX_HOME, CODEX_SESSION_ID, CODEX_THREAD_ID, DISPLAY, INVOCATION_ID, LC_ALL, LC_MESSAGES- Where it talks to
- no vendor host named in the codeAlso kiro.dev, apple.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
- the tool list (the server exited before answering) · what the tools do when called with real credentials
Connect it with a scoped credential, under the guard, and read the third-party hosts first. The code names kiro.dev, apple.com as well as its own vendor. The guard injects ACH_AUTH_EXIT_CODE, ACH_CF_SECRET, ACH_RUN_TOKEN, KIRO_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 [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (2 scenarios; startup only; authenticated tool behavior not tested) on 2026-11-09 and scored it 65/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; Privileged sudo command. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 65 s · 2 scenarios · 0 deviationsStatic findings
/** A file whose contents are secrets by convention (.env, .npmrc, key files): its content is never put in a trace. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** Refuse files that hold secrets by convention (.env, keys, .npmrc): set for the short read-only runs a mention or a question starts in the real working copy. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** Shell lines to run, in order (sudo included). Empty: there is nothing safe to run; the sentence says what to do. */Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.zypper: (p) => `sudo zypper install -y ${p.join(' ')}`,Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…retFile(path) { const base = path.split(/[\\/]/).pop() ?? ''; return /^\.env(\..*)?$/i.test(base) || /^\.(npmrc|netrc|pypirc)$/i.test(base) || /^id_(rsa|ed2…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** Runs a shell line with this terminal (sudo can ask for a password); the exit code. Absent: sandbox fixes are only printed. */Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.child.on('error', (e) => finish(null, e?.code === 'ENOENT' ? `kiro-cli not found (${bin}): install it (curl -fsSL https://cli.kiro.dev/install | bash) or set ACH_KIRO_BIN` : String(e?.message ?? e)));Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return shim ? { ...env, PATH: `${shim}${delimiter}${env.PATH ?? ''}` } : env;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.* commands that fix it (sudo included), run only after Enter in a terminal;Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.apt: (p) => `sudo apt-get install -y ${p.join(' ')}`,Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell....(linger ? [] : ['Note: it stops when you log out of this machine. To keep it running: sudo loginctl enable-linger "$USER"']),Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.pacman: (p) => `sudo pacman -S --needed --noconfirm ${p.join(' ')}`,Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.let jenv = ownHome ? { ...env, AGENTCHANNEL_HOME: ownHome } : env;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose./** A file whose contents are secrets by convention (.env, .npmrc, key files): its content is never put in a trace. */Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const INSTALL = 'curl -fsSL https://cli.kiro.dev/install | bash';Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.// nothing to run (no safe command for this machine), or no terminal to run sudo in: say what to do and go onFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.dnf: (p) => `sudo dnf install -y ${p.join(' ')}`,Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell./** A shell line with this terminal's stdin/stdout/stderr (sudo asks for its password there); its exit code. */Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.const repo = kiroRepoFor(opts.cwd, { ...env, ...opts.env, ACH_KIRO_REPO: env.ACH_KIRO_REPO }, this.o.git);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.jenv = { ...env, AGENTCHANNEL_HOME: agentHome(me.name, env) };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const npx = runFromNpx(self);Fix: Pin versions and sources; vendor anything fetched at install time.Setup: npx -y @koalaauto/agentchannel@3 join <ach2.invite> [--name <n>] [--service] [--yes] [--dry-run] (run it in theFix: Pin versions and sources; vendor anything fetched at install time./** `npx -y @koalaauto/agentchannel@<spec>`: how messages and MCP entries start the CLI without relying on PATH. */Fix: Pin versions and sources; vendor anything fetched at install time.…e path meanwhile.`, 'machine', `remove it or put this CLI first on PATH (or use npx -y ${npmSpec()} …); see below`); add('fix', 'info', shadowFix(first, a…Fix: Pin versions and sources; vendor anything fetched at install time.out(v.json ? r : `note posted (message ${r?.message?.id ?? '?'})`);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.the join line npx -y @koalaauto/agentchannel@3 join <blob>. Language: --lang, else the hub's (Memory) language.Fix: Pin versions and sources; vendor anything fetched at install time.* From the npx cache the unit runs `npx -y <spec>` (the cache may be cleared;Fix: Pin versions and sources; vendor anything fetched at install time.* Run through npx, the helper runs the same pinned npx spec as the MCPFix: Pin versions and sources; vendor anything fetched at install time.export const JOIN_HINT = 'They paste the line in a terminal (Node 20+); npx fetches the CLI. To type `ach` yourself: `npm i -g ' + PKG_NAME + '`. ' +Fix: Pin versions and sources; vendor anything fetched at install time./** How the MCP entry and service start ach: the pinned npx spec when run through npx, else an absolute `ach`. */Fix: Pin versions and sources; vendor anything fetched at install time.const INSTALL = 'curl -fsSL https://cli.kiro.dev/install | bash';Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.// ACH_AUTO_UPDATE=0 turns the installing off (the log and the session notice remain).Fix: Pin versions and sources; vendor anything fetched at install time.* with npx or `node dist/src/cli.js`). Returns the dir to prepend to PATH.Fix: Pin versions and sources; vendor anything fetched at install time./** `npx -y @koalaauto/agentchannel@<spec>`: how messages and MCP entries start the CLI without relying on PATH. */Fix: Pin versions and sources; vendor anything fetched at install time./** True when this CLI runs from the npx cache (it disappears; install it first). */Fix: Pin versions and sources; vendor anything fetched at install time.* with npx or `node dist/src/cli.js`). Returns the dir to prepend to PATH.Fix: Pin versions and sources; vendor anything fetched at install time.…[]): string; export declare const HELP = "ach - AgentChannel CLI\n\nSetup: npx -y @koalaauto/agentchannel@3 join <ach2.invite> [--name <n>] [--service] [--yes] […Fix: Pin versions and sources; vendor anything fetched at install time.* entry, never a path in the npx cache.Fix: Pin versions and sources; vendor anything fetched at install time.* PATH while `npx agentchannel` runs).Fix: Pin versions and sources; vendor anything fetched at install time.achCmd: npx ? npxAch() : absoluteAch(env, self),Fix: Pin versions and sources; vendor anything fetched at install time.// registered before the SDK spawns codex, so it runs before the SDK's own killFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.export const JOIN_LINE_RE = /^npx -y @koalaauto\/agentchannel@\S+ join (ach2\.\S+)$/;Fix: Pin versions and sources; vendor anything fetched at install time./** The one line a teammate pastes: npx fetches the CLI and `join` sets everything up. */Fix: Pin versions and sources; vendor anything fetched at install time.export declare function sessionDeliverer(server: McpServer, env?: NodeJS.ProcessEnv, exec?: Exec): (text: string) => Promise<boolean>;Fix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.// started by a service written by an early release (node on the npx cache, which no restart ever refreshes): make it `npx -y <spec>`Fix: Pin versions and sources; vendor anything fetched at install time.child.on('error', (e) => finish(null, e?.code === 'ENOENT' ? `kiro-cli not found (${bin}): install it (curl -fsSL https://cli.kiro.dev/install | bash) or set ACH_KIRO_BIN` : String(e?.message ?? e)));Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.* npx cache (`.../_npx/...`) or in a node_modules/.bin (e.g. npx puts thisFix: Pin versions and sources; vendor anything fetched at install time.const kill = o.kill ?? ((pid, sig) => process.kill(pid, sig));Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.…oarding: ach admin import github --org <org> [--since 60d] --dry-run [--out plan.json] (reads GitHub with your gh login; writes a plan)\n ach admin import github --org <org> --link <one-time admin link> [--yes] (the line from the panel's S…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.return spec ? { ok: true, why: `through npx (${spec})` } : { ok: false, why: `npx does not start ${PKG_NAME}` };Fix: Pin versions and sources; vendor anything fetched at install time.out(v.json ? r : `posted ${r.id} in #${r.channel_name ?? hit?.name ?? channelRef(name)}${r.url ? `: ${absUrl(env, r.url)}` : ''}`);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.return s.env.AGENTCHANNEL_HOME || achHome({ ...env, AGENTCHANNEL_HOME: '' });Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return `npx -y ${npmSpec(version)} join ${blob}`;Fix: Pin versions and sources; vendor anything fetched at install time.if (starts || /^[A-Za-z][A-Za-z ]*:\s+npx /.test(line))Fix: Pin versions and sources; vendor anything fetched at install time.// a codex that npx put on PATH (this package's SDK dependency) is not the user's CodexFix: Pin versions and sources; vendor anything fetched at install time./** User-installed claude / codex (never the bins npx puts on PATH). */Fix: Pin versions and sources; vendor anything fetched at install time./** The one line a teammate pastes: npx fetches the CLI and `join` sets everything up. */Fix: Pin versions and sources; vendor anything fetched at install time./** True when this CLI runs from the npx cache (it disappears; install it first). */Fix: Pin versions and sources; vendor anything fetched at install time.add('hub', cfg.hub ? 'ok' : 'fail', cfg.hub ? `${cfg.hub}${env.ACH_HUB ? ' (ACH_HUB)' : ''}` : 'no hub configured', 'hub', `paste the join line from your admin (npx -y ${npmSpec()} join ach2....)`);Fix: Pin versions and sources; vendor anything fetched at install time.apk: (p) => `sudo apk add ${p.join(' ')}`,Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.const word = (w) => new RegExp(`(?:ach|npx -y @koalaauto/agentchannel@3|\\|)\\s+${w.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}(?![\\w-])`);Fix: Pin versions and sources; vendor anything fetched at install time.out(v.json ? m : `${p.cmd} posted`);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why./** Started from the npx cache with a range spec (`@koalaauto/agentchannel@3`): a restart fetches the newest release. */Fix: Pin versions and sources; vendor anything fetched at install time.const run = shellLine([...(home ? [`AGENTCHANNEL_HOME=${home}`] : []), ...(d.npx ? d.achCmd : ['ach']), 'run', '--install-service', ...(desktop ? ['--notify'] : []), '--dir', io.cwd]);Fix: Pin versions and sources; vendor anything fetched at install time.out.push('', `${zh ? '随时检查配置:' : 'Check the setup any time with: '}${shellLine([...(d.npx ? d.achCmd : ['ach']), 'doctor'])}`);Fix: Pin versions and sources; vendor anything fetched at install time./** Install the release. npx needs nothing now (the restart fetches it). A global install is `npm install -g`, scripts off, then read back. */Fix: Pin versions and sources; vendor anything fetched at install time.* an npx install has nothing to go back to and only marks it). Returns what it did; 'rolledback' means: exit UPDATE_EXIT_CODE.Fix: Pin versions and sources; vendor anything fetched at install time.// - A service written by an early release starts node on a file inside the npx cache. A restart (including the self-update's)Fix: Pin versions and sources; vendor anything fetched at install time.// global install) or relies on npx to fetch it (a service started from the npx cache), and exits with UPDATE_EXIT_CODE.Fix: Pin versions and sources; vendor anything fetched at install time.return { ok: true, detail: 'npx fetches it on restart' };Fix: Pin versions and sources; vendor anything fetched at install time.…hen the runner it started (its command line holds the same --dir) const kill = (like) => `Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like…Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell./** Install the release. npx needs nothing now (the restart fetches it). A global install is `npm install -g`, scripts off, then read back. */Fix: Pin versions and sources; vendor anything fetched at install time./** What starts the CLI: node + cli.js of an install, or `npx -y <spec>` when it runs from the npx cache. */Fix: Pin versions and sources; vendor anything fetched at install time./** `npx`: starts `npx -y <spec>`, so a restart gets the newest release. `node-cache`: starts node on a file inside the npx cache, which only everFix: Pin versions and sources; vendor anything fetched at install time.* This agent's own service, when it is in the old form (node on the npx cache): rewritten to start `npx -y <spec>`. Null when there isFix: Pin versions and sources; vendor anything fetched at install time.* This agent's own service, when it is in the old form (node on the npx cache): rewritten to start `npx -y <spec>`. Null when there isFix: Pin versions and sources; vendor anything fetched at install time.// Keeping an agent's runner service right (issue #4): one service per agent, and a service that starts `npx -y <spec>`.Fix: Pin versions and sources; vendor anything fetched at install time.// `npx -y <spec>` and has the supervisor reload it.Fix: Pin versions and sources; vendor anything fetched at install time.…turn (o.version ?? VERSION).includes('-') ? { kind: 'other', why: 'started with npx from an exact prerelease version: run the join line (or `ach run --install-service`)…Fix: Pin versions and sources; vendor anything fetched at install time.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
No advisories in OSV for @koalaauto/agentchannel@3.27.0 as of 5d ago. This is the package itself, not its dependencies.
What would make this Verified
15 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Pipe-to-shell pattern≈ +9 on the totalBuild commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.
- Unclaimed publisher≈ +8 on the totalClaim koalaauto: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- 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.
- Auto-update or dynamic fetch configuration≈ +4 on the totalPin versions and sources; vendor anything fetched at install time.
- New publisher≈ +3 on the totalTime clears this on its own after 14 and 30 days. Claiming the handle (+50) is the fastest way past it.