registry  /  terminalhire  /  0.10.11

terminalhire@0.10.11

Local-first job matching for developers — ambient job matches in the Claude Code spinner. Matching runs on your machine; your profile never leaves it.

AI Security Review

scanned 4d ago · by lpm-firewall-ai

No confirmed malicious attack surface was established. Risky primitives are present, but they are user-invoked CLI behavior for job matching, GitHub auth, profile storage, and Claude spinner/status display integration rather than install-time control hijack.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
User runs terminalhire CLI commands; npm postinstall only prints an activation notice.
Impact
User-invoked commands may write ~/.terminalhire state and optional Claude spinner settings, and may call package service/GitHub/public job APIs.
Mechanism
user-consented CLI integration and package-aligned network/profile features
Rationale
Static source inspection contradicts the malicious scanner hint: postinstall is a notice only, and AI/Claude settings changes are gated behind explicit user commands and typed consent. The remaining network, local profile, and child_process behavior is package-aligned for a developer job-matching CLI.
Evidence
package.jsonpostinstall.jsinstall.jsdist/bin/jpi-dispatch.jsREADME.md~/.terminalhire/config.json~/.terminalhire/profile.enc~/.terminalhire/key~/.terminalhire/github-token.enc~/.terminalhire/index-cache.json~/.terminalhire/project.json~/.terminalhire/claims.json~/.terminalhire/chat-identity.enc~/.terminalhire/chat-peers.json~/.terminalhire/chat-reads.json~/.claude/settings.json~/.claude/projects
Network endpoints12
terminalhire.comwww.terminalhire.comapi.github.comgithub.com/login/device/codegithub.com/login/oauth/access_tokenboards-api.greenhouse.ioapi.ashbyhq.comapi.lever.cohimalayas.appweworkremotely.comhn.algolia.comapi.opire.dev

Decision evidence

public snapshot
AI called this Clean at 90.0% confidence as Benign with low false-positive risk.
Evidence for block
  • package.json has a postinstall lifecycle script
  • install.js and dist/bin/jpi-dispatch.js can write ~/.claude/settings.json spinnerVerbs/spinnerTipsOverride
  • dist/bin/jpi-dispatch.js reads ~/.claude/projects for trajectory/profile features
  • CLI includes network calls to terminalhire.com, www.terminalhire.com, api.github.com, GitHub OAuth, and public job-board APIs
  • CLI uses child_process spawn/spawnSync/execFile for user-invoked onboarding and GitHub PR workflows
Evidence against
  • postinstall.js is print-only: no imports of install.js, no file writes, no network calls, exits 0
  • Claude settings writes require explicit user commands such as terminalhire init, terminalhire spinner --on, or node install.js with typed yes
  • No PreToolUse/Stop hook injection found; only spinnerVerbs/spinnerTipsOverride/statusLine-related user-facing settings are referenced
  • GitHub token/profile files are stored locally under ~/.terminalhire and encrypted where applicable
  • Network endpoints are aligned with job matching, GitHub login/profile, chat/sync, and public job ingestion functionality
  • No obfuscation, native binary loading, destructive persistence, or install-time exfiltration found
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 38 file(s), 2.91 MB of source, external domains: 127.0.0.1, api.ashbyhq.com, api.github.com, api.lever.co, api.opire.dev, apply.workable.com, boards-api.greenhouse.io, github.com, himalayas.app, hn.algolia.com, jobs.ashbyhq.com, jobs.lever.co, news.ycombinator.com, terminalhire.com, weworkremotely.com, www.terminalhire.com

Source & flagged code

8 flagged · loading source
package.jsonView file
scripts.postinstall = node ./postinstall.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node ./postinstall.js
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
dist/bin/jpi-init.jsView file
7import { createInterface } from "readline"; L8: import { spawnSync, spawn } from "child_process"; L9: import { homedir } from "os";
High
Child Process

Package source references child process execution.

dist/bin/jpi-init.jsView on unpkg · L7
install.jsView file
52if (existsSync(c)) { L53: try { return await import(pathToFileURL(c).href); } catch { /* try next */ } L54: }
Medium
Dynamic Require

Package source references dynamic require/import behavior.

install.jsView on unpkg · L52
dist/bin/jpi-sync.jsView file
1027try { L1028: const child = spawn(cmd, args, { stdio: "ignore", detached: true }); L1029: child.on("error", () => { ... L1036: // bin/jpi-sync.js L1037: var TH_DIR = process.env["TERMINALHIRE_DIR"] || join3(homedir2(), ".terminalhire"); L1038: var TIER1_MARKER = join3(TH_DIR, "tier1.json"); L1039: var API_URL = process.env["TERMINALHIRE_API_URL"] || process.env["JPI_API_URL"] || "https://terminalhire.com"; L1040: var SYNC_BASE = "https://www.terminalhire.com";
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/bin/jpi-sync.jsView on unpkg · L1027
99{ id: "azure", synonyms: ["microsoft-azure"], related: [{ to: "aws", w: 0.4 }] }, L100: { id: "ci-cd", synonyms: ["cicd", "jenkins", "circleci", "circle-ci", "travis"], related: [{ to: "github-actions", w: 0.6 }, { to: "gitlab-ci", w: 0.6 }] }, L101: { id: "github-actions", parents: ["ci-cd"], synonyms: ["github-action"] }, ... L191: { id: "microservices" }, L192: { id: "websockets", synonyms: ["ws", "socket.io"], related: [{ to: "realtime", w: 0.6 }] }, L193: { id: "realtime", synonyms: ["real-time"] }, ... L744: "use strict"; L745: KDF_INFO = Buffer.from("terminalhire-chat-v1"); L746: } ... L975: init_src(); L976: TERMINALHIRE_DIR = join2(homedir(), ".terminalhire"); L977: PROFILE_FILE = join2(TERMINALHIRE_DIR, "profile.enc");
High
Sandbox Evasion Gated Capability

Source gates dangerous network, credential, or execution behavior behind CI, host, platform, time, or geo fingerprint checks.

dist/bin/jpi-sync.jsView on unpkg · L99
dist/bin/jpi-dispatch.jsView file
matchType = previous_version_dangerous_delta matchedPackage = terminalhire@0.10.10 matchedIdentity = npm:dGVybWluYWxoaXJl:0.10.10 similarity = 0.789 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.

dist/bin/jpi-dispatch.jsView on unpkg
31Cross-file remote execution chain: dist/bin/jpi-dispatch.js spawns dist/bin/jpi-link.js; helper contains network access plus dynamic code execution. L31: function terminalhireDir() { L32: return join(homedir(), ".terminalhire"); L33: } ... L49: if (fromFile) return fromFile; L50: const env = process.env["TERMINALHIRE_WEB_SESSION"]; L51: return typeof env === "string" && env.length > 0 ? env : null; ... L90: const raw = readFileSync2(CONFIG_FILE, "utf8"); L91: const parsed = JSON.parse(raw); L92: return { ...DEFAULT_CONFIG, ...parsed }; ... L182: const candidates = [ L183: join3(__dirname, "..", "..", "package.json"), L184: join3(__dirname, "..", "package.json")
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/bin/jpi-dispatch.jsView on unpkg · L31

Findings

1 Critical6 High5 Medium5 Low
CriticalPrevious Version Dangerous Deltadist/bin/jpi-dispatch.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/bin/jpi-init.js
HighShell
HighSame File Env Network Executiondist/bin/jpi-sync.js
HighSandbox Evasion Gated Capabilitydist/bin/jpi-sync.js
HighCross File Remote Execution Contextdist/bin/jpi-dispatch.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requireinstall.js
MediumNetwork
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings