registry  /  @swirls/cli  /  0.1.104

@swirls/cli@0.1.104

Swirls command line application

AI Security Review

scanned 6h ago · by lpm-firewall-ai

The package executes a remote shell script during npm postinstall for global installs. That remote script controls what binary is installed and copied into the package entrypoint without integrity verification.

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
Global npm/Bun install with lifecycle scripts enabled
Impact
Untrusted remote code can run with installer user privileges and replace the CLI binary at install time.
Mechanism
install-time curl-to-bash remote code execution
Attack narrative
On global installation, npm runs scripts/install.js. The hook skips CI, Windows, and non-global installs, then executes curl -fsSL https://swirls.ai/install | bash using a shell. If that installer creates ~/.local/bin/swirls, the hook copies it over bin/swirls and marks it executable, making remote install-time code determine the published CLI entrypoint.
Rationale
Source inspection confirms lifecycle-triggered remote shell execution and binary replacement without integrity checks. Even though the endpoint is package-aligned, this is a concrete install-time remote code execution attack surface suitable for blocking.
Evidence
package.jsonscripts/install.jsbin/swirlsREADME.md~/.local/bin/swirls
Network endpoints1
swirls.ai/install

Decision evidence

public snapshot
AI called this Malicious at 92.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: curl -fsSL https://swirls.ai/install | bash
  • Remote shell execution is lifecycle-triggered on global npm/Bun installs outside CI and non-Windows
  • scripts/install.js copies ~/.local/bin/swirls into package bin/swirls after remote installer runs
  • No checksum, pinned artifact URL, or local packaged binary is present
Evidence against
  • Hook is gated to global installs and skips CI/Windows
  • Endpoint is package-aligned with author/docs domain swirls.ai
  • No source evidence of credential harvesting, broad file enumeration, AI-agent config writes, or exfiltration in packaged files
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.105 matchedPath = scripts/install.js matchedIdentity = npm:QHN3aXJscy9jbGk:0.1.105 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.105 matchedPath = scripts/install.js matchedIdentity = npm:QHN3aXJscy9jbGk:0.1.105 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