registry  /  @jhizzard/termdeck  /  1.12.0

@jhizzard/termdeck@1.12.0

Browser-based terminal multiplexer with metadata overlays, panel flashback memory recall, and AI-aware session management

AI Security Review

scanned 4d ago · by lpm-firewall-ai

No confirmed malicious attack surface is established. The package is a terminal multiplexer/orchestration tool, so shell spawning, local listeners, config writes, and cloud API calls are expected and user-invoked.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs termdeck, termdeck stack, or explicit init/setup commands.
Impact
Expected local terminal and setup behavior; no unconsented install-time or import-time compromise found.
Mechanism
User-invoked terminal server, setup wizards, MCP/config helpers, and Supabase/OpenAI/Anthropic integrations.
Rationale
Static inspection found high-risk primitives, but they are consistent with a user-invoked browser terminal multiplexer and setup tool and are not activated by npm lifecycle hooks or import-time behavior. The source includes guardrails around auth/non-loopback binding and token propagation, with no concrete exfiltration or covert payload path identified.
Evidence
package.jsonpackages/cli/src/index.jspackages/cli/src/stack.jspackages/cli/src/init-rumen.jspackages/cli/src/mcp-config.jspackages/server/src/index.jspackages/server/src/spawn-shell.jsdoctrine/index.js~/.termdeck/config.yaml~/.termdeck/secrets.env~/.termdeck/termdeck.db~/.claude.json~/.claude/mcp.json~/.claude/hooks/memory-session-end.js~/.claude/hooks/memory-pre-compact.js
Network endpoints7
127.0.0.1:<port>localhost:<port>registry.npmjs.org/-/package/@jhizzard%2Ftermdeck/dist-tagsapi.openai.com/v1/embeddingsapi.anthropic.com/v1/messages<project-ref>.supabase.co/functions/v1/rumen-tick<project-ref>.supabase.co/functions/v1/graph-inference

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • packages/cli/src/index.js uses child_process to launch/reclaim TermDeck processes at runtime.
  • packages/server/src/index.js exposes an Express/WebSocket PTY terminal server and spawns shells on user session requests.
  • packages/cli/src/init-rumen.js deploys Supabase functions and sets secrets, but only via explicit init --rumen flow.
  • packages/cli/src/mcp-config.js can write ~/.claude.json MCP config, but only through installer/helper calls, not lifecycle hooks.
Evidence against
  • package.json has no preinstall/install/postinstall lifecycle scripts.
  • Default CLI/server path is user-invoked via bin termdeck or npm start, not import-time execution.
  • packages/cli/src/index.js has non-loopback bind guard requiring auth token.
  • packages/server/src/index.js excludes management tokens such as SUPABASE_ACCESS_TOKEN, GITHUB_TOKEN, NPM_TOKEN from PTY env propagation.
  • Network endpoints are package-aligned: local server, npm registry update check, Supabase/OpenAI/Anthropic setup and memory features.
  • No evidence of credential harvesting/exfiltration, persistence outside documented config/setup, destructive payload, or dependency confusion.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 87 file(s), 1.61 MB of source, external domains: 127.0.0.1, api.anthropic.com, api.openai.com, api.supabase.com, deno.com, deno.land, github.com, grok.com, pkg.cloudflare.com, registry.npmjs.org, supabase.com, www.apple.com, xxxxxx.supabase.co, xyz.supabase.co, your-project.supabase.co

Source & flagged code

8 flagged · loading source
doctrine/index.jsView file
9// - vanilla JS / CommonJS / zero build / ZERO non-builtin deps. (node:fs, L10: // path, os, child_process only. better-sqlite3 is NEVER required here — L11: // the db handle is dependency-injected; doctrine opens no DB file.)
High
Child Process

Package source references child process execution.

doctrine/index.jsView on unpkg · L9
13// path. Bad inputs log one `[doctrine]` warning and degrade gracefully. L14: // - NO work at require() time. Requiring this module only defines functions, L15: // so `database.js` can require it cheaply for the DDL.
Medium
Dynamic Require

Package source references dynamic require/import behavior.

doctrine/index.jsView on unpkg · L13
packages/cli/src/init-bridge.jsView file
27// ~/.cloudflared/config.yml (tunnel id from the credentials JSON, L28: // ingress → http://127.0.0.1:8870). Existing files are backed up L29: // before any overwrite and a foreign (non-wizard) config.yml is never ... L33: // unit + timer → ~/.config/systemd/user/ on linux — then PRINTS the L34: // operator `launchctl load -w` / `systemctl enable` steps. It never L35: // runs launchctl/systemctl itself (ORCH decision 2026-06-11 20:58). ... L68: // L69: // Exit codes: 0 ok · 2 input/validation error · 3 tunnel credentials L70: // pending or ambiguous (resume with `--yes` / `--tunnel-id` after the ... L81: const os = require('os'); L82: const { execSync } = require('child_process'); L83:
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

