registry  /  karajan-code  /  3.8.0

karajan-code@3.8.0

Local multi-agent coding orchestrator with TDD, SonarQube, and code review pipeline

AI Security Review

scanned 2h ago · by lpm-firewall-ai

LPM blocks this version under the AI-agent control-surface policy. Installing the package silently alters Claude Code and Codex global MCP configuration. Those clients will subsequently launch package-controlled Node code as an MCP server.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm postinstall during package installation
Impact
Persistent execution path through foreign AI-agent control surfaces.
Mechanism
unconsented global AI-agent MCP configuration injection
Policy narrative
The install hook executes without user interaction, creates or rewrites the user's global Claude Code and Codex configuration, and inserts a `karajan-mcp` server entry pointing to this installed package's MCP server. This persists beyond the install and causes foreign AI-agent clients to launch package-controlled code later. The lifecycle hook catches all errors so installation is not blocked.
Rationale
This is a concrete, unconsented postinstall mutation of broad foreign AI-agent control surfaces, meeting the firewall block boundary despite otherwise recognizable MCP functionality.
Evidence
package.jsonscripts/postinstall.jssrc/mcp/server.jssrc/mcp/server-handlers.jssrc/mcp/tools.js~/.claude.json~/.codex/config.toml

Decision evidence

public snapshot
AI called this Malicious at 99.0% confidence as Malware with low false-positive risk.
Evidence for policy block
  • `package.json` runs `scripts/postinstall.js` on install.
  • `scripts/postinstall.js` unconditionally writes `~/.claude.json`.
  • It registers `karajan-mcp` to execute package `src/mcp/server.js`.
  • It creates and modifies `~/.codex/config.toml` during install.
  • The hook is non-interactive and suppresses failures.
Evidence against
  • The registered MCP uses stdio; no postinstall network call is present.
  • `src/mcp/server.js` is a normal MCP dispatcher rather than an encoded payload.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsFilesystemNativeBindingsNetworkShell
Supply chain
HighEntropyStringsUrlStrings
Manifest
CopyleftLicenseWildcardDependency
scanned 565 file(s), 2.87 MB of source, external domains: aider.chat, aistudio.google.com, api.cohere.com, api.mistral.ai, api.openai.com, api.voyageai.com, cli.github.com, console.anthropic.com, developers.openai.com, docs.anthropic.com, docs.docker.com, docs.sonarsource.com, fonts.googleapis.com, fonts.gstatic.com, github.com, google.github.io, karajan-code.web.app, karajancode.com, nodejs.org, opencode.ai, platform.openai.com, raw.githubusercontent.com, registry.npmjs.org, semgrep.dev, sonarcloud.io, www.docker.com, www.w3.org

Source & flagged code

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

Package defines install-time lifecycle scripts.

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

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

package.jsonView on unpkg
scripts/diet-baseline.mjsView file
25L26: import { execFileSync, spawnSync } from "node:child_process"; L27: import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
High
Child Process

Package source references child process execution.

scripts/diet-baseline.mjsView on unpkg · L25
src/agents/resolve-bin.jsView file
65L66: // 3. Fallback: return name as-is (let execa try PATH) L67: cache.set(name, name);
High
Shell

Package source references shell execution.

