registry  /  @lmctl-ai/lmctl  /  0.1.49

@lmctl-ai/lmctl@0.1.49

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 risky primitives are explicit CLI features for orchestrating AI coding agents, loading user-approved workflows, local diagnostics, and update checking.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs the lmctl CLI or specific subcommands such as workflow run/load, diagnose, team seed, terminal, or workspace commands.
Impact
Expected CLI behavior can launch local provider tools and write lmctl state/config; no unconsented install/import-time impact found.
Mechanism
User-invoked AI-agent control plane with local DB/config writes, provider CLI spawning, optional https workflow fetch, and sanitized diagnostics.
Rationale
Static inspection shows a legitimate AI-agent orchestration CLI with no lifecycle hooks and no automatic malicious behavior. Network, environment, and child_process findings are user-invoked and package-aligned, with redaction/trust prompts or stubbed upload paths where sensitive data could be involved.
Evidence
package.jsonbin/lmctldist/cli/index.jsREADME.mdworkflows/qa-suite.compound.jsonworkflows/pr-fix.compound.json~/.lmctl/state.db~/.lmctl/workspaces/<workspace>/state.db~/.lmctl/.update-check.json/tmp/lmctl-diag-<ticket>.tar.gz
Network endpoints5
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.anthropic.comapi.githubcopilot.comapi.deepseek.com/v1openrouter.ai/api/v1

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • dist/cli/index.js uses child_process spawn/spawnSync for provider CLIs and system probes.
  • dist/cli/index.js can fetch https workflows and has an update check to npm registry.
  • dist/cli/index.js can collect diagnostics including env presence, logs, DB summaries, and intent log tails.
Evidence against
  • package.json has no lifecycle scripts; bin/lmctl only imports runCli and runs on explicit CLI invocation.
  • Diagnostic collection redacts token/secret/key/password values and upload modes are stubbed or local bundle output.
  • Remote workflow run requires https and an interactive trust prompt unless --yes is supplied by the user.
  • Shell/child_process use is aligned with an AI-agent orchestration CLI: launching provider CLIs, version checks, du/uname, git/workflow commands.
  • Network endpoints are package-aligned: npm update metadata, user-supplied https workflow URLs, configured AI provider base URLs.
  • No install-time execution, credential exfiltration, persistence, destructive lifecycle behavior, or reviewer/prompt manipulation 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