registry  /  @lmctl-ai/lmctl  /  0.1.51

@lmctl-ai/lmctl@0.1.51

A provider-agnostic control plane for teams of AI coding agents — across providers, with independent review and durable memory.

AI Security Review

scanned 10d ago · by lpm-firewall-ai

No confirmed malicious attack surface was established. The package is an AI-agent control-plane CLI with explicit user-invoked command execution, remote workflow loading, and MCP setup capabilities.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl commands such as seed, chat, terminal, workflow run/load, diagnose, or serve.
Impact
Can delegate prompts to provider CLIs and execute workflow-defined local commands when the operator configures or runs those workflows.
Mechanism
User-invoked AI agent orchestration and local CLI/process spawning
Rationale
Source inspection shows a powerful AI coding-agent CLI with child process, MCP, workflow, and network primitives, but these are exposed through documented user-invoked commands rather than lifecycle/import-time behavior or hidden exfiltration. Because the dangerous capabilities are package-aligned but real, warn rather than block.
Evidence
package.jsonbin/lmctldist/cli/index.jsREADME.mdworkflows/qa-suite.compound.jsonworkflows/pr-fix.compound.json~/.lmctl/state.db~/.lmctl/.update-check.json.mcp.jsonteamfile.lmctl/tmp/lmctl-diag-<ticket>.tar.gz
Network endpoints4
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.comlmctl.anthropic.com127.0.0.1:8787

Decision evidence

public snapshot
AI called this Suspicious at 82.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • dist/cli/index.js spawns provider CLIs with permissive/yolo flags for chat/terminal/session workflows
  • dist/cli/index.js can install an lmctl_chat MCP bridge into a project/session during explicit seed flow
  • dist/cli/index.js loads remote workflow/skill URLs only via https and can run loaded workflows when invoked
  • workflows/*.compound.json include operator-directed shell/git/gh commands for AI coding workflows
Evidence against
  • package.json has no lifecycle scripts; bin/lmctl only imports runCli
  • No install-time or import-time execution beyond CLI module definition was found
  • Diagnostics redact token-like env values and upload modes are stubbed/noop or user-selected
  • Network use is package-aligned: update check, https workflow/skill fetch, local API/MCP
  • No credential harvesting, persistence, destructive install behavior, or hidden exfiltration found
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 1 file(s), 773 KB of source, external domains: 127.0.0.1, antigravity.google, api.deepseek.com, api.github.com, api.githubcopilot.com, cli.github.com, docs.anthropic.com, docs.claude.com, docs.github.com, github.com, lmctl.ai, lmctl.anthropic.com, lmctl.com, mailbox.local, nodejs.org, opencode.ai, openrouter.ai, registry.npmjs.org, unpkg.com

Source & flagged code

4 flagged · loading source
dist/cli/index.jsView file
4`).map(e=>On(e)).join(` L5: `)}function Df(t,e){let r=t.toUpperCase();return r.includes("TOKEN")||r.includes("SECRET")||r.includes("KEY")||r.includes("PASSWORD")||r.includes("PASSWD")||r.includes("CREDENTIAL"... L6: `),f=d.slice(Math.max(0,d.length-n));c=f.length,a=Ln(f.join(`
High
Child Process

Package source references child process execution.

dist/cli/index.jsView on unpkg · L4
4`).map(e=>On(e)).join(` L5: `)}function Df(t,e){let r=t.toUpperCase();return r.includes("TOKEN")||r.includes("SECRET")||r.includes("KEY")||r.includes("PASSWORD")||r.includes("PASSWD")||r.includes("CREDENTIAL"... L6: `),f=d.slice(Math.max(0,d.length-n));c=f.length,a=Ln(f.join(` ... L16: `)}catch{}}function Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}wk(yk(Vs),{recursive:!0})}function ot(...t){It({event:"legacy",msg:t.join(" ")... L17: `)){let r=e.trim();if(!r||r.startsWith("#"))continue;if(r.startsWith("["))break;let n=/^debug\s*=\s*(.+)$/.exec(r);if(n){let s=n[1].trim().toLowerCase().replace(/^["']|["']$/g,"");... L18: CREATE TABLE IF NOT EXISTS session_size (
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/cli/index.jsView on unpkg · L4
1var PT=Object.defineProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var ce=(t,e)=>{for(var r in e)PT(t,r,{get:e[r],enumerable:!0})};import{existsSync as Pr,readdirSync as FT,readFileSy... L2: `)}function Va(){return kt(pr(),JT)}function Of(){return kt(pr(),XT)}function VT(){try{return Pr(Va())}catch{return!1}}function Lf(t=process.stderr){VT()&&t.write(`note: legacy ~/.... L3: `)}var BT,jf,qT,HT,Af,JT,XT,_r,Ve=b(()=>{"use strict";BT=".lmctl",jf="state.db",qT="workspaces",HT="active-workspace",Af="default",JT="profiles",XT="active-profile";_r={default:Af}... L4: `).map(e=>On(e)).join(` L5: `)}function Df(t,e){let r=t.toUpperCase();return r.includes("TOKEN")||r.includes("SECRET")||r.includes("KEY")||r.includes("PASSWORD")||r.includes("PASSWD")||r.includes("CREDENTIAL"... L6: `),f=d.slice(Math.max(0,d.length-n));c=f.length,a=Ln(f.join(` ... L16: `)}catch{}}function Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}wk(yk(Vs),{recursive:!0})}function ot(...t){It({event:"legacy",msg:t.join(" ")... L17: `)){let r=e.trim();if(!r||r.startsWith("#"))continue;if(r.startsWith("["))break;let n=/^debug\s*=\s*(.+)$/.exec(r);if(n){let s=n[1].trim().toLowerCase().rep
High
Command Output Exfiltration

Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.

dist/cli/index.jsView on unpkg · L1
1var PT=Object.defineProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var ce=(t,e)=>{for(var r in e)PT(t,r,{get:e[r],enumerable:!0})};import{existsSync as Pr,readdirSync as FT,readFileSy... L2: `)}function Va(){return kt(pr(),JT)}function Of(){return kt(pr(),XT)}function VT(){try{return Pr(Va())}catch{return!1}}function Lf(t=process.stderr){VT()&&t.write(`note: legacy ~/.... ... L4: `).map(e=>On(e)).join(` L5: `)}function Df(t,e){let r=t.toUpperCase();return r.includes("TOKEN")||r.includes("SECRET")||r.includes("KEY")||r.includes("PASSWORD")||r.includes("PASSWD")||r.includes("CREDENTIAL"... L6: `),f=d.slice(Math.max(0,d.length-n));c=f.length,a=Ln(f.join(` ... L14: `).filter(i=>i.length>0),o=s.slice(Math.max(0,s.length-r));return{source_path:e,tail_lines:o.length,tail:Ln(o.join(` L15: `)),note:null}}catch(n){return n.code==="ENOENT"?{source_path:e,tail_lines:0,tail:"",note:"no intent log present (status never run on this host)"}:{source_path:e,tail_lines:0,tail:... L16: `)}catch{}}function Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}wk(yk(Vs),{recursive:!0})}function ot(...t){It({event:"legacy",msg:t.join(" ")... L17: `)){let r=e.trim();if(!r||r.s
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/cli/index.jsView on unpkg · L1

Findings

4 High2 Medium5 Low
HighChild Processdist/cli/index.js
HighShell
HighSame File Env Network Executiondist/cli/index.js
HighCommand Output Exfiltrationdist/cli/index.js
MediumNetwork
MediumEnvironment Vars
LowWeak Cryptodist/cli/index.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License