registry  /  @truealter/cli  /  0.8.28

@truealter/cli@0.8.28

~Alter identity CLI - login once, authenticated everywhere.

AI Security Review

scanned 10d ago · by lpm-firewall-ai

No confirmed malicious attack surface is established. Risky primitives are aligned with an identity CLI, explicit Claude-hook installer, self-update flow, Obsidian plugin pairing, and diagnostics.

Static reason
One or more suspicious static signals were detected.; previous stored version diff introduced dangerous source
Trigger
User invokes CLI commands such as alter hooks install, login, update, pair, alignment, or uses the bundled Obsidian plugin.
Impact
Can modify Alter/Claude/Obsidian user configuration and contact TrueAlter services when requested; no evidence of unconsented exfiltration, persistence, destructive behavior, or install-time compromise.
Mechanism
User-invoked identity CLI with local config writes, authenticated API calls, optional hooks/statusline setup, and release update checks.
Rationale
Static inspection found sensitive capabilities, but they are exposed as explicit product features for an identity CLI and companion Obsidian/Claude integrations, not as hidden install/import-time behavior. The scanner's dangerous-delta and hook/persistence signals are explained by shipped user-invoked integrations with bounded targets and uninstall paths.
Evidence
package.jsondist/index.jsdist/lib/self-update.jsdist/commands/hooks.jsdist/commands/alignment.jsdist/lib/cosmetics/inscribe.jsdist/embedded-plugins/alter-obsidian-plugin/main.jsdist/auth.jsdist/assets/hooks/destructive-bash-gate.shdist/assets/hooks/cc-broadcast.shdist/secure-store.js
Network endpoints5
registry.npmjs.org/@truealter/cliapi.truealter.commcp.truealter.comreleases.truealter.comtruealter.com

Decision evidence

public snapshot
AI called this Clean at 82.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • package.json prepare can run git config core.hooksPath, but only when .githooks and .git/HEAD exist and package name matches local dev package.
  • dist/commands/hooks.js can write .claude/hooks scripts and .claude/settings.json hook bindings.
  • dist/embedded-plugins/alter-obsidian-plugin/main.js reads Alter session data and can POST consent/ingest data to api.truealter.com after plugin pairing.
Evidence against
  • package.json has no install/postinstall hook; prepare is gated away from global installs and appears dev-repo hook setup.
  • dist/index.js dispatches user-invoked CLI commands; startup only sweeps credential residue, checks update/preflight, and does not harvest files.
  • dist/commands/hooks.js requires explicit alter hooks install/uninstall and marks/removes its own Claude hook entries.
  • dist/commands/alignment.js spawns only an absolute ALTER_MCP_CMD supplied by the user and rejects relative/shell-metacharacter command strings.
  • dist/lib/self-update.js checks npm registry for @truealter/cli and verifies releases before silent background install; otherwise prompts.
  • Credential/session access in dist/auth.js and related commands is package-aligned for login, secure storage, API auth, and diagnostics.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNetworkShell
Supply chain
HighEntropyStringsObfuscatedUrlStrings
ManifestNo manifest risk signals triggered.
scanned 167 file(s), 1.26 MB of source, external domains: 127.0.0.1, api.github.com, api.truealter.com, aur.archlinux.org, github.com, mcp.truealter.com, objects.githubusercontent.com, obsidian.md, registry.npmjs.org, releases.truealter.com, starship.rs, token.actions.githubusercontent.com, truealter.com

Source & flagged code

8 flagged · loading source
dist/cc-wrapper/pty-adapter.jsView file
1import * as childProcess from "node:child_process"; L2: export async function spawnCcUnderPty(opts) {
High
Child Process

Package source references child process execution.

dist/cc-wrapper/pty-adapter.jsView on unpkg · L1
4const moduleId = "node-pty"; L5: const pty = (await import(moduleId)); L6: const proc = pty.spawn(opts.file, opts.args, {
Medium
Dynamic Require

Package source references dynamic require/import behavior.

dist/cc-wrapper/pty-adapter.jsView on unpkg · L4
dist/commands/hooks.jsView file
173: `D="${hooksDir}"; [ -x "$D/_verify.sh" ] && bash "$D/_verify.sh" >/dev/null && [ -x ${scriptPath} ] && bash ${scriptPath}${argSuffix}; exit 0`; L174: return `bash -c '${body} ${marker}'`; L175: }
High
Shell

Package source references shell execution.

dist/commands/hooks.jsView on unpkg · L173
dist/lib/cosmetics/inscribe.jsView file
61if (surface.id === "pfetch") { L62: return inscribePfetch(surface, ctx); L63: } ... L178: function expandHome(p) { L179: return p.replace(/^\$HOME/, os.homedir()); L180: } L181: function ccStatuslineWardrobePath() { L182: const base = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config"); L183: return path.join(base, "alter", "statusline-wardrobe.json"); ... L187: return "fish"; L188: if (targetPath.endsWith(".bashrc") || targetPath.endsWith(".bash_profile")) L189: return "bash";
Medium
Install Persistence

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

dist/lib/cosmetics/inscribe.jsView on unpkg · L61
dist/doctor/checks/runtime.jsView file
1import * as fs from "node:fs"; L2: import * as net from "node:net"; L3: import * as os from "node:os"; L4: import * as path from "node:path"; L5: import { execFile as _execFile } from "node:child_process"; L6: import { promisify } from "node:util"; ... L11: } L12: const runtimeDir = process.env.XDG_RUNTIME_DIR; L13: if (runtimeDir) {
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/doctor/checks/runtime.jsView on unpkg · L1
dist/commands/alignment.jsView file
1import { spawn } from "child_process"; L2: import * as path from "path"; ... L13: function resolveServerCmd() { L14: const envCmd = process.env.ALTER_MCP_CMD; L15: if (envCmd) { ... L24: "(no shell metacharacters)."); L25: process.exitCode = 1; L26: return null; ... L39: "Set ALTER_MCP_CMD=<absolute-path-to-the-server-binary> to enable. " + L40: "See https://truealter.com/docs/cli#alignment"); L41: process.exitCode = 1; ... L49: const wait = await withKeyListenerCancel(async (signal) => {
High
Sandbox Evasion Gated Capability

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

dist/commands/alignment.jsView on unpkg · L1
dist/assets/statusline/statusline.shView file
path = [redacted].sh kind = build_helper sizeBytes = 47798 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

dist/assets/statusline/statusline.shView on unpkg
dist/embedded-plugins/alter-obsidian-plugin/main.jsView file
matchType = previous_version_dangerous_delta matchedPackage = @truealter/cli@0.8.30 matchedIdentity = npm:QHRydWVhbHRlci9jbGk:0.8.30 similarity = 0.833 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/embedded-plugins/alter-obsidian-plugin/main.jsView on unpkg

Findings

1 Critical4 High6 Medium6 Low
CriticalPrevious Version Dangerous Deltadist/embedded-plugins/alter-obsidian-plugin/main.js
HighChild Processdist/cc-wrapper/pty-adapter.js
HighShelldist/commands/hooks.js
HighSame File Env Network Executiondist/doctor/checks/runtime.js
HighSandbox Evasion Gated Capabilitydist/commands/alignment.js
MediumDynamic Requiredist/cc-wrapper/pty-adapter.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/lib/cosmetics/inscribe.js
MediumShips Build Helperdist/assets/statusline/statusline.sh
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowUrl Strings