registry  /  @spinabot/brigade  /  1.23.0

@spinabot/brigade@1.23.0

Brigade — your personal AI crew

AI Security Review

scanned 2h ago · by lpm-firewall-ai

No confirmed malware or exfiltration was found. Residual risk is an unconsented postinstall mutation of a dependency file plus a broad AI-agent platform surface that is mostly user-invoked.

Static reason
High-risk behavior combination matched malicious policy.; previous stored version diff introduced dangerous source
Trigger
npm install postinstall; later user-invoked brigade CLI commands
Impact
Cosmetic dependency patch at install; user-invoked AI agent capabilities can write Brigade-owned workspace files and load acknowledged extensions.
Mechanism
install-time dependency file rewrite and user-invoked agent workspace/extension setup
Attack narrative
On installation, the package runs a postinstall script that locates a bundled dependency OAuth callback page and rewrites branding assets/title in that file. The package also ships a full AI-agent runtime that can seed Brigade-owned workspace persona files, expose MCP memory, run a gateway, and install extensions, but those behaviors are reached through explicit Brigade CLI/runtime actions rather than npm install and are scoped to Brigade paths.
Rationale
Source inspection shows no credential harvesting, exfiltration, remote payload execution, persistence, or unconsented writes to foreign AI-agent control surfaces. The unguarded postinstall dependency rewrite is not clean packaging behavior, so warn rather than block.
Evidence
package.jsonscripts/brand-oauth-page.mjsbrigade.mjsdist/entry.jsdist/workspace/bootstrap.jsdist/config/paths.jsdist/cli/commands/extensions.jsdist/security/injection-patterns.jsnode_modules/@earendil-works/pi-ai/**/utils/oauth/oauth-page.js~/.brigade/workspace/AGENTS.md~/.brigade/workspace/BOOTSTRAP.md~/.brigade/workspace/IDENTITY.md~/.brigade/workspace/SOUL.md~/.brigade/workspace/TOOLS.md~/.brigade/workspace/HEARTBEAT.md~/.brigade/workspace/USER.md

Decision evidence

public snapshot
AI called this Suspicious at 78.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • package.json defines postinstall: node scripts/brand-oauth-page.mjs
  • scripts/brand-oauth-page.mjs resolves @earendil-works/pi-ai/oauth and rewrites its oauth-page.js during install
  • dist/workspace/bootstrap.js can seed AGENTS.md and other persona files under Brigade workspace
  • Package exposes an AI agent platform with skills, extensions, MCP, gateway, and channel integrations
Evidence against
  • postinstall does not fetch network data, execute remote code, collect credentials, or write shell/VCS/agent configs
  • postinstall target is a dependency OAuth callback page, not Claude/Codex/Cursor/MCP user control config
  • workspace/persona files are created by runtime onboarding/bootstrap under ~/.brigade workspace, not npm install
  • extension installs are explicit CLI actions with compatibility and static scan acknowledgement
  • dist/security/injection-patterns.js Trojan-source hint is a regex scanner for invisible Unicode, not hidden control flow
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 674 file(s), 7.38 MB of source, external domains: 127.0.0.1, 192.168.1.5, accounts.google.com, aistudio.google.com, api-dashboard.search.brave.com, api.anthropic.com, api.cerebras.ai, api.deepgram.com, api.deepseek.com, api.dev.runwayml.com, api.duckduckgo.com, api.elevenlabs.io, api.exa.ai, api.example.com, api.firecrawl.dev, api.github.com, api.groq.com, api.minimax.io, api.mistral.ai, api.moonshot.ai, api.openai.com, api.perplexity.ai, api.sarvam.ai, api.search.brave.com, api.slack.com, api.tavily.com, api.telegram.org, api.together.xyz, api.x.ai, api.z.ai, app.tavily.com, ark.ap-southeast.bytepluses.com, bailian.console.alibabacloud.com, brave.com, brigade.spinabot.com, build.nvidia.com, chatgpt.com, claude.ai, cloud.cerebras.ai, console.anthropic.com, console.groq.com, console.mistral.ai, console.x.ai, core.telegram.org, dashscope-intl.aliyuncs.com, discord.com, docs.exa.ai, docs.firecrawl.dev, docs.github.com, docs.ollama.com
Oversized source lightweight scan
dist/ui/brand-frames-cli.js2.36 MB file, sampled 256 KB
Minified

Source & flagged code

