registry  /  caveat-cli  /  0.16.0

caveat-cli@0.16.0

Codex hooks feature key is deprecated; upgrade to 0.16.1 or later.

Long-term memory CLI for Claude Code and Codex (markdown + SQLite FTS5 + MCP + hooks)

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No install-time execution occurs. Explicit setup commands modify Claude Code and Codex configuration to register Caveat-owned MCP/hooks, whose handlers process agent prompts and tool-event data locally.

Static reason
One or more suspicious static signals were detected.
Trigger
User runs `caveat init` or `caveat codex-hook install`; registered hooks then run on agent events.
Impact
User-approved persistence in agent configuration; hooks can receive prompt and tool-event content after setup.
Mechanism
Explicit first-party AI-agent extension registration and local hook processing.
Rationale
Not malicious by static source inspection, but it intentionally persists first-party hooks into AI-agent configuration after explicit user commands. Policy classifies this guarded extension setup as warn rather than block.
Evidence
package.jsondist/caveat.jsdist/index.js~/.claude/settings.json~/.codex/hooks.json~/.codex/config.toml~/.caveat/~/.caveatrc.json

Decision evidence

public snapshot
AI called this Suspicious at 93.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for warning
  • `dist/index.js` `init` explicitly registers Claude MCP/hooks and Codex hooks.
  • `installClaudeIntegration` writes `~/.claude/settings.json` and invokes `claude mcp add` via shell.
  • `installCodexHooks` enables `codex_hooks` and writes `~/.codex/hooks.json`/`config.toml`.
  • Hook handlers read prompt/tool-event input and start a detached local worker.
Evidence against
  • `package.json` has no preinstall/install/postinstall lifecycle scripts.
  • All integration writes are reached through explicit `caveat init` or `caveat codex-hook install` commands.
  • Hook entries invoke this package's own CLI subcommands and preserve backups.
  • No package-originated HTTP client/exfiltration path was found; reported fetch use is bundled server framework code.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShell
Supply chain
HighEntropyStringsUrlStrings
ManifestNo manifest risk signals triggered.
scanned 4 file(s), 2.10 MB of source, external domains: developer.mozilla.org, developers.cloudflare.com, gist.github.com, github.com, hono.dev, json-schema.org, mathiasbynens.be, raw.githubusercontent.com, spec.openapis.org, stackoverflow.com, tools.ietf.org, www.w3.org

Source & flagged code

5 flagged · loading source
dist/index.jsView file
6877// src/commands/init.ts L6878: import { spawnSync as spawnSync4 } from "node:child_process"; L6879: import { existsSync as existsSync5, mkdirSync as mkdirSync3, readdirSync, renameSync, rmdirSync, writeFileSync as writeFileSync4 } from "node:fs";
High
Child Process

Package source references child process execution.

dist/index.jsView on unpkg · L6877
6965const line = [CLAUDE_BIN, ...args].map(shellQuote).join(" "); L6966: return spawnSync(line, { shell: true, encoding: "utf-8" }); L6967: }
High
Shell

Package source references shell execution.

dist/index.jsView on unpkg · L6965
56Cross-file remote execution chain: dist/index.js spawns dist/server-SZAVLE56.js; helper contains network access plus dynamic code execution. L56: search, L57: stderrLogger, L58: stopReminderText, ... L1261: // validation function arguments L1262: data: new codegen_1.Name("data"), L1263: // data passed to validation function ... L2288: id = normalizeId(id); L2289: return resolver.resolve(baseId, id); L2290: } ... L3148: for (i = 0; i < input.length; i++) { L3149: code = input[i].charCodeAt(0); L3150: if (code === 48) {
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.jsView on unpkg · L56
dist/chunk-ZNAFNCPW.jsView file
2import { createRequire as __caveat_createRequire } from 'node:module'; L3: const require = __caveat_createRequire(import.meta.url); L4: var __create = Object.create;
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/chunk-ZNAFNCPW.jsView on unpkg · L2
1383if (ast.body[0].expression.body.type === "BlockStatement") { L1384: return new Function(params, source.slice(body[0] + 1, body[1] - 1)); L1385: }
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/chunk-ZNAFNCPW.jsView on unpkg · L1383

Findings

3 High3 Medium5 Low
HighChild Processdist/index.js
HighShelldist/index.js
HighCross File Remote Execution Contextdist/index.js
MediumDynamic Requiredist/chunk-ZNAFNCPW.js
MediumNetwork
MediumEnvironment Vars
LowScripts Present
LowEvaldist/chunk-ZNAFNCPW.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings