registry  /  @swirls/cli  /  0.1.105

@swirls/cli@0.1.105

Swirls command line application

AI Security Review

scanned 3h ago · by lpm-firewall-ai

Global installation triggers a lifecycle script that downloads and pipes a remote shell installer from swirls.ai into bash, then replaces the package bin with the installed binary. The reviewed package does not contain the remote script or binary, so install-time behavior depends on mutable remote code.

Static reason
High-risk behavior combination matched malicious policy.; source matched previously finalized malicious package; routed for review; source fingerprint signature matched known malicious package; routed for review
Trigger
npm/Bun global install with postinstall enabled
Impact
Remote installer can execute arbitrary shell code on the installer host and determine the final swirls executable shipped in the package install tree.
Mechanism
install-time remote shell execution
Attack narrative
On global install, npm runs package.json postinstall. scripts/install.js skips CI, Windows, and non-global installs, then executes `curl -fsSL https://swirls.ai/install | bash` through a shell. If that remote installer creates ~/.local/bin/swirls, the lifecycle script copies it into bin/swirls and marks it executable, making mutable remote code determine the installed CLI binary.
Rationale
Source inspection confirms lifecycle-triggered remote shell execution and binary replacement; this is a concrete install-time dangerous capability even though the endpoint is package-aligned and no credential theft or agent hijack is visible in the package files. Because the payload is fetched and executed during install, package consumers cannot audit the executed code from the tarball.
Evidence
package.jsonscripts/install.jsbin/swirls~/.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 on global npm/Bun installs outside CI/Windows
  • scripts/install.js executes `curl -fsSL https://swirls.ai/install | bash` with shell:true during lifecycle
  • scripts/install.js copies ~/.local/bin/swirls into package bin/swirls after remote installer completes
Evidence against
  • Lifecycle script is gated to global installs and skips CI/Windows
  • Network endpoint is package-aligned with declared author URL/domain
  • No source evidence of credential harvesting, AI-agent control-surface writes, persistence files, or destructive actions in the package itself
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

9 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
matchType = normalized_sha256 matchedPackage = @swirls/cli@0.1.103 matchedPath = scripts/install.js matchedIdentity = npm:QHN3aXJscy9jbGk:0.1.103 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.

scripts/install.jsView on unpkg
matchType = malicious_source_fingerprint_signature signature = 87fc30553c66ec35 signatureType = suspicious_hashes sourceLabel = final_verdict:malicious matchedPackage = @swirls/cli@0.1.103 matchedPath = scripts/install.js matchedIdentity = npm:QHN3aXJscy9jbGk:0.1.103 similarity = 1.000 shingleOverlap = 1 summary = package final verdict is malicious
High
Known Malware Source Fingerprint Signature

Source fingerprint signature matches a known malicious package signature; route for source-aware review.

scripts/install.jsView on unpkg

Findings

2 Critical6 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
HighKnown Malware Source Similarityscripts/install.js
HighKnown Malware Source Fingerprint Signaturescripts/install.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumEnvironment Vars
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowUrl Strings
LowNo License