registry  /  @swirls/cli  /  0.1.103

@swirls/cli@0.1.103

Swirls command line application

AI Security Review

scanned 5h ago · by lpm-firewall-ai

Global installation triggers a postinstall script that downloads and pipes a remote installer from swirls.ai directly into bash. The package source does not pin, verify, or include the executed installer content.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
npm/bun global install of @swirls/cli on non-Windows outside CI
Impact
Unreviewed remote code can run with the installing user's privileges during package installation.
Mechanism
install-time remote shell execution via curl|bash
Attack narrative
When installed globally, package.json invokes scripts/install.js as postinstall. That script exits in CI, Windows, or non-global installs, but otherwise runs curl against https://swirls.ai/install and pipes the response to bash with shell execution. It then copies $HOME/.local/bin/swirls into the package bin path if present, so the executable users run may be supplied by the remote installer rather than the npm tarball.
Rationale
Static inspection confirms install-time download-and-execute behavior from a remote shell script, which is a concrete unconsented lifecycle execution surface even though the endpoint is package-aligned. No credential theft or AI-agent hijack was found, but remote code execution during install is sufficient to block.
Evidence
package.jsonscripts/install.jsbin/swirls$HOME/.local/bin/swirls
Network endpoints1
swirls.ai/install

Decision evidence

public snapshot
AI called this Malicious at 94.0% confidence as Malware with low false-positive risk.
Evidence for block
  • package.json defines postinstall: node scripts/install.js
  • scripts/install.js runs execSync with shell:true during lifecycle
  • scripts/install.js executes curl -fsSL https://swirls.ai/install | bash on global install
  • Lifecycle script is gated only by CI, Windows, and non-global install checks
  • Remote installer executes unaudited network content at install time
Evidence against
  • No credential harvesting found in inspected files
  • No AI-agent control-surface writes found in package source
  • bin/swirls is a package CLI placeholder, not hidden persistence
  • Lifecycle skips local/non-global installs and CI
  • Network endpoint is package-aligned to swirls.ai
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemShell
Supply chain
UrlStrings
Manifest
NoLicense
scanned 1 file(s), 1.35 KB of source, external domains: swirls.ai

Source & flagged code

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

Package defines install-time lifecycle scripts.

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

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

package.jsonView on unpkg
scripts/install.jsView file
13L14: import { execSync } from 'node:child_process' L15: import { chmodSync, copyFileSync, existsSync } from 'node:fs' ... L18: L19: const INSTALL_URL = 'https://swirls.ai/install' L20: ... L28: const INSTALLED_BINARY = join( L29: process.env.HOME || process.env.USERPROFILE || '', L30: '.local', ... L36: L37: if (process.env.CI === 'true' || process.env.CI === '1') { L38: process.exit(0)
Critical
Download Execute

Source downloads or fetches remote code and executes it.

scripts/install.jsView on unpkg · L13
13Trigger-reachable chain: scripts.postinstall -> scripts/install.js L13: L14: import { execSync } from 'node:child_process' L15: import { chmodSync, copyFileSync, existsSync } from 'node:fs' ... L18: L19: const INSTALL_URL = 'https://swirls.ai/install' L20: ... L28: const INSTALLED_BINARY = join( L29: process.env.HOME || process.env.USERPROFILE || '', L30: '.local', ... L36: L37: if (process.env.CI === 'true' || process.env.CI === '1') { L38: process.exit(0)
Critical
Trigger Reachable Dangerous Capability

A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.

scripts/install.jsView on unpkg · L13
13L14: import { execSync } from 'node:child_process' L15: import { chmodSync, copyFileSync, existsSync } from 'node:fs'
High
Child Process

Package source references child process execution.

scripts/install.jsView on unpkg · L13
49stdio: 'inherit', L50: shell: true, L51: })
High
Shell

Package source references shell execution.

scripts/install.jsView on unpkg · L49
13L14: import { execSync } from 'node:child_process' L15: import { chmodSync, copyFileSync, existsSync } from 'node:fs' ... L18: L19: const INSTALL_URL = 'https://swirls.ai/install' L20: ... L28: const INSTALLED_BINARY = join( L29: process.env.HOME || process.env.USERPROFILE || '', L30: '.local', ... L36: L37: if (process.env.CI === 'true' || process.env.CI === '1') { L38: process.exit(0)
High
Sandbox Evasion Gated Capability

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

scripts/install.jsView on unpkg · L13

Findings

2 Critical4 High3 Medium4 Low
CriticalDownload Executescripts/install.js
CriticalTrigger Reachable Dangerous Capabilityscripts/install.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processscripts/install.js
HighShellscripts/install.js
HighSandbox Evasion Gated Capabilityscripts/install.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowUrl Strings
LowNo License