22 flagged · loading source
package.jsonView file
scripts.postinstall = node scripts/brand-oauth-page.mjs
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
dist/ui/onboarding.jsView file
matchType = previous_version_dangerous_delta matchedPackage = @spinabot/brigade@1.22.1 matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.22.1 similarity = 0.975 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; route for source-aware review.

dist/ui/onboarding.jsView on unpkg
14*/ L15: import { spawn } from "node:child_process"; L16: import { getModels } from "@earendil-works/pi-ai";
High
Child Process

Package source references child process execution.

dist/ui/onboarding.jsView on unpkg · L14
dist/core/daemon/systemd.jsView file
21.join("\n"); L22: const execArgs = [ctx.nodePath, ctx.brigadeBin, "gateway", "run"] L23: .map((s) => (s.includes(" ") ? `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : s))
High
Shell

Package source references shell execution.

dist/core/daemon/systemd.jsView on unpkg · L21
8*/ L9: import { spawn } from "node:child_process"; L10: import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; ... L14: function unitPath() { L15: return path.join(os.homedir(), ".config", "systemd", "user", SERVICE_UNIT_NAME); L16: } ... L36: "RestartSec=2", L37: `StandardOutput=append:${ctx.stdoutPath}`, L38: `StandardError=append:${ctx.stderrPath}`, ... L74: if (r.code !== 0) { L75: return { ok: false, message: `systemctl enable failed: ${r.stderr.trim()}`, unitPath: file }; L76: }
Medium
Install Persistence

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

dist/core/daemon/systemd.jsView on unpkg · L8
dist/agents/org/pride-image.jsView file
90// consistent with how Brigade lazy-loads other heavy modules.) L91: const importer = new Function("s", "return import(s)"); L92: const mod = (await importer("playwright-core"));
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/agents/org/pride-image.jsView on unpkg · L90
brigade.mjsView file
54try { L55: const mod = await import("node:module"); L56: if (typeof mod.enableCompileCache === "function" && !process.env.NODE_DISABLE_COMPILE_CACHE) {
Medium
Dynamic Require

Package source references dynamic require/import behavior.

brigade.mjsView on unpkg · L54
dist/agents/tool-loop-detector.jsView file
1/** L2: * Tool-loop detector — catches the model when it's stuck calling the same
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/agents/tool-loop-detector.jsView on unpkg · L1
scripts/convex-dev.mjsView file
16L17: import { spawn } from "node:child_process"; L18: import { mkdirSync, existsSync, writeFileSync, readFileSync, unlinkSync } from "node:fs"; L19: import { randomBytes } from "node:crypto"; L20: import { createServer } from "node:http"; L21: import { readFile, stat } from "node:fs/promises"; ... L30: // or `npm run convex:dev` from a checkout (→ <root>/.convex-data, the default). L31: const DATA_DIR = process.env.BRIGADE_CONVEX_DATA_DIR?.trim() || join(ROOT, ".convex-data"); L32: const DASHBOARD_DIR = join(BIN_DIR, "dashboard");
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

scripts/convex-dev.mjsView on unpkg · L16
dist/infra/net/fetch-guard.jsView file
4* Why this exists: Brigade runs LLM-controllable URLs through `fetch`. L5: * Without a guard, a model can be tricked into hitting `http://169.254.169.254/` L6: * (cloud metadata) or `http://localhost:1234/` (developer service) and ... L20: import { isIP, isIPv4, isIPv6 } from "node:net"; L21: import { promises as dnsPromises } from "node:dns"; L22: import { DEFAULT_TIMEOUT_SECONDS } from "../../agents/tools/web-shared.js"; ... L28: * Cloud-metadata + forbidden-literal hosts that stay blocked EVEN WHEN L29: * `allowPrivateNetwork` is set — these are never a legitimate LAN target and are L30: * the highest-value SSRF destinations. ... L364: headers: currentHeaders, L365: body: currentBody ?? undefined, L366: redirect: "manual",
High
Cloud Metadata Access

Source reaches cloud instance metadata or link-local credential endpoints.

dist/infra/net/fetch-guard.jsView on unpkg · L4
dist/security/injection-patterns.jsView file
58contains invisible/control Unicode U+200B (zero width space) const INVISIBLE_CODEPOINTS = /[<U+200B>-<U+200D><U+2060>⁢-⁤<U+FEFF><U+202A>-<U+202E><U+2066>-<U+2069>]/;
Critical
Trojan Source Unicode

Source contains bidi control or invisible Unicode characters associated with Trojan Source attacks.

dist/security/injection-patterns.jsView on unpkg · L58
scripts/convex-push.mjsView file
75console.log(`▌ Pushing convex/ functions → ${target}`); L76: const res = spawnSync("npx", ["convex", "deploy", "--yes"], { L77: cwd: ROOT,
High
Runtime Package Install

Package source invokes a package manager install command at runtime.

scripts/convex-push.mjsView on unpkg · L75
skills/video-frames/scripts/frame.shView file
path = skills/video-frames/scripts/frame.sh kind = build_helper sizeBytes = 1347 magicHex = [redacted]
Medium
Ships Build Helper

Package ships non-JavaScript build or shell helper files.

skills/video-frames/scripts/frame.shView on unpkg
scripts/assets/brigade-favicon.icoView file
path = scripts/assets/brigade-favicon.ico kind = high_entropy_blob sizeBytes = 19371 magicHex = [redacted]
High
Ships High Entropy Blob

Package ships high-entropy non-source blobs.

scripts/assets/brigade-favicon.icoView on unpkg
dist/ui/brand-frames-cli.jsView file
path = dist/ui/brand-frames-cli.js kind = oversized_source_file sizeBytes = 2475115 magicHex = [redacted]
High
Oversized Source File

Package contains source files above the static scanner size ceiling.

dist/ui/brand-frames-cli.jsView on unpkg
path = dist/ui/brand-frames-cli.js kind = oversized_cli_entrypoint sizeBytes = 2475115 magicHex = [redacted]
Medium
Oversized Cli Entrypoint

Package contains an oversized executable-looking CLI entrypoint.

dist/ui/brand-frames-cli.jsView on unpkg
dist/agents/channels/bluebubbles/account-config.d.tsView file
28patternName = generic_password severity = medium line = 28 matchedText = * ch...}" }
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.d.ts

dist/agents/channels/bluebubbles/account-config.d.tsView on unpkg · L28
34patternName = generic_password severity = medium line = 34 matchedText = * ..." },
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.d.ts

dist/agents/channels/bluebubbles/account-config.d.tsView on unpkg · L34
35patternName = generic_password severity = medium line = 35 matchedText = * ..." },
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.d.ts

dist/agents/channels/bluebubbles/account-config.d.tsView on unpkg · L35
dist/agents/channels/bluebubbles/account-config.jsView file
28patternName = generic_password severity = medium line = 28 matchedText = * ch...}" }
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.js

dist/agents/channels/bluebubbles/account-config.jsView on unpkg · L28
34patternName = generic_password severity = medium line = 34 matchedText = * ..." },
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.js

dist/agents/channels/bluebubbles/account-config.jsView on unpkg · L34
35patternName = generic_password severity = medium line = 35 matchedText = * ..." },
Medium
Secret Pattern

Hardcoded password in dist/agents/channels/bluebubbles/account-config.js

dist/agents/channels/bluebubbles/account-config.jsView on unpkg · L35

Findings

2 Critical8 High13 Medium8 Low
CriticalTrojan Source Unicodedist/security/injection-patterns.js
CriticalPrevious Version Dangerous Deltadist/ui/onboarding.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/ui/onboarding.js
HighShelldist/core/daemon/systemd.js
HighSame File Env Network Executionscripts/convex-dev.mjs
HighCloud Metadata Accessdist/infra/net/fetch-guard.js
HighRuntime Package Installscripts/convex-push.mjs
HighShips High Entropy Blobscripts/assets/brigade-favicon.ico
HighOversized Source Filedist/ui/brand-frames-cli.js
MediumDynamic Requirebrigade.mjs
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistencedist/core/daemon/systemd.js
MediumShips Build Helperskills/video-frames/scripts/frame.sh
MediumOversized Cli Entrypointdist/ui/brand-frames-cli.js
MediumStructural Risk Force Deep Review
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.d.ts
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.d.ts
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.d.ts
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.js
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.js
MediumSecret Patterndist/agents/channels/bluebubbles/account-config.js
LowScripts Present
LowEvaldist/agents/org/pride-image.js
LowWeak Cryptodist/agents/tool-loop-detector.js
LowFilesystem
LowObfuscated
LowHigh Entropy Strings
LowTelemetry
LowUrl Strings