src/agents/resolve-bin.jsView on unpkg · L65
packages/hu-board/src/boot-info.jsView file
12L13: const require = createRequire(import.meta.url); L14: export const PKG_VERSION = (() => {
Medium
Dynamic Require

Package source references dynamic require/import behavior.

packages/hu-board/src/boot-info.jsView on unpkg · L12
src/sonar/project-key.jsView file
59const explicit = String( L60: options.projectKey || process.env.KJ_SONAR_PROJECT_KEY || config?.sonarqube?.project_key || "" L61: ).trim(); ... L66: const remote = await runCommand("git", ["config", "--get", "remote.origin.url"]); L67: const remoteUrl = String(remote.stdout || "").trim(); L68: if (remote.exitCode !== 0 || !remoteUrl) {
Low
Weak Crypto

Package source references weak cryptographic algorithms.

src/sonar/project-key.jsView on unpkg · L59
scripts/install.jsView file
4import path from "node:path"; L5: import { spawn } from "node:child_process"; L6: import readline from "node:readline/promises"; L7: import { stdin as input, stdout as output } from "node:process"; L8: L9: const rl = readline.createInterface({ input, output }); L10: const REGISTRY_PATH = path.join(os.homedir(), ".karajan", "instances.json"); L11: const INSTALL_STATE_PATH = path.join(os.homedir(), ".karajan", "install-state.json"); L12: const AGENT_META = { L13: codex: { bin: "codex", installUrl: "https://developers.openai.com/codex/cli" }, L14: claude: { bin: "claude", installUrl: "https://docs.anthropic.com/en/docs/claude-code" }, ... L119: if (cliValue !== undefined) return cliValue;
Medium
Install Persistence

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

scripts/install.jsView on unpkg · L4
scripts/postinstall.jsView file
3Install-time AI-agent control hijack evidence: L25: await fs.mkdir(path.dirname(file), { recursive: true }); L26: await fs.writeFile(file, `${JSON.stringify(obj, null, 2)}\n`, "utf8"); L27: } ... L48: async function setupClaudeMcp(kjHome) { L49: const claudeJsonPath = path.join(os.homedir(), ".claude.json"); L50: let config = {}; ... L56: L57: config.mcpServers = config.mcpServers || {}; L58: config.mcpServers["karajan-mcp"] = { L59: type: "stdio", ... L83: async function setupCodexMcp(kjHome) { L84: const configPath = path.join(os.homedir(), ".codex", "config.toml"); Payload evidence from src/agents/resolve-bin.js: L3: import os from "node:os"; L4: import { execFileSync } from "node:child_process"; L5: ... L7: L8: const isWin = process.platform === "win32"; L9: ... L11: ? [ L12: path.join(os.homedir(), "AppData", "Roaming", "npm"), L13: path.join(os.homedir(), "AppData", "Local", "npm"), ... L24: function getNvmDirs() { L25: const nvmDir = process.env.NVM_DIR || path.join(os.homedir(), ".nvm"); L26: const versionsDir = path.join(nvmDir, "versions", "node");
Critical
Ai Agent Control Hijack

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

scripts/postinstall.jsView on unpkg · L3
src/audit/basal-cost.jsView file
76return new Promise((resolve) => { L77: execFile("npx", ["depcheck", "--json"], { cwd: projectDir, timeout: 30000 }, (err, stdout) => { L78: if (err && !stdout) {
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

src/audit/basal-cost.jsView on unpkg · L76
vendor/tree-sitter-grammars/python.wasmView file
path = vendor/tree-sitter-grammars/python.wasm kind = wasm_module sizeBytes = 457883 magicHex = [redacted]
Medium
Ships Wasm Module

Package ships WebAssembly modules.

vendor/tree-sitter-grammars/python.wasmView on unpkg
scripts/setup-multi-instance.shView file
path = scripts/setup-multi-instance.sh kind = build_helper sizeBytes = 3848 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

scripts/setup-multi-instance.shView on unpkg

Findings

1 Critical4 High9 Medium7 Low
CriticalAi Agent Control Hijackscripts/postinstall.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processscripts/diet-baseline.mjs
HighShellsrc/agents/resolve-bin.js
HighRuntime Package Installsrc/audit/basal-cost.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumDynamic Requirepackages/hu-board/src/boot-info.js
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencescripts/install.js
MediumShips Wasm Modulevendor/tree-sitter-grammars/python.wasm
MediumShips Build Helperscripts/setup-multi-instance.sh
MediumStructural Risk Force Deep Review
MediumWildcard Dependency
LowNon Install Lifecycle Scripts
LowScripts Present
LowWeak Cryptosrc/sonar/project-key.js
LowFilesystem
LowHigh Entropy Strings
LowUrl Strings
LowCopyleft License