registry  /  @spinabot/brigade  /  1.24.0

@spinabot/brigade@1.24.0

Brigade — your personal AI crew

AI Security Review

scanned 3h ago · by lpm-firewall-ai

LPM blocks this version under the AI-agent control-surface policy. Install-time script mutates files inside the @convex-dev/auth dependency to brand an OAuth page. This is an unconsented postinstall write to a foreign package control surface, but inspection did not show exfiltration or remote payload loading.

Static reason
High-risk behavior combination matched malicious policy.; previous stored version diff introduced dangerous source
Trigger
npm install of @spinabot/brigade@1.24.0
Impact
Changes behavior/assets of installed @convex-dev/auth OAuth UI without an explicit user action.
Mechanism
postinstall dependency file rewrite
Policy narrative
On installation, npm runs scripts/brand-oauth-page.mjs. The script locates @convex-dev/auth inside node_modules and rewrites callback.js and callback.mjs to replace embedded OAuth page markup/styles/favicon/logo references with Brigade branding. No network or credential theft was observed, but the install-time mutation targets a foreign dependency automatically.
Rationale
The package performs unconsented postinstall mutation of a foreign dependency's OAuth control surface, which matches the blocking policy even though the observed payload is branding rather than exfiltration. User-invoked CLI/network capabilities are package-aligned and are not the basis for the verdict. Product guard normalized a concrete AI-agent control hijack publish_block to the blockable dangerous-capability shape.
Evidence
package.jsonscripts/brand-oauth-page.mjsbrigade.mjsdist/entry.jsnode_modules/@convex-dev/auth/dist/server/oauth/callback.jsnode_modules/@convex-dev/auth/dist/server/oauth/callback.mjs

Decision evidence

public snapshot
AI called this Malicious at 91.0% confidence as Dangerous Capability with low false-positive risk.
Evidence for policy block
  • package.json defines postinstall: node scripts/brand-oauth-page.mjs
  • scripts/brand-oauth-page.mjs reads and writes installed dependency files under node_modules/@convex-dev/auth/dist/server/oauth/
  • postinstall rewrites OAuth HTML/CJS/ESM assets in a foreign dependency rather than package-owned files
  • Mutation is automatic at install time and not gated by an explicit user command
Evidence against
  • No credential harvesting or broad filesystem scanning found in inspected postinstall script
  • No network calls found in scripts/brand-oauth-page.mjs
  • CLI entrypoints are package-aligned user-invoked commands in brigade.mjs and dist/entry.js
  • Large asset and favicon findings appear consistent with shipped UI assets
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 681 file(s), 7.47 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.23.0 matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.23.0 similarity = 0.908 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