registry  /  claude-recall  /  0.28.0

claude-recall@0.28.0

Persistent memory for Claude Code and Pi with native Skills integration, automatic capture, failure learning, and project scoping

AI Security Review

scanned 2h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malicious payload or exfiltration chain was found. The real risk is install-time first-party Claude hook repair across user/project settings plus explicit setup that installs Claude hooks and skills.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm postinstall for repair; user-invoked claude-recall setup --install or upgrade for broader actions
Impact
Can modify existing claude-recall hook commands in Claude settings during install; explicit setup can install/replace claude-recall hooks and skills in a project.
Mechanism
first-party AI-agent extension lifecycle mutation
Rationale
The package has notable AI-agent lifecycle risk because postinstall can mutate Claude settings, but the mutation is constrained to first-party claude-recall hook repair and I found no credential theft, destructive behavior, stealth persistence, or remote payload execution. This fits a warn/suspicious verdict rather than publish-block malicious behavior.
Evidence
package.jsonscripts/postinstall.jsscripts/uninstall.jsdist/cli/commands/repair.jsdist/cli/claude-recall-cli.js.claude/hooks/search_enforcer.pydist/hooks/llm-classifier.jsdist/memory/database-adapter.js~/.claude-recall/~/.claude-recall/projects.json~/.claude/settings.json~/.claude/settings.local.json<project>/.claude/settings.json<project>/.claude/settings.local.json<project>/.claude/hooks/search_enforcer.py<project>/.claude/skills/
Network endpoints4
registry.npmjs.org/git+https://github.com/raoulbia-ai/claude-recall.gitgithub.com/raoulbia-ai/claude-recall#readmegithub.com/raoulbia-ai/claude-recall/issues

Decision evidence

public snapshot
AI called this Suspicious at 84.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • package.json runs postinstall: node scripts/postinstall.js || true
  • scripts/postinstall.js creates ~/.claude-recall and writes projects.json for cwd when not inside package/node_modules
  • scripts/postinstall.js executes dist CLI repair --auto --scope all during install
  • dist/cli/commands/repair.js scans ~/.claude and project .claude/settings*.json under $HOME and can rewrite existing claude-recall hook commands with backups
  • dist/cli/claude-recall-cli.js explicit setup --install writes .claude/hooks/search_enforcer.py, .claude/skills, and replaces settings.hooks
  • hooks/llm-classifier.js sends classified user/session text to Anthropic SDK when ANTHROPIC_API_KEY is present
Evidence against
  • postinstall comments and code do not auto-run setup --install or add MCP servers
  • repair only proposes fixes for commands classified as claude-recall hooks with missing absolute script paths
  • repair writes backups before changing settings files
  • search_enforcer.py is a local gating hook; no network or credential harvesting seen
  • runtime npm install/npm view is confined to explicit claude-recall upgrade command
  • database-adapter dynamic require loads better-sqlite3/sql.js local dependencies, not remote code
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemShell
Supply chain
HighEntropyStrings
ManifestNo manifest risk signals triggered.
scanned 84 file(s), 1.05 MB of source

Source & flagged code

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

Package defines install-time lifecycle scripts.

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

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

package.jsonView on unpkg
dist/memory/database-adapter.jsView file
56} L57: exec(sql) { L58: this.db.exec(sql);
High
Child Process

Package source references child process execution.

dist/memory/database-adapter.jsView on unpkg · L56
36exports.createDatabaseAdapter = createDatabaseAdapter; L37: const fs = __importStar(require("fs")); L38: const path = __importStar(require("path"));
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/memory/database-adapter.jsView on unpkg · L36
dist/cli/claude-recall-cli.jsView file
414// Run npm install -g, streaming output so the user sees progress / errors live. L415: // shell: true on Windows — npm is npm.cmd there and a bare spawnSync ENOENTs. L416: const install = spawnSync('npm', ['install', '-g', 'claude-recall@latest'], {
High
Shell

Package source references shell execution.

dist/cli/claude-recall-cli.jsView on unpkg · L414
scripts/postinstall.jsView file
8Install-time AI-agent control hijack evidence: L13: if (!fs.existsSync(dest)) { L14: fs.mkdirSync(dest, { recursive: true }); L15: } ... L25: } else { L26: fs.copyFileSync(srcPath, destPath); L27: } ... L48: // Set up database location in user's home directory L49: const dbDir = path.join(os.homedir(), '.claude-recall'); L50: L51: if (!fs.existsSync(dbDir)) { L52: fs.mkdirSync(dbDir, { recursive: true }); L53: console.log(`📁 Created database directory: ${dbDir}`); Payload evidence from .claude/hooks/search_enforcer.py: L8: State file: ~/.claude-recall/hook-state/{session_id}.json L9: Exit codes: 0 = allow, 2 = block L10: """ ... L51: 'git rebase', 'git checkout', 'git switch', 'git cherry-pick', L52: 'npm install', 'npm version', 'npm publish', 'npm pack', L53: 'npx',
Critical
Ai Agent Control Hijack

Install-time source drops package-supplied AI-agent/MCP control files or instructions.

scripts/postinstall.jsView on unpkg · L8
dist/services/claude-json-watcher.jsView file
195console.log('[WATCHER] Spawning capture process...'); L196: const captureProcess = (0, child_process_1.spawn)('npx', ['claude-recall', 'capture', 'user-prompt'], { L197: stdio: ['pipe', 'pipe', 'pipe']
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

dist/services/claude-json-watcher.jsView on unpkg · L195
.claude/hooks/search_enforcer.pyView file
path = .claude/hooks/search_enforcer.py kind = payload_in_excluded_dir sizeBytes = 9759 magicHex = [redacted]
High
Payload In Excluded Dir

Package hides binary, compressed, or executable-looking payloads in test/fixture/hidden paths.

.claude/hooks/search_enforcer.pyView on unpkg
path = .claude/hooks/search_enforcer.py kind = build_helper sizeBytes = 9759 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

.claude/hooks/search_enforcer.pyView on unpkg

Findings

1 Critical5 High5 Medium4 Low
CriticalAi Agent Control Hijackscripts/postinstall.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/memory/database-adapter.js
HighShelldist/cli/claude-recall-cli.js
HighRuntime Package Installdist/services/claude-json-watcher.js
HighPayload In Excluded Dir.claude/hooks/search_enforcer.py
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requiredist/memory/database-adapter.js
MediumEnvironment Vars
MediumShips Build Helper.claude/hooks/search_enforcer.py
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowFilesystem
LowHigh Entropy Strings