registry  /  @lmctl-ai/lmctl  /  0.1.54

@lmctl-ai/lmctl@0.1.54

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

AI Security Review

scanned 9d ago · by lpm-firewall-ai

No confirmed malicious attack surface was found. The package is a CLI control plane for AI coding-agent workflows with user-invoked network, shell, local DB, and diagnostic features.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl CLI subcommands such as workflow run, terminal, diagnose, serve, or seeded workflows.
Impact
Expected local project/session management; no install-time execution or confirmed covert exfiltration.
Mechanism
user-invoked AI-agent orchestration and workflow execution
Rationale
Static inspection shows suspicious primitives, but they are tied to documented CLI/workflow functionality and require explicit user commands; there are no lifecycle hooks or covert install/import-time actions. I found no credential harvesting or unconsented exfiltration path beyond redacted diagnostics and user-supplied remote workflow loading.
Evidence
package.jsonbin/lmctldist/cli/index.jsREADME.mdworkflows/qa-suite.compound.jsonworkflows/pr-fix.compound.json~/.lmctl/state.db~/.lmctl/.update-check.json/tmp/lmctl-diag-<ticket>.tar.gz
Network endpoints3
registry.npmjs.org/@lmctl-ai/lmctl/latestlmctl.comlmctl.anthropic.com

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with low false-positive risk.
Evidence for block
    Evidence against
    • package.json has no lifecycle scripts; bin/lmctl only imports runCli and passes argv.
    • dist/cli/index.js command dispatch gates behavior behind explicit CLI subcommands.
    • Network use is package-aligned: update check to registry.npmjs.org and user-supplied HTTPS workflow loading.
    • child_process use launches configured AI-provider CLIs, tar/stat/du/uname, and user-invoked workflow commands.
    • diagnose bundle redacts token/secret/password/key-like values and upload paths are stub/noop.
    • workflows/*.compound.json commands are workflow definitions executed only when loaded/run by the user.
    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 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 Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}yk(wk(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 Lf(){return kt(pr(),XT)}function VT(){try{return Pr(Va())}catch{return!1}}function Cf(t=process.stderr){VT()&&t.write(`note: legacy ~/.... L3: `)}var BT,Af,qT,HT,Rf,JT,XT,_r,Ve=b(()=>{"use strict";BT=".lmctl",Af="state.db",qT="workspaces",HT="active-workspace",Rf="default",JT="profiles",XT="active-profile";_r={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 Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}yk(wk(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 Lf(){return kt(pr(),XT)}function VT(){try{return Pr(Va())}catch{return!1}}function Cf(t=process.stderr){VT()&&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 Tk(){if(!Vs){let e=Sk().slice(0,13).replace("T","-");Vs=Ks(Za(),`debug-${e}.log`)}yk(wk(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