packages/cli/src/init-bridge.jsView on unpkg · L27
packages/cli/src/stack.jsView file
13const path = require('path'); L14: const http = require('http'); L15: const net = require('net'); L16: const { spawn, spawnSync } = require('child_process'); L17: ... L26: const SECRETS_FILE = path.join(CONFIG_DIR, 'secrets.env'); L27: const DEFAULT_MNESTRA_PORT = parseInt(process.env.MNESTRA_PORT || '37778', 10); L28: const MNESTRA_LOG = path.join(os.tmpdir(), 'termdeck-mnestra.log');
High
Same File Env Network Execution

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

packages/cli/src/stack.jsView on unpkg · L13
packages/cli/src/init-rumen.jsView file
136function which(bin) { L137: const r = spawnSync('which', [bin], { encoding: 'utf-8' }); L138: if (r.status !== 0) return null; L139: return (r.stdout || '').trim() || null; L140: } ... L146: fail('not found on PATH'); L147: process.stderr.write( L148: '\nInstall it first:\n' + L149: ' macOS: brew install supabase/tap/supabase\n' + L150: ' other: https://supabase.com/docs/guides/local-development/cli/getting-started\n' L151: );
High
Command Output Exfiltration

Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.

packages/cli/src/init-rumen.jsView on unpkg · L136
packages/cli/src/index.jsView file
17Cross-file remote execution chain: packages/cli/src/index.js spawns packages/cli/src/init-rumen.js; helper contains network access plus dynamic code execution. L17: const os = require('os'); L18: const { exec, execSync, spawn } = require('child_process'); L19: ... L29: // L30: // Fix: when launched in non-TTY mode (nohup detaches stdin/stdout/stderr) L31: // AND secrets.env exists with at least one key not already in process.env, L32: // spawn a detached child node with the merged env and exit the parent. The ... L63: if (argvSet.has('--service') || argvSet.has('--non-interactive')) return false; L64: const secretsPath = path.join(os.homedir(), '.termdeck', 'secrets.env'); L65: if (!fs.existsSync(secretsPath)) return false; ... L149: try { L150: const probe = execSync(`curl -sf -m 1.5 -o /dev/null -w "%{http_code}" http://127.0.0.1:${port}/api/sessions 2>/dev/null`, { encoding: 'utf8' });
High
Cross File Remote Execution Context

Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.

packages/cli/src/index.jsView on unpkg · L17
packages/server/src/index.jsView file
1Detached bundled service listener: packages/server/src/index.js launches a Node helper and exposes a broad-bound HTTP listener. L1: // TermDeck Server - main entry point L2: // Express REST API + WebSocket hub + PTY management L3: ... L10: const fs = require('fs'); L11: const dns = require('dns'); L12: const { spawn: spawnChild } = require('child_process'); L13: const { createCachedLookup, createFailureLogger } = require('./rumen-pool-resilience'); ... L30: console.error('[db] Fix:'); L31: process.stderr.write(' cd "$(npm root -g)/@jhizzard/termdeck" && npm rebuild better-sqlite3\n'); L32: console.error('[db] Then restart TermDeck. Aborting.'); ... L62: } L63: if (!pg || !process.env.DATABASE_URL) return null;
High
Spawned Bundled Service Listener

Source launches a detached bundled service that exposes a broad-bound HTTP listener.

packages/server/src/index.jsView on unpkg · L1
packages/cli/assets/supervise/termdeck-supervise.shView file
path = [redacted]-supervise.sh kind = build_helper sizeBytes = 7190 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

packages/cli/assets/supervise/termdeck-supervise.shView on unpkg

Findings

6 High6 Medium4 Low
HighChild Processdoctrine/index.js
HighShell
HighSame File Env Network Executionpackages/cli/src/stack.js
HighCommand Output Exfiltrationpackages/cli/src/init-rumen.js
HighCross File Remote Execution Contextpackages/cli/src/index.js
HighSpawned Bundled Service Listenerpackages/server/src/index.js
MediumDynamic Requiredoctrine/index.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencepackages/cli/src/init-bridge.js
MediumShips Build Helperpackages/cli/assets/supervise/termdeck-supervise.sh
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings