registry  /  @lmctl-ai/lmctl  /  0.1.45

@lmctl-ai/lmctl@0.1.45

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 found. The package is a user-invoked AI agent control CLI with expected network, local database, workflow, and process-spawn capabilities.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl subcommands such as workflow, terminal, api, device, diagnose, or mcp.
Impact
Expected CLI behavior can contact configured/local services, fetch explicitly supplied HTTPS workflows, spawn provider tools, and write lmctl state/debug/diagnostic files.
Mechanism
User-directed CLI orchestration and diagnostics
Rationale
Static inspection shows risky primitives, but they are aligned with a documented lmctl CLI for agent orchestration, local diagnostics, workflow loading, and optional API/device use. There is no install/import execution or concrete unconsented data theft/control mutation, so the scanner findings are noisy for this package.
Evidence
package.jsonbin/lmctldist/cli/index.jsREADME.mdworkflows/qa-suite.compound.jsonworkflows/pr-fix.compound.json~/.lmctl/state.db~/.lmctl/.update-check.json~/.lmctl/debug-*.log/tmp/lmctl-diag-*.tar.gz
Network endpoints5
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.comlmctl.anthropic.comcognito-idp.<region>.amazonaws.coms3://lmctl/diagnostics/

Decision evidence

public snapshot
AI called this Clean at 86.0% confidence as Benign with low false-positive risk.
Evidence for block
  • dist/cli/index.js can spawn provider CLIs and lmctl chat for user-invoked terminal/MCP/team workflows.
  • dist/cli/index.js fetches HTTPS workflow URLs and npm metadata; device path uses AWS Cognito/S3 SDK.
  • dist/cli/index.js diagnose can collect local env/status/log tail data, but redacts token/secret/key/password fields by default.
Evidence against
  • package.json has no lifecycle scripts; only bin is bin/lmctl.
  • bin/lmctl only imports dist/cli/index.js and calls runCli with user arguments.
  • Network and child_process paths are CLI subcommands, not install-time or import-time execution.
  • Remote workflow run requires HTTPS and prompts unless --yes/--no-prompt is supplied.
  • diagnose upload paths are local by default; HQ/S3 upload is stub/noop and --no-sanitize is blocked with upload modes.
  • No evidence of credential exfiltration, persistence, destructive behavior, or AI-agent control-surface mutation on install/import.
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 1 file(s), 770 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 Cf(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 Cf(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 ce=(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 Af(){return Tt(mr(),BT)}function HT(){try{return Dr(Xa())}catch{return!1}}function Rf(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 Cf(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 ce=(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 Af(){return Tt(mr(),BT)}function HT(){try{return Dr(Xa())}catch{return!1}}function Rf(t=process.stderr){HT()&&t.write(`note: legacy ~/.... ... L4: `).map(e=>An(e)).join(` L5: `)}function Cf(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