registry  /  @lmctl-ai/lmctl  /  0.1.113

@lmctl-ai/lmctl@0.1.113

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

AI Security Review

scanned 3h ago · by lpm-firewall-ai

Review flagged AI-agent configuration or capability changes. This remains warn-only unless evidence shows foreign-agent hijack through preinstall/install/postinstall, hidden persistence, exfiltration, remote code execution, or other concrete malicious behavior.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs lmctl with an OpenCode or other configured provider
Impact
A user-invoked agent can receive broad tool/file permissions; OpenCode configuration is persisted in the selected project.
Mechanism
CLI-driven agent launch with permissive provider settings
Rationale
Source inspection confirms dangerous agent-control behavior is explicit runtime functionality rather than an npm lifecycle attack. Warn because it persists an allow-permission OpenCode configuration and launches providers with bypass flags, but do not block absent unconsented install-time mutation or a concrete malicious chain.
Evidence
package.jsonbin/lmctldist/cli/index.jsworkflows/pr-followup-v2.compound.json<cwd>/.opencode/opencode.json
Network endpoints1
api.github.com

Decision evidence

public snapshot
AI called this Suspicious at 88.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for warning
  • `dist/cli/index.js` launches agent CLIs with approval/sandbox-bypass or YOLO flags.
  • `dist/cli/index.js` creates `<cwd>/.opencode/opencode.json` with `permission: "allow"` when OpenCode runs.
  • `workflows/pr-followup-v2.compound.json` tells agents to omit AI-identifying language from public replies.
Evidence against
  • `package.json` has no `preinstall`, `install`, `postinstall`, or other lifecycle scripts.
  • `bin/lmctl` only invokes the CLI after an explicit user command.
  • Remote workflow fetches require HTTPS, reject redirects, and workflow execution presents a trust prompt unless bypassed by CLI option.
  • Diagnostic environment output redacts values whose names indicate credentials.
Behavioral surface
Source
ChildProcessEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 1 file(s), 854 KB of source, external domains: 127.0.0.1, antigravity.google, api.github.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, registry.npmjs.org, unpkg.com

Source & flagged code

4 flagged · loading source
dist/cli/index.jsView file
4`).map(e=>Vn(e)).join(` L5: `)}function Dm(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=Yn(f.join(`
High
Child Process

Package source references child process execution.

dist/cli/index.jsView on unpkg · L4
4`).map(e=>Vn(e)).join(` L5: `)}function Dm(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=Yn(f.join(` ... L16: `)}catch{}}function LI(){if(!Eo){let e=RI().slice(0,13).replace("T","-");Eo=To(Ll(),`debug-${e}.log`)}II(NI(Eo),{recursive:!0})}function je(...t){Oe({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 Xk=Object.defineProperty;var T=(t,e)=>()=>(t&&(e=t(t=0)),e);var se=(t,e)=>{for(var r in e)Xk(t,r,{get:e[r],enumerable:!0})};import{existsSync as Vr,readdirSync as Gk,readFileSy... L2: `)}function Nl(){return Mt(vr(),Qk)}function Om(){return Mt(vr(),eI)}function rI(){try{return Vr(Nl())}catch{return!1}}function jm(t=process.stderr){rI()&&t.write(`note: legacy ~/.... L3: `)}var Yk,Rm,zk,Zk,Lm,Qk,eI,Ir,Ve=T(()=>{"use strict";Yk=".lmctl",Rm="state.db",zk="workspaces",Zk="active-workspace",Lm="default",Qk="profiles",eI="active-profile";Ir={default:Lm}... L4: `).map(e=>Vn(e)).join(` L5: `)}function Dm(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=Yn(f.join(` ... L16: `)}catch{}}function LI(){if(!Eo){let e=RI().slice(0,13).replace("T","-");Eo=To(Ll(),`debug-${e}.log`)}II(NI(Eo),{recursive:!0})}function je(...t){Oe({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 Xk=Object.defineProperty;var T=(t,e)=>()=>(t&&(e=t(t=0)),e);var se=(t,e)=>{for(var r in e)Xk(t,r,{get:e[r],enumerable:!0})};import{existsSync as Vr,readdirSync as Gk,readFileSy... L2: `)}function Nl(){return Mt(vr(),Qk)}function Om(){return Mt(vr(),eI)}function rI(){try{return Vr(Nl())}catch{return!1}}function jm(t=process.stderr){rI()&&t.write(`note: legacy ~/.... ... L4: `).map(e=>Vn(e)).join(` L5: `)}function Dm(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=Yn(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:Yn(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 LI(){if(!Eo){let e=RI().slice(0,13).replace("T","-");Eo=To(Ll(),`debug-${e}.log`)}II(NI(Eo),{recursive:!0})}function je(...t){Oe({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 Medium6 Low
HighChild Processdist/cli/index.js
HighShell
HighSame File Env Network Executiondist/cli/index.js
HighCommand Output Exfiltrationdist/cli/index.js
MediumNetwork
MediumEnvironment Vars
LowEval
LowWeak Cryptodist/cli/index.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License