registry  /  @threadbase-sh/streamer  /  1.22.0

@threadbase-sh/streamer@1.22.0

PTY session management, WebSocket streaming, and REST API server for Claude Code conversations

AI Security Review

scanned 12d ago · by lpm-firewall-ai

No confirmed malicious attack surface was established. The risky primitives are expected for a PTY/WebSocket Claude streamer and are gated by CLI invocation, API keys, local auth choices, or configured webhook secrets.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm install runs postinstall chmod; runtime behavior starts when user invokes threadbase-streamer commands such as serve, update, cache, pair, or set-key.
Impact
Can run and control local Claude sessions and update its own install when explicitly configured/invoked; no evidence of covert exfiltration or malicious install-time execution.
Mechanism
PTY session manager, local HTTP/WebSocket API server, and optional verified GitHub-release self-updater
Rationale
Static inspection shows high-risk capabilities, but they match the package's stated PTY/WebSocket Claude streamer and updater functionality and are not activated covertly at install/import time. The postinstall hook is narrow dependency permission repair, not payload execution or AI-agent control-surface mutation.
Evidence
package.jsondist/index.cjsdist/cli.cjsdist/launchd-entry.cjsnode_modules/node-pty/prebuilds/<platform-arch>/spawn-helper~/.threadbase/server.yaml~/.threadbase/update.yaml~/.threadbase/cache/cache.db~/.claude/projects/<encoded-project>/<session>.jsonl~/.threadbase/releases~/.threadbase/downloads
Network endpoints7
localhost:8766ws://localhost:8766/ws127.0.0.1:<port>/api/sessionsapi.github.comlocalhost:8081localhost:19006localhost:3000

Decision evidence

public snapshot
AI called this Clean at 86.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • package.json defines postinstall, but it only chmods node-pty prebuilds/<platform>/spawn-helper and suppresses errors.
  • dist/index.cjs and dist/cli.cjs spawn Claude CLI/PTYs and expose HTTP/WebSocket controls for sessions.
  • dist/cli.cjs has an authenticated update flow that fetches GitHub release assets and swaps local install files.
Evidence against
  • No install-time network, credential harvesting, persistence, or payload download found in package.json postinstall.
  • dist/index.cjs has no main/import-time server start; exports are library APIs only.
  • Child process use is package-aligned: finding claude, spawning claude PTYs, launchctl/systemctl/schtasks restart, and update self-reexec.
  • Network endpoints are local server routes, Temporal/DB configuration, and user-invoked GitHub updater with manifest sha256/size verification.
  • /api/__update requires configured webhook_secret HMAC before spawning the updater.
  • File access is aligned with config, cache, Claude conversation JSONL watching, migrations, and updater state.
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 4 file(s), 1.34 MB of source, external domains: github.com, json-schema.org
Oversized source lightweight scan
dist/cli.cjs6.81 MB file, sampled 256 KB
FilesystemNetworkChildProcessEnvironmentVarsCryptoHighEntropyStrings

Source & flagged code

7 flagged · loading source
package.jsonView file
scripts.postinstall = node -e "try{require('fs').chmodSync(require('path').join(require.resolve('node-pty'),'..','..','prebuilds',process.platform+'-'+process.arch,'spawn-helper'),0o755)}catch{}"
Critical
Red Install Lifecycle Script

Install-time lifecycle script matches a deterministic static-gate block pattern.

package.jsonView on unpkg
scripts.postinstall = node -e "try{require('fs').chmodSync(require('path').join(require.resolve('node-pty'),'..','..','prebuilds',process.platform+'-'+process.arch,'spawn-helper'),0o755)}catch{}"
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
dist/index.jsView file
478// src/process-discovery.ts L479: import { execFile } from "child_process"; L480: import { platform as platform2 } from "os";
High
Child Process

Package source references child process execution.

dist/index.jsView on unpkg · L478
55} L56: function readAgentConfig(env = process.env) { L57: const enabled = isTruthy(env.MULTI_AGENT_FLOW); ... L160: try { L161: return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); L162: } catch { ... L179: const app = new Hono(); L180: app.post("/sessions/:sessionId/progress", async (c) => { L181: if (!deps.agentConfig.enabled) { ... L280: import { join as join2 } from "path"; L281: var CONFIG_DIR = join2(homedir(), ".threadbase"); L282: var CONFIG_FILE = join2(CONFIG_DIR, "server.yaml");
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/index.jsView on unpkg · L55
dist/index.cjsView file
101Cross-file remote execution chain: dist/index.cjs spawns dist/index.js; helper contains network access plus dynamic code execution. L101: } L102: function readAgentConfig(env = process.env) { L103: const enabled = isTruthy(env.MULTI_AGENT_FLOW); ... L206: try { L207: return import_node_crypto.default.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); L208: } catch { ... L225: const app = new import_hono.Hono(); L226: app.post("/sessions/:sessionId/progress", async (c) => { L227: if (!deps.agentConfig.enabled) { ... L326: var import_path = require("path"); L327: var CONFIG_DIR = (0, import_path.join)((0, import_os.homedir)(), ".threadbase"); L328: var CONFIG_FILE = (0, import_path.join)(CONFIG_DIR, "server.yaml");
High
Cross File Remote Execution Context

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

dist/index.cjsView on unpkg · L101
dist/cli.cjsView file
path = dist/cli.cjs kind = oversized_source_file sizeBytes = 7139667 magicHex = [redacted]
High
Oversized Source File

Package contains source files above the static scanner size ceiling.

dist/cli.cjsView on unpkg
path = dist/cli.cjs kind = oversized_cli_entrypoint sizeBytes = 7139667 magicHex = [redacted]
Medium
Oversized Cli Entrypoint

Package contains an oversized executable-looking CLI entrypoint.

dist/cli.cjsView on unpkg

Findings

1 Critical5 High4 Medium6 Low
CriticalRed Install Lifecycle Scriptpackage.json
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/index.js
HighShell
HighCross File Remote Execution Contextdist/index.cjs
HighOversized Source Filedist/cli.cjs
MediumNetwork
MediumEnvironment Vars
MediumOversized Cli Entrypointdist/cli.cjs
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowWeak Cryptodist/index.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings