registry  /  @fny/joy-tmux  /  1.6.0

@fny/joy-tmux@1.6.0

joy-tmux daemon + CLI — run Claude Code sessions in tmux, bridged to the joy/Happy relay.

AI Security Review

scanned 7h 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.; previous stored version diff introduced dangerous source
Trigger
User runs the joy CLI, starts the daemon, creates sessions, or explicitly installs the user service.
Impact
Authorized Joy/Happy relay clients can run shell commands and write files in session cwd; explicit install can persist the daemon as a user service.
Mechanism
authenticated local daemon plus encrypted relay RPCs controlling tmux/Claude sessions
Rationale
Static inspection shows dangerous but package-aligned AI-agent/session-control capabilities, activated by explicit CLI/daemon use and guarded by local token plus Joy credentials. There is no npm lifecycle hook, stealth credential harvesting, unconsented foreign AI-agent control-surface mutation, or hardcoded exfiltration chain to justify a malicious block.
Evidence
package.jsonbin/joy.mjssrc/cli.tssrc/server.tssrc/transports/http.tssrc/relay/relay.tssrc/domain/fileOps.tssrc/domain/registry.tssrc/claude/hooks.ts~/.happy/access.key~/.happy/settings.json~/.happy/joy-tmux-state/daemon.json~/.happy/joy-tmux-state/claude-settings.json~/.config/systemd/user/joy-tmux.service~/Library/LaunchAgents/vip.voltai.joy-tmux.plist~/.joy/sessions/<sessionId><session cwd>
Network endpoints3
api.cluster-fluster.comexp.host/--/api/v2/push/send127.0.0.1:<PORT>

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • src/domain/fileOps.ts exposes authenticated bash exec and writeFile handlers within a session cwd.
  • src/relay/relay.ts registers relay RPC handlers over socket.io to the Joy/Happy server and receives encrypted RPC requests.
  • src/domain/registry.ts launches claude in tmux with --dangerously-skip-permissions by default for created sessions.
  • src/cli.ts explicit install command writes user systemd/launchd autostart service; update runs pnpm add -g @fny/joy-tmux@latest.
Evidence against
  • package.json has no preinstall/install/postinstall lifecycle scripts.
  • bin/joy.mjs only registers tsx and imports src/cli.ts as the explicit joy CLI entrypoint.
  • src/cli.ts service install/update paths are user-invoked commands, not npm install-time persistence.
  • src/transports/http.ts binds localhost and requires X-Joy-Token for POST/DELETE with host checks.
  • src/domain/fileOps.ts validates file paths to session cwd or a per-session media root before file reads/writes.
  • src/relay/relay.ts uses ~/.happy credentials and package-aligned endpoints rather than hardcoded credential exfiltration.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsUrlStrings
Manifest
NoLicense
scanned 41 file(s), 562 KB of source, external domains: 0.0.0.0, 127.0.0.1, api.cluster-fluster.com, claude.com, example.com, exp.host, github.com, www.apple.com

Source & flagged code

7 flagged · loading source
src/cli.tsView file
10import { homedir, platform as osPlatform } from "os"; L11: import { spawn, spawnSync } from "child_process"; L12: import { moduleDir } from "./esm";
High
Child Process

Package source references child process execution.

src/cli.tsView on unpkg · L10
10import { homedir, platform as osPlatform } from "os"; L11: import { spawn, spawnSync } from "child_process"; L12: import { moduleDir } from "./esm"; ... L14: L15: const PORT = parseInt(process.env.PORT ?? "4997"); L16: const BASE = `http://127.0.0.1:${PORT}`; L17: const HAPPY_HOME = happyHomeDir();
High
Same File Env Network Execution

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

src/cli.tsView on unpkg · L10
10import { homedir, platform as osPlatform } from "os"; L11: import { spawn, spawnSync } from "child_process"; L12: import { moduleDir } from "./esm"; ... L22: // store (…/.pnpm/@fny+joy-tmux@1.0.15_…/node_modules/@fny/joy-tmux). Baking THAT into a L23: // launchd/systemd service breaks on the next `pnpm add -g`: pnpm makes a fresh store dir L24: // for the new version and deletes the old one, so the service's server.ts path vanishes
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

src/cli.tsView on unpkg · L10
10import { homedir, platform as osPlatform } from "os"; L11: import { spawn, spawnSync } from "child_process"; L12: import { moduleDir } from "./esm"; ... L14: L15: const PORT = parseInt(process.env.PORT ?? "4997"); L16: const BASE = `http://127.0.0.1:${PORT}`; L17: const HAPPY_HOME = happyHomeDir(); L18: const STATE_DIR = joyStateDir(); ... L47: function readState(): DaemonState | null { L48: try { return JSON.parse(readFileSync(STATE_FILE, "utf8")) as DaemonState; } catch { return null; } L49: } ... L61: headers: authHeaders(),
Medium
Install Persistence

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

src/cli.tsView on unpkg · L10
src/domain/operations.tsView file
48// like `--import tsx` + the script path) so the replacement runs the same way. L49: const argv = [process.execPath, ...process.execArgv, ...process.argv.slice(1)]; L50: const cmd = argv.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(" ");
High
Shell

Package source references shell execution.

src/domain/operations.tsView on unpkg · L48
bin/joy.mjsView file
15L16: await import(new URL('../src/cli.ts', import.meta.url).href);
Medium
Dynamic Require

Package source references dynamic require/import behavior.

bin/joy.mjsView on unpkg · L15
src/claude/session.tsView file
matchType = previous_version_dangerous_delta matchedPackage = @fny/joy-tmux@1.5.0 matchedIdentity = npm:QGZueS9qb3ktdG11eA:1.5.0 similarity = 0.950 summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta

This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.

src/claude/session.tsView on unpkg

Findings

1 Critical4 High5 Medium5 Low
CriticalPrevious Version Dangerous Deltasrc/claude/session.ts
HighChild Processsrc/cli.ts
HighShellsrc/domain/operations.ts
HighSame File Env Network Executionsrc/cli.ts
HighRuntime Package Installsrc/cli.ts
MediumDynamic Requirebin/joy.mjs
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencesrc/cli.ts
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowNo License