registry  /  @holt-os/holt  /  0.8.3

@holt-os/holt@0.8.3

An open-source personal agent OS: any LLM, private memory you can see and walk.

AI Security Review

scanned 4d ago · by lpm-firewall-ai

No confirmed malicious attack surface is established. The package is a user-invoked personal agent CLI with optional Telegram, scheduler, skills, memory, and LLM provider integrations.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
Explicit commands such as holt init, holt telegram, holt notify, holt run, holt schedule, or holt skill add.
Impact
User-requested task output may be sent to configured Telegram/API endpoints; local config, memory, aliases, schedules, and skills may be written as documented.
Mechanism
User-configured agent orchestration and optional message forwarding
Rationale
The scary primitives are reachable through documented CLI commands and prompts, with no install-time execution or hidden exfiltration path found. Telegram can forward command output, but only after user configuration of a token/chat and an explicit bot/notify/schedule flow, so it is package-aligned functionality rather than malware.
Evidence
package.jsondist/cli.jsREADME.md.holt/config.json.holt/memory/turns.jsonl.holt/memory/facts.md.holt/graph.html~/.holt/trust.json~/.holt/credentials.json~/.holt/telegram.json~/.holt/schedules.json~/.holt/skills/<name>/SKILL.md~/.zshrc~/.bashrc~/Library/LaunchAgents/com.holt.<id>.plist
Network endpoints5
api.telegram.org127.0.0.1:11434api.anthropic.com/v1/messagesapi.openai.com/v1/chat/completionsgenerativelanguage.googleapis.com/v1beta/models/...:streamGenerateContent?alt=sse

Decision evidence

public snapshot
AI called this Clean at 88.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • dist/cli.js exposes user-invoked Telegram bot/notify features that send run output or stdin text to https://api.telegram.org.
  • dist/cli.js can spawn configured agent CLIs (claude/codex/gemini), install selected CLIs, clone skill repos, and install scheduler entries, all after explicit CLI commands/prompts.
  • dist/cli.js can write ~/.zshrc/~/.bashrc or PATH shim for a custom launch alias and create launchd/cron jobs for scheduled tasks when requested.
Evidence against
  • package.json has no preinstall/install/postinstall lifecycle hooks; only bin holt -> dist/cli.js.
  • Network endpoints are package-aligned: Telegram integration, local Ollama, and user-selected Anthropic/OpenAI/Gemini API brains.
  • Telegram setup requires a bot token and allowed chat id; handler ignores other chats and runs only when user starts holt telegram.
  • Writes are documented/configuration-oriented: .holt config/memory/skills/graph, ~/.holt credentials/trust/schedules/telegram, optional alias/scheduler files.
  • No hidden dynamic eval/remote payload loading found; git clone is only for explicit holt skill add source.
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 133 KB of source, external domains: 127.0.0.1, api.anthropic.com, api.openai.com, api.telegram.org, generativelanguage.googleapis.com, github.com, ollama.com, productsdecoded.com

Source & flagged code

4 flagged · loading source
dist/cli.jsView file
13import readline from "readline"; L14: var on = process.stdout.isTTY && !process.env.NO_COLOR; L15: var wrap = (code) => (s) => on ? `\x1B[${code}m${s}\x1B[0m` : s; ... L43: }); L44: const ask = (q) => new Promise((resolve4) => { L45: if (q) process.stdout.write(q); L46: if (buffer.length) resolve4(buffer.shift()); ... L53: // src/workspace.ts L54: var GLOBAL_DIR = join(homedir(), ".holt"); L55: var TRUST_PATH = join(GLOBAL_DIR, "trust.json"); ... L66: try { L67: return JSON.parse(readFileSync(TRUST_PATH, "utf8"));
Critical
Command Output Exfiltration

Source executes local commands and sends command output to an external endpoint.

dist/cli.jsView on unpkg · L13
13Trigger-reachable chain: manifest.bin -> dist/cli.js L13: import readline from "readline"; L14: var on = process.stdout.isTTY && !process.env.NO_COLOR; L15: var wrap = (code) => (s) => on ? `\x1B[${code}m${s}\x1B[0m` : s; ... L43: }); L44: const ask = (q) => new Promise((resolve4) => { L45: if (q) process.stdout.write(q); L46: if (buffer.length) resolve4(buffer.shift()); ... L53: // src/workspace.ts L54: var GLOBAL_DIR = join(homedir(), ".holt"); L55: var TRUST_PATH = join(GLOBAL_DIR, "trust.json"); ... L66: try { L67: return JSON.parse(readFileSync(TRUST_PATH, "utf8"));
Critical
Trigger Reachable Dangerous Capability

A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.

dist/cli.jsView on unpkg · L13
199// src/brains.ts L200: import { spawn, spawnSync } from "child_process"; L201: var MAX_REPLAY_TURNS = 12;
High
Child Process

Package source references child process execution.

dist/cli.jsView on unpkg · L199
13import readline from "readline"; L14: var on = process.stdout.isTTY && !process.env.NO_COLOR; L15: var wrap = (code) => (s) => on ? `\x1B[${code}m${s}\x1B[0m` : s; ... L43: }); L44: const ask = (q) => new Promise((resolve4) => { L45: if (q) process.stdout.write(q); L46: if (buffer.length) resolve4(buffer.shift()); ... L53: // src/workspace.ts L54: var GLOBAL_DIR = join(homedir(), ".holt"); L55: var TRUST_PATH = join(GLOBAL_DIR, "trust.json"); ... L66: try { L67: return JSON.parse(readFileSync(TRUST_PATH, "utf8"));
Medium
Install Persistence

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

dist/cli.jsView on unpkg · L13

Findings

2 Critical2 High4 Medium4 Low
CriticalCommand Output Exfiltrationdist/cli.js
CriticalTrigger Reachable Dangerous Capabilitydist/cli.js
HighChild Processdist/cli.js
HighShell
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/cli.js
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings