registry  /  @lmctl-ai/lmctl  /  0.1.57

@lmctl-ai/lmctl@0.1.57

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

AI Security Review

scanned 8d ago · by lpm-firewall-ai

No confirmed malicious attack surface was found. The suspicious primitives are aligned with a local-first CLI for orchestrating AI coding agents, workflows, diagnostics, and local SQLite state.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl CLI commands.
Impact
Expected local state changes and user-directed provider/tool execution; no install-time payload, credential exfiltration, persistence, or destructive behavior identified.
Mechanism
User-invoked workflow/agent orchestration with optional HTTPS workflow fetch and provider subprocess control
Rationale
Static inspection shows no lifecycle hook, import-time payload, harvesting-to-exfiltration flow, persistence, destructive action, or unconsented AI-agent control-surface mutation. The network, environment, filesystem, and subprocess capabilities are activated by explicit CLI commands and match the package's documented purpose.
Evidence
package.jsonbin/lmctldist/cli/index.jsdist/cli/schema.sqlREADME.mddist/cli/side_effect_classifier.json
Network endpoints8
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.comapi.githubcopilot.comapi.deepseek.com/v1openrouter.ai/api/v1docs.claude.com/en/docs/claude-codegithub.com/openai/codexopencode.ai

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with low false-positive risk.
Evidence for block
  • dist/cli/index.js can fetch https:// workflow URLs and npm metadata under user-invoked CLI paths.
  • dist/cli/index.js uses child_process for provider checks, diagnostics, tar/stat, and terminal/provider orchestration.
  • dist/cli/index.js contains provider resume/start flags that bypass approvals for managed agent sessions.
Evidence against
  • package.json has no lifecycle scripts and only exposes bin/lmctl.
  • bin/lmctl only imports dist/cli/index.js and calls runCli with argv.
  • Remote workflow loading is tied to workflow load/run commands; remote run help states a trust prompt.
  • Diagnostic upload modes are stubbed; --no-sanitize is rejected with upload flags.
  • Env diagnostics redact token/secret/key/password-like values before bundling.
  • Writes are scoped to LMCTL state, update cache, diagnostics, workflow templates, and user-selected project/session paths.
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 1 file(s), 782 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 Pf(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 Pf(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 Ak(){if(!Ks){let e=jk().slice(0,13).replace("T","-");Ks=Vs(Qa(),`debug-${e}.log`)}Ik(Nk(Ks),{recursive:!0})}function Je(...t){xt({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 XS=Object.defineProperty;var E=(t,e)=>()=>(t&&(e=t(t=0)),e);var ce=(t,e)=>{for(var r in e)XS(t,r,{get:e[r],enumerable:!0})};import{existsSync as Ur,readdirSync as GS,readFileSy... L2: `)}function Va(){return It(hr(),QS)}function Lf(){return It(hr(),ek)}function rk(){try{return Ur(Va())}catch{return!1}}function Cf(t=process.stderr){rk()&&t.write(`note: legacy ~/.... L3: `)}var YS,Af,zS,ZS,Rf,QS,ek,gr,Ye=E(()=>{"use strict";YS=".lmctl",Af="state.db",zS="workspaces",ZS="active-workspace",Rf="default",QS="profiles",ek="active-profile";gr={default:Rf}... L4: `).map(e=>On(e)).join(` L5: `)}function Pf(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 Ak(){if(!Ks){let e=jk().slice(0,13).replace("T","-");Ks=Vs(Qa(),`debug-${e}.log`)}Ik(Nk(Ks),{recursive:!0})}function Je(...t){xt({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 XS=Object.defineProperty;var E=(t,e)=>()=>(t&&(e=t(t=0)),e);var ce=(t,e)=>{for(var r in e)XS(t,r,{get:e[r],enumerable:!0})};import{existsSync as Ur,readdirSync as GS,readFileSy... L2: `)}function Va(){return It(hr(),QS)}function Lf(){return It(hr(),ek)}function rk(){try{return Ur(Va())}catch{return!1}}function Cf(t=process.stderr){rk()&&t.write(`note: legacy ~/.... ... L4: `).map(e=>On(e)).join(` L5: `)}function Pf(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 Ak(){if(!Ks){let e=jk().slice(0,13).replace("T","-");Ks=Vs(Qa(),`debug-${e}.log`)}Ik(Nk(Ks),{recursive:!0})}function Je(...t){xt({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