registry  /  loomctl  /  0.19.0

loomctl@0.19.0

Orchestrate a fleet of real Claude Code agents on your Claude subscription (Pro/Max), not per-token API bills — durable sessions, multi-agent orchestration, all local-first on your own machine.

AI Security Review

scanned 3h ago · by lpm-firewall-ai

Review flagged AI-agent configuration or capability changes. This remains warn-only unless evidence shows foreign-agent hijack through preinstall/install/postinstall, hidden persistence, exfiltration, remote code execution, or other concrete malicious behavior.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
User runs `loom` to start/manage sessions, or explicitly runs `loom service install`.
Impact
Loom can pre-accept workspace trust and influence Claude sessions in projects it manages; no install-time or foreign-network exfiltration chain was confirmed.
Mechanism
Claude configuration mutation, project-local skill injection, local agent orchestration, and authenticated usage polling.
Rationale
No malicious install hook, stealth persistence, remote payload execution, or unrelated exfiltration was found. The package nonetheless performs explicit user-command mutation of Claude trust and skill surfaces, so it warrants a warning rather than a clean verdict.
Evidence
package.jsonbin/loom.mjsbin/service.mjsdist/pty/host.jsdist/pty/claude-config.jsdist/skills/inject.jsdist/orchestration/usage-status.jsdist/git/worktrees.js~/.claude.json<cwd>/.claude/skills<cwd>/.git/info/exclude~/.claude/.credentials.json<worktree>/node_modules
Network endpoints2
api.anthropic.com/api/oauth/usage127.0.0.1

Decision evidence

public snapshot
AI called this Suspicious at 90.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for warning
  • `dist/pty/claude-config.js` writes trust/onboarding flags to `~/.claude.json` for each spawned workspace.
  • `dist/skills/inject.js` copies Loom skills into `<cwd>/.claude/skills`, shadowing personal Claude skills.
  • `dist/orchestration/usage-status.js` reads Claude OAuth credentials and sends the token to Anthropic's usage endpoint.
  • `dist/git/worktrees.js` runs bounded package-manager installs in user-project worktrees.
Evidence against
  • `package.json` has no lifecycle scripts; install does not execute this behavior.
  • Agent configuration writes occur when the user starts Loom-managed Claude sessions.
  • Credential network use is limited to `https://api.anthropic.com/api/oauth/usage` with an Anthropic bearer token.
  • `bin/service.mjs` service registration is an explicit `loom service install` action.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 144 file(s), 4.31 MB of source, external domains: 127.0.0.1, accounts.google.com, api.anthropic.com, api.telegram.org, github.com, oauth2.googleapis.com, react.dev, registry.npmjs.org, schemas.microsoft.com, www.w3.org

Source & flagged code

9 flagged · loading source
bin/loom.mjsView file
22import http from "node:http"; L23: import { spawn, spawnSync } from "node:child_process"; L24: import { CHANNELS, isValidChannel, installSpecFor, readChannel, writeChannel } from "./update-config.mjs";
High
Child Process

Package source references child process execution.

bin/loom.mjsView on unpkg · L22
449// no shell-injection surface. L450: const r = spawnSync("npm", ["i", "-g", spec], { stdio: "inherit", shell: true }); L451: if (r.error || r.status !== 0) {
High
Shell

Package source references shell execution.

bin/loom.mjsView on unpkg · L449
21import fs from "node:fs"; L22: import http from "node:http"; L23: import { spawn, spawnSync } from "node:child_process"; L24: import { CHANNELS, isValidChannel, installSpecFor, readChannel, writeChannel } from "./update-config.mjs"; ... L33: // to resize it after the fact). Never overrides an operator's own explicit setting. L34: if (!process.env.UV_THREADPOOL_SIZE) process.env.UV_THREADPOOL_SIZE = "16"; L35:
High
Same File Env Network Execution

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

bin/loom.mjsView on unpkg · L21
270// readiness. L271: await import(pathToFileURL(daemonEntry).href); L272:
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/loom.mjsView on unpkg · L270
dist/mcp/repo-read.jsView file
62for (let i = 0; i < s.length; i++) L63: if (s.charCodeAt(i) === 0) L64: return true;
Medium
Unsafe Vm Context

Package source executes code through a VM context API.

dist/mcp/repo-read.jsView on unpkg · L62
bin/service.mjsView file
10// - macOS : a launchd LaunchAgent plist (RunAtLoad + KeepAlive) under ~/Library/LaunchAgents, L11: // loaded via `launchctl`. L12: // - Windows: a Task Scheduler logon task (schtasks /create /xml) running at logon — no admin / no ... L22: import path from "node:path"; L23: import { spawnSync } from "node:child_process"; L24: ... L74: // launchd LaunchAgent plist. RunAtLoad starts it when the agent is loaded at login; KeepAlive restarts L75: // it if it exits (the keep-alive). Stdout/stderr go to a log under LOOM_HOME so a background boot stays L76: // debuggable. ... L118: return `<?xml version="1.0" encoding="UTF-16"?> L119: <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> L120: <RegistrationInfo>
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

bin/service.mjsView on unpkg · L10
dist/git/worktrees.jsView file
92/** L93: * Run a BOUNDED, NON-INTERACTIVE `pnpm install --frozen-lockfile --prefer-offline` in `worktreePath`, L94: * killing the child if it exceeds `timeoutMs`. ASYNC (child_process.spawn, NOT spawnSync) on purpose: L95: * createWorktree is awaited on the worker-spawn hot path, and a synchronous spawnSync would freeze the
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

dist/git/worktrees.jsView on unpkg · L92
assets/python/synthesize.pyView file
path = assets/python/synthesize.py kind = build_helper sizeBytes = 11311 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

assets/python/synthesize.pyView on unpkg
dist/pty/host.jsView file
matchType = previous_version_dangerous_delta matchedPackage = loomctl@0.18.0 matchedIdentity = npm:bG9vbWN0bA:0.18.0 similarity = 0.867 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

dist/pty/host.jsView on unpkg

Findings

1 Critical4 High7 Medium4 Low
CriticalPrevious Version Dangerous Deltadist/pty/host.js
HighChild Processbin/loom.mjs
HighShellbin/loom.mjs
HighSame File Env Network Executionbin/loom.mjs
HighRuntime Package Installdist/git/worktrees.js
MediumDynamic Requirebin/loom.mjs
MediumUnsafe Vm Contextdist/mcp/repo-read.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencebin/service.mjs
MediumShips Build Helperassets/python/synthesize.py
MediumStructural Risk Force Deep Review
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings