registry  /  @lmctl-ai/lmctl  /  0.1.42

@lmctl-ai/lmctl@0.1.42

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 a broad AI-agent/workflow CLI with expected user-invoked network, filesystem, database, and shell/PTY capabilities.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl commands such as api, workflow run, terminal, diagnose, serve, or workspace operations.
Impact
Expected CLI actions can read/write lmctl state, run configured provider tools/workflow commands, and call configured or user-provided endpoints; no hidden exfiltration path found.
Mechanism
User-invoked CLI orchestration and local state management
Rationale
The suspicious primitives are consistent with a provider-agnostic AI workflow CLI and are activated by explicit CLI commands, not installation or import. Source inspection found redaction and trust-checking controls and no concrete unconsented exfiltration, persistence, or destructive behavior.
Evidence
package.jsonbin/lmctldist/cli/index.jsworkflows/*.compound.jsonexamples/opencode.json~/.lmctl/state.db~/.lmctl/.update-check.json/tmp/lmctl-diag-<ticket>.tar.gz
Network endpoints3
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.anthropic.comlmctl.com

Decision evidence

public snapshot
AI called this Clean at 86.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • dist/cli/index.js has user-invoked child_process/PTY paths for provider CLIs, shell workflows, diagnostics, and version checks.
  • dist/cli/index.js can fetch HTTPS workflow URLs and npm metadata; remote workflow run has a trust prompt but auto-continues when stdin is non-TTY.
Evidence against
  • package.json has no install/preinstall/postinstall lifecycle scripts.
  • bin/lmctl only imports dist/cli/index.js and calls runCli with argv.
  • dist/cli/index.js network use is CLI-aligned: API calls, update notifier, HTTPS workflow loading, and stub diagnostic upload.
  • dist/cli/index.js redacts token/secret/password-like env values in diagnostics by default and blocks --no-sanitize with upload modes.
  • Remote workflows are user-supplied or packaged workflow files; bundled workflow shell steps are visible templates for agent orchestration.
  • No source evidence of import-time credential harvesting, persistence, destructive install behavior, or unconsented AI-agent control-surface mutation.
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 1 file(s), 767 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=>An(e)).join(` L5: `)}function Lf(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=Rn(f.join(`
High
Child Process

Package source references child process execution.

dist/cli/index.jsView on unpkg · L4
4`).map(e=>An(e)).join(` L5: `)}function Lf(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=Rn(f.join(` ... L16: `)}catch{}}function yk(){if(!Xs){let e=wk().slice(0,13).replace("T","-");Xs=Gs(za(),`debug-${e}.log`)}pk(hk(Xs),{recursive:!0})}function Vs(...t){vt({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 LT=Object.defineProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var le=(t,e)=>{for(var r in e)LT(t,r,{get:e[r],enumerable:!0})};import{existsSync as Dr,readdirSync as CT,readFileSy... L2: `)}function Xa(){return Tt(mr(),WT)}function Nf(){return Tt(mr(),BT)}function HT(){try{return Dr(Xa())}catch{return!1}}function Af(t=process.stderr){HT()&&t.write(`note: legacy ~/.... L3: `)}var PT,xf,FT,UT,$f,WT,BT,hr,Ve=b(()=>{"use strict";PT=".lmctl",xf="state.db",FT="workspaces",UT="active-workspace",$f="default",WT="profiles",BT="active-profile";hr={default:$f}... L4: `).map(e=>An(e)).join(` L5: `)}function Lf(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=Rn(f.join(` ... L16: `)}catch{}}function yk(){if(!Xs){let e=wk().slice(0,13).replace("T","-");Xs=Gs(za(),`debug-${e}.log`)}pk(hk(Xs),{recursive:!0})}function Vs(...t){vt({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 LT=Object.defineProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var le=(t,e)=>{for(var r in e)LT(t,r,{get:e[r],enumerable:!0})};import{existsSync as Dr,readdirSync as CT,readFileSy... L2: `)}function Xa(){return Tt(mr(),WT)}function Nf(){return Tt(mr(),BT)}function HT(){try{return Dr(Xa())}catch{return!1}}function Af(t=process.stderr){HT()&&t.write(`note: legacy ~/.... ... L4: `).map(e=>An(e)).join(` L5: `)}function Lf(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=Rn(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:Rn(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 yk(){if(!Xs){let e=wk().slice(0,13).replace("T","-");Xs=Gs(za(),`debug-${e}.log`)}pk(hk(Xs),{recursive:!0})}function Vs(...t){vt({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