registry  /  @spinabot/brigade  /  1.29.1

@spinabot/brigade@1.29.1

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 mutation of a foreign AI SDK OAuth callback page is confirmed. The package rewrites the dependency's local source to alter sign-in callback branding.

Static reason
High-risk behavior combination matched malicious policy.; source matched previously finalized malicious package; routed for review
Trigger
npm postinstall during package installation
Impact
Changes a foreign AI authentication-adjacent control surface without user consent; may misrepresent the OAuth flow.
Mechanism
Silent overwrite of a resolved dependency OAuth page
Policy narrative
On installation, the declared postinstall hook resolves the OAuth export of the separately owned `@earendil-works/pi-ai` dependency, locates its callback-page source, and writes a modified version containing embedded Brigade logo/favicon data and title text. The mutation is automatic, idempotent, and deliberately suppresses errors, so the user receives no meaningful consent gate for a change to an authentication-adjacent dependency surface.
Rationale
Source inspection confirms unconsented postinstall modification of a foreign AI SDK OAuth callback page. Although no credential exfiltration or network activity was found in the hook, this is a concrete install-time foreign control-surface mutation.
Evidence
package.jsonscripts/brand-oauth-page.mjsdist/agents/extensions/install.jsdist/security/injection-patterns.jsnode_modules/@earendil-works/pi-ai/utils/oauth/oauth-page.js

Decision evidence

public snapshot
AI called this Malicious at 95.0% confidence as Malware with low false-positive risk.
Evidence for policy block
  • `package.json` runs `scripts/brand-oauth-page.mjs` as `postinstall`.
  • The hook resolves `@earendil-works/pi-ai/oauth` and overwrites its `utils/oauth/oauth-page.js`.
  • The write silently injects Brigade branding into a foreign OAuth callback page and exits successfully on errors.
Evidence against
  • The hook contains no network request or credential harvesting logic.
  • `dist/agents/extensions/install.js` is only reached by explicit extension-management commands and surfaces scan findings.
  • `dist/security/injection-patterns.js` contains invisible Unicode in its defensive detection regex, not a hidden payload.
Behavioral surface
Source
ChildProcessCryptoDynamicRequireEnvironmentVarsEvalFilesystemNetworkShellWebSocket
Supply chain
HighEntropyStringsMinifiedTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 704 file(s), 7.84 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

26 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
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/ui/clipboard.jsView file
18* Each platform expresses all four differently, so they live behind one L19: * `ClipboardBackend` and the rest of the product never learns that PowerShell, L20: * osascript, or wl-paste exist.
High
Shell

Package source references shell execution.

dist/ui/clipboard.jsView on unpkg · L18
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
dist/core/daemon/systemd.jsView file
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
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/extensions/install-scan.jsView file
matchType = normalized_sha256 matchedPackage = @spinabot/brigade@1.28.0 matchedPath = dist/agents/extensions/install-scan.js matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.28.0 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

dist/agents/extensions/install-scan.jsView on unpkg
dist/agents/extensions/install.jsView file
matchType = normalized_sha256 matchedPackage = @spinabot/brigade@1.28.0 matchedPath = dist/agents/extensions/install.js matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.28.0 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

dist/agents/extensions/install.jsView on unpkg
dist/core/daemon/launchd.jsView file
matchType = normalized_sha256 matchedPackage = @spinabot/brigade@1.28.0 matchedPath = dist/core/daemon/launchd.js matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.28.0 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

dist/core/daemon/launchd.jsView on unpkg
dist/core/daemon/schtasks.jsView file
matchType = normalized_sha256 matchedPackage = @spinabot/brigade@1.28.0 matchedPath = dist/core/daemon/schtasks.js matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.28.0 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

dist/core/daemon/schtasks.jsView on unpkg
dist/core/tunnel/providers/bore.jsView file
matchType = normalized_sha256 matchedPackage = @spinabot/brigade@1.28.0 matchedPath = dist/core/tunnel/providers/bore.js matchedIdentity = npm:QHNwaW5hYm90L2JyaWdhZGU:1.28.0 similarity = 1.000 summary = normalized source hash matched finalized malicious source
High
Known Malware Source Similarity

Source file is highly similar to a previously finalized malicious package; route for source-aware review.

dist/core/tunnel/providers/bore.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

1 Critical13 High13 Medium7 Low
CriticalTrojan Source Unicodedist/security/injection-patterns.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processdist/ui/onboarding.js
HighShelldist/ui/clipboard.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
HighKnown Malware Source Similaritydist/agents/extensions/install-scan.js
HighKnown Malware Source Similaritydist/agents/extensions/install.js
HighKnown Malware Source Similaritydist/core/daemon/launchd.js
HighKnown Malware Source Similaritydist/core/daemon/schtasks.js
HighKnown Malware Source Similaritydist/core/tunnel/providers/bore.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
LowHigh Entropy Strings
LowTelemetry
LowUrl Strings