Spice is a local Shai-Hulud exposure checker for developers. It scans your workstation and projects for known package versions, files, hashes, and incident-specific indicators from public detection packs.
Install the signed macOS desktop app and the CLI:
brew tap turenlabs/tap
brew install --cask turenlabs/tap/spice
spice versionInstall only the CLI:
brew tap turenlabs/tap
brew install turenlabs/tap/spice
spice versionYou can also download the signed macOS app from the latest GitHub release.
Spice is focused on known Shai-Hulud and Mini Shai-Hulud supply-chain attacks. It does not try to be a general antivirus or generic malware scanner.
It checks local files for:
- Affected package names and versions in manifests, lockfiles, Python metadata, Composer metadata, package archives, and package cache folders.
- Known campaign artifacts such as incident-specific payload filenames, runtime files, persistence files, and repository marker strings.
- Known SHA-256 and SHA-1 hashes for published malicious files and tarballs.
- Network and payload indicators from loaded packs, including campaign domains, payload URLs, exfil endpoints, and composite IOC patterns.
- Startup and persistence locations such as macOS LaunchAgents, Linux systemd units, shell startup files, and known token-monitor service paths.
- Package install or prepare hook context when it matches high-signal incident evidence, not just because a package has a normal lifecycle script.
- A local package inventory so you can search what Spice saw by package name, version, ecosystem, path, source file, and digest.
Detection data lives in the public turenlabs/spice-detections repository. The Spice app is the scanning engine; the detection repo is where package rows, IOCs, hashes, filenames, and remediation text are updated.
Open Spice from /Applications/Spice.app.
Use the desktop app when you want to:
- Run a guided scan.
- See findings as they are discovered.
- Review findings with file previews.
- Ignore or restore findings during triage.
- Browse the local package inventory.
- Apply npm install guardrails from the Harden page.
- Exclude noisy directories from future scans.
- Clear local scan data from settings.
Recommended first scan:
- Choose Incident sweep.
- Keep the default paths.
- Run the scan.
- Review anything in Findings.
- Open Inventory if you want to inspect packages Spice discovered.
Use Deep disk scan only when you want a broader pass over selected paths. It reads more files and takes longer.
The Harden page helps developers apply reversible npm guardrails from the desktop app. It reads your current user-level npm config, shows the exact commands it will run, and lets you choose between a daily-use preset, a stricter preset, or npm defaults.
min-release-age: avoid npm versions published too recently.save-exact: save exact versions for new installs.allow-git: block Git dependency specs during npm install.ignore-scripts: optionally disable lifecycle scripts in strict mode.
The recommended preset runs:
npm config set min-release-age 7 --location=user
npm config set save-exact true --location=user
npm config set allow-git none --location=user
npm config set ignore-scripts false --location=userUse Strict if you want lifecycle scripts disabled globally. Use npm defaults to back out the settings Spice changes.
Scan the current project:
spice scan .Run the targeted Shai-Hulud incident sweep:
spice scan --profile shai-huludScan startup and persistence locations:
spice scan --profile startupRun a broader deep scan over selected paths:
spice scan --profile deep ~/code ~/DownloadsWrite JSON for automation:
spice scan --json --profile shai-hulud > spice-findings.jsonRefresh remote detection packs:
spice updateCLI reference:
spice scan [--json] [--no-remote] [--profile project|shai-hulud|startup|deep] [path ...]
spice update
spice versionExit codes:
0: scan completed and found no issues.1: scan or update failed.2: invalid CLI usage.3: scan completed and found one or more findings.
--no-remote disables fetching remote packs for that run. Normal scans load spice-detections from GitHub and fall back to cached packs when offline.
project is the default. It is meant for a repository or working directory. It prioritizes package manifests, lockfiles, package metadata, Dockerfiles, package archives, known suspicious names, and likely loader files.
shai-hulud is the incident sweep. It checks default host paths and package caches that matter for Shai-Hulud style attacks, including IDE residue, package caches, token config paths, known payload names, and persistence paths.
startup focuses on persistence. It checks startup items, LaunchAgents, LaunchDaemons, systemd units, Linux autostart entries, shell startup files, and known token-monitor locations.
deep scans more content under the paths you choose. Use it when you are willing to trade speed for broader coverage.
A Spice finding means "this matched loaded detection evidence." It is triage evidence, not proof by itself that your machine or project is compromised.
When Spice finds something:
- Read what matched and where.
- Check whether the file is an installed dependency, a lockfile, a package cache entry, or documentation containing copied IOCs.
- Follow the finding's what now guidance from the detection pack.
- If a malicious package version is present, remove or upgrade it and regenerate the lockfile.
- If persistence or credential theft evidence is present, treat the host as potentially exposed and rotate relevant credentials after removing any persistence.
False positives are possible, especially when security notes or threat-intel files contain real IOC text. Report detection issues with the finding ID, package/version, redacted path, and matched evidence.
Spice scans local files on your workstation. It stores scan state locally in SQLite:
- macOS:
~/Library/Application Support/Spice/scan-index.sqlite - Linux:
~/.config/Spice/scan-index.sqlite
Remote detection packs are cached separately:
- macOS:
~/Library/Application Support/Spice/detections/ - Linux:
~/.config/Spice/detections/
Spice makes outbound HTTPS GET requests to GitHub to load turenlabs/spice-detections. It does not upload scanned files, package inventory, findings, previews, or local paths as part of detection updates.
Treat findings and previews as sensitive anyway. They can contain local paths, package names, matched strings, and occasionally snippets that look like credentials.
Detection packs are remote data, not executable code. Spice pins detection loading to HTTPS GitHub content from turenlabs/spice-detections on main, validates pack URLs, and uses cached packs when remote loading fails.
Add or review detections here:
Engine changes belong in this repo only when the scanner needs a new parser, archive handler, inventory source, or composite rule capability.
Run the desktop app from source:
go install github.com/wailsapp/wails/v2/cmd/wails@latest
cd frontend && npm install && npm run build
cd ..
wails devBuild the CLI:
make build-cli
build/bin/spice scan --profile project .Run checks:
make release-check
make testSpice is a best-effort local detection tool for known Shai-Hulud indicators covered by loaded detection packs. It does not guarantee that every compromise, variant, or future supply-chain attack will be found. A clean scan is a useful signal, not proof that a system or project is safe.
Spice is licensed under the Apache License 2.0. See LICENSE and NOTICE.
Release metadata lives in VERSION and must match wails.json info.productVersion.
make release builds CLI archives in dist/, builds and packages the macOS app bundle on macOS, and writes dist/SHA256SUMS. See docs/RELEASE.md for the full checklist.