registry  /  @tokenfactory/acc-runner  /  0.37.4

@tokenfactory/acc-runner@0.37.4

Agent Control Center local runner. Spawns Claude Code sessions assigned via ACC.

AI Security Review

scanned 2h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. An authenticated user who runs `acc-runner watch` accepts ACC task assignments that start a local coding-agent session. The runner temporarily injects its ACC MCP server configuration, including a user access token, into the task worktree and restores it afterward. It also supports autonomous global package upgrades while watching.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs `acc-runner login` and then `acc-runner watch`; an ACC task assignment activates the task runner.
Impact
A compromised ACC service, task stream, or referenced MCP package could direct the local agent in the selected worktree and receive runner-authorized MCP access.
Mechanism
Remote task orchestration, temporary MCP extension setup, and opt-out global self-upgrade.
Rationale
Source inspection found no concrete malicious chain or unconsented lifecycle mutation. The package nevertheless configures and launches a token-bearing MCP extension in project worktrees and can self-update globally, so it warrants a non-blocking warning rather than clean classification.
Evidence
package.jsondist/cli.jsdist/task-runner.jsdist/mcp-spawn.jsdist/runtime/self-upgrade.jsdist/secrets/inject.jsdist/watch.jsworktree/.mcp.json
Network endpoints3
agent-control-center-sepia.vercel.appctknjrtevjrzwpuojghx.supabase.coregistry.npmjs.org/@tokenfactory/acc-runner/latest

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for warning
  • `dist/mcp-spawn.js` writes token-bearing `.mcp.json` entries and may invoke `npx -y @tokenfactory/acc-mcp-server`.
  • `dist/task-runner.js` receives server-assigned tasks, writes MCP configuration in a task worktree, and spawns a coding agent with task prompts.
  • `dist/runtime/self-upgrade.js` automatically runs global npm/pnpm installs and re-execs during `watch` unless opted out.
  • `dist/secrets/inject.js` retrieves named secret plaintext under the runner JWT for MCP tool arguments.
Evidence against
  • `package.json` contains no `preinstall`, `install`, `postinstall`, or other lifecycle hooks.
  • `dist/cli.js` activates behavior only through explicit CLI commands such as `login` and `watch`.
  • `dist/keychain.js` stores sessions through the OS keychain; no source evidence harvests arbitrary local credentials.
  • No `eval`, VM execution, obfuscated payload, or unrelated exfiltration endpoint was found in inspected runtime code.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 52 file(s), 637 KB of source, external domains: agent-control-center-sepia.vercel.app, claude.com, cli.github.com, ctknjrtevjrzwpuojghx.supabase.co, git-scm.com, nodejs.org, registry.npmjs.org

Source & flagged code

7 flagged · loading source
dist/config.jsView file
74patternName = supabase_service_key severity = critical line = 74 matchedText = const DE...lQ";
Critical
Critical Secret

Package contains a critical-looking secret pattern.

dist/config.jsView on unpkg · L74
74patternName = supabase_service_key severity = critical line = 74 matchedText = const DE...lQ";
Critical
Secret Pattern

Supabase service role key (JWT) in dist/config.js

dist/config.jsView on unpkg · L74
dist/gh.jsView file
74chargeGithubCall(); L75: return exec(args, { cwd: opts.cwd }); L76: };
High
Child Process

Package source references child process execution.

dist/gh.jsView on unpkg · L74
dist/task-runner.jsView file
21import { fileURLToPath, pathToFileURL } from "node:url"; L22: import { execa } from "execa"; L23: import { canServeRepo, loadProfile as defaultLoadProfile } from "./config.js";
High
Shell

Package source references shell execution.

dist/task-runner.jsView on unpkg · L21
355} L356: const mod = (await import(/* @vite-ignore */ pathToFileURL(resolved).href)); L357: const def = mod.default;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/task-runner.jsView on unpkg · L355
dist/runtime/singleton.jsView file
41*/ L42: export function singletonRunnerId(env = process.env) { L43: return env.ACC_RUNNER_ID?.trim() || ""; ... L93: try { L94: const parsed = JSON.parse(raw); L95: if (typeof parsed.pid !== "number" || !Number.isFinite(parsed.pid)) ... L133: * same (canonical repo path, runner identity) pair. A stale lock (dead pid, L134: * our own pid, or a corrupt file) is reclaimed with a stderr breadcrumb and L135: * then re-acquired. A different `runnerId` keys a different lock file, so two ... L170: // Stale: dead holder, our own leftover pid, or unparseable. Reclaim. L171: process.stderr.write(`[acc-runner] reclaiming stale runner lock ${file} ` + L172: `(held by pid ${holder?.pid ?? "?"}, not alive)\n`);
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/runtime/singleton.jsView on unpkg · L41
dist/login.jsView file
66try { L67: await execa(bin, ["--version"], { env: process.env }); L68: if (bin === "claude") { ... L81: async function postJson(url, body) { L82: const res = await fetch(url, { L83: method: "POST",
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

dist/login.jsView on unpkg · L66

Findings

2 Critical3 High3 Medium6 Low
CriticalCritical Secretdist/config.js
CriticalSecret Patterndist/config.js
HighChild Processdist/gh.js
HighShelldist/task-runner.js
HighSame File Env Network Executiondist/login.js
MediumDynamic Requiredist/task-runner.js
MediumNetwork
MediumEnvironment Vars
LowScripts Present
LowWeak Cryptodist/runtime/singleton.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License