registry  /  mulmoterminal  /  0.6.1

mulmoterminal@0.6.1

MulmoTerminal — browser terminal + GUI panel for Claude Code. One command to start.

AI Security Review

scanned 3d ago · by lpm-firewall-ai

No confirmed malicious attack surface was found. The package is a local Claude Code terminal/GUI, so PTY spawning, localhost networking, and plugin loading are expected runtime capabilities rather than hidden install/import behavior.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
postinstall chmod; user runs mulmoterminal CLI or uses local web UI
Impact
Expected local server, PTY, workspace file, and plugin operations under user-invoked runtime
Mechanism
local terminal/GUI server with Claude MCP/plugin integration
Rationale
Static inspection shows high-risk primitives, but they are explicit terminal/Claude GUI functionality and the install hook is limited to chmodding node-pty helpers. I found no credential harvesting, exfiltration, destructive persistence, hidden payload execution, or unconsented AI-agent control-surface mutation.
Evidence
package.jsonserver/fix-pty-perms.jsbin/mulmoterminal.jsbin/update-check.jsserver/index.tsserver/plugins-registry.tsserver/pick-file.tsserver/claude-args.tsplugins/plugins.jsonnode-pty prebuilds/*/spawn-helper~/.mulmoterminal/dev-terminal-sessions.json<CLAUDE_CWD>~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl
Network endpoints4
registry.npmjs.org/<pkg>/latestlocalhost:<PORT>127.0.0.1:<PORT>/api/mcp/<sessionId>127.0.0.1:<PORT>/api/accounting

Decision evidence

public snapshot
AI called this Clean at 86.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • postinstall runs server/fix-pty-perms.js and chmods node-pty spawn-helper files
  • Runtime launches claude and user shell PTYs via bin/mulmoterminal.js and server/index.ts
  • Server exposes local browser/MCP endpoints that can spawn Claude sessions and plugin tools
Evidence against
  • postinstall only resolves node-pty/prebuilds and chmods existing spawn-helper; no network or dropped payload
  • bin/update-check.js only fetches registry latest metadata and is best-effort/opt-out
  • Child process use is package-aligned: launcher checks claude, starts server, opens localhost UI, and PTYs implement terminal features
  • WebSocket/local action routes validate localhost origins and session IDs; shell command PTY is user-driven
  • Dynamic imports are limited to configured plugin package names and local plugins/plugins.json has no arbitrary paths
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareUrlStrings
ManifestNo manifest risk signals triggered.
scanned 167 file(s), 4.10 MB of source, external domains: 127.0.0.1, bitbucket.org, cdn.jsdelivr.net, cdn.plot.ly, cdnjs.cloudflare.com, chevrotain.io, en.wikipedia.org, evil.example, fonts.bunny.net, fonts.googleapis.com, fonts.gstatic.com, github.com, langium.org, registry.npmjs.org, unpkg.com, www.w3.org
Oversized source lightweight scan
dist/assets/index-BQm57UKf.js2.55 MB file, sampled 256 KB
NetworkChildProcessHighEntropyStringsMinifiedUrlStringsProtestwarewww.w3.org
dist/assets/marp-DhAav9Gi.js3.39 MB file, sampled 256 KB
ChildProcessObfuscatedHighEntropyStringsUrlStringscdn.jsdelivr.netfonts.bunny.netwww.w3.org

Source & flagged code

10 flagged · loading source
package.jsonView file
scripts.postinstall = node server/fix-pty-perms.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
bin/mulmoterminal.jsView file
7L8: import { execSync, spawn } from "node:child_process"; L9: import { existsSync, statSync } from "node:fs";
High
Child Process

Package source references child process execution.

bin/mulmoterminal.jsView on unpkg · L7
7Manifest entrypoint (manifest.bin) carries capability families absent from dist/build output: environment+network, execution+network L7: L8: import { execSync, spawn } from "node:child_process"; L9: import { existsSync, statSync } from "node:fs"; L10: import { get as httpGet } from "node:http"; L11: import { createRequire } from "node:module"; ... L16: L17: const __dirname = dirname(fileURLToPath(import.meta.url)); L18: const PKG_DIR = join(__dirname, ".."); ... L22: const MAX_BIND_RETRIES = 5; L23: // Server exit code meaning "port taken at bind time" — keep in sync with L24: // server/index.ts (PORT_IN_USE_EXIT_CODE). ... L26:
High
Entrypoint Build Divergence

Manifest entrypoint contains risky behavior absent from dist/build output.

bin/mulmoterminal.jsView on unpkg · L7
193log(`Starting MulmoTerminal on port ${port}...`); L194: const server = spawn(process.execPath, ["--import", "tsx", SERVER_ENTRY], { L195: cwd: PKG_DIR, L196: env: { ...process.env, NODE_ENV: "production", PORT: String(port), CLAUDE_CWD: cwd }, L197: stdio: "inherit", ... L200: L201: const url = `http://localhost:${port}`; L202: const cancelReady = waitUntilReady(port, () => {
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

bin/mulmoterminal.jsView on unpkg · L193
server/pick-file.tsView file
33return { L34: cmd: "powershell", L35: args: [
High
Shell

Package source references shell execution.

server/pick-file.tsView on unpkg · L33
server/plugins-registry.tsView file
65async function loadPackage(name: string) { L66: const mod = await import(name); L67: const definition = mod.TOOL_DEFINITION ?? mod.pluginCore?.toolDefinition;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

server/plugins-registry.tsView on unpkg · L65
server/worktrees.tsView file
6// parse / paths) are split out for unit tests; the rest shell out to git. L7: import { spawn } from "node:child_process"; L8: import { createHash } from "node:crypto"; ... L15: // realpath so it matches the realpaths `git worktree list` reports (e.g. macOS L16: // /tmp -> /private/tmp), which the isManagedWorktree filter relies on. L17: function worktreesBase(): string { L18: const base = process.env.MULMOTERMINAL_HOME || path.join(os.homedir(), ".mulmoterminal"); L19: try { ... L101: L102: // Run git with argv (no shell) in `cwd`; resolve { ok, stdout } — never reject, so L103: // a missing git / non-repo dir is just `ok:false` and the caller falls back.
Low
Weak Crypto

Package source references weak cryptographic algorithms.

server/worktrees.tsView on unpkg · L6
dist/assets/mermaid-parser.core-DC7NPJ_M-gJ-cjH2L.jsView file
46contains invisible/control Unicode U+FEFF (zero width no-break space) \r \v \xA0            \u2028\u2029   <U+FEFF>`.split(``);function ka(e){let t=typeof e==`string`?new RegExp(e):e;return Oa.some(e=>t.test(e))}s(ka,`isWhitespace`);function Aa(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}s(Aa,`escapeReg
Critical
Trojan Source Unicode

Source contains bidi control or invisible Unicode characters associated with Trojan Source attacks.

dist/assets/mermaid-parser.core-DC7NPJ_M-gJ-cjH2L.jsView on unpkg · L46
dist/assets/material-symbols-outlined-DKJDg2oJ.woff2View file
path = dist/assets/material-symbols-outlined-DKJDg2oJ.woff2 kind = high_entropy_blob sizeBytes = 3960064 magicHex = [redacted]
High
Ships High Entropy Blob

Package ships high-entropy non-source blobs.

dist/assets/material-symbols-outlined-DKJDg2oJ.woff2View on unpkg
dist/assets/index-BQm57UKf.jsView file
path = dist/assets/index-BQm57UKf.js kind = oversized_source_file sizeBytes = 2673542 magicHex = [redacted]
High
Oversized Source File

Package contains source files above the static scanner size ceiling.

dist/assets/index-BQm57UKf.jsView on unpkg

Findings

1 Critical7 High5 Medium6 Low
CriticalTrojan Source Unicodedist/assets/mermaid-parser.core-DC7NPJ_M-gJ-cjH2L.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processbin/mulmoterminal.js
HighShellserver/pick-file.ts
HighEntrypoint Build Divergencebin/mulmoterminal.js
HighSame File Env Network Executionbin/mulmoterminal.js
HighShips High Entropy Blobdist/assets/material-symbols-outlined-DKJDg2oJ.woff2
HighOversized Source Filedist/assets/index-BQm57UKf.js
MediumDynamic Requireserver/plugins-registry.ts
MediumNetwork
MediumEnvironment Vars
MediumProtestware
MediumStructural Risk Force Deep Review
LowScripts Present
LowWeak Cryptoserver/worktrees.ts
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings