Supply-Chain Scan Alerts
Schedule the Cline CLI to scan your machine for compromised packages with Bumblebee and text you on Telegram when it finds one.
npm worms like Shai-Hulud spread through install scripts: the moment you run npm install, a preinstall hook executes and steals your npm, GitHub, AWS, and SSH credentials. New campaigns are reported almost every week.
This guide wires three pieces together so your machine checks itself automatically and pings your phone only when it matters:
- Bumblebee, Perplexity's open-source, read-only supply-chain scanner. It maintains catalogs of recent campaigns and checks whether any compromised package or version is present on disk.
- The Cline CLI scheduler, which runs an agent on a cron schedule.
- The Cline CLI Telegram connector, which delivers the result to a chat.
The end result: every morning, a Cline agent pulls the latest threat intelligence, runs a read-only scan, and texts you a green check if you are clean or a red alert with details if you are exposed.
flowchart TD
cron["cline schedule (daily)"] --> agent["Cline agent"]
agent --> pull["git pull (latest catalogs)"]
agent --> scan["bumblebee scan (read-only)"]
scan --> q{"any findings?"}
q -- "no" --> clean["✅ Clean"]
q -- "yes" --> alert["🚨 Compromise detected"]
clean --> tg["Telegram on your phone"]
alert --> tgHow Bumblebee works
Bumblebee answers one narrow question fast: when an advisory names a package and version, is it present on this machine right now?
The important design choice is that it is read-only. A scanner that runs npm, pnpm, or pip to enumerate your dependencies would trigger the very install-script payload it is looking for. Bumblebee never does that. It only reads metadata files directly:
| Surface | What it reads |
|---|---|
| npm / pnpm / yarn / bun | lockfiles and installed package.json metadata |
| PyPI | *.dist-info/METADATA, *.egg-info/PKG-INFO |
| Go modules | go.sum, go.mod |
| RubyGems | Gemfile.lock, installed gemspecs |
| Composer | composer.lock, vendor/composer/installed.json |
| MCP servers | mcp.json, claude_desktop_config.json, and similar configs |
| Editor extensions | VS Code-family extension manifests |
| Browser extensions | Chromium-family and Firefox extension manifests |
It never runs package managers, never executes install scripts or lifecycle hooks, and never reads your application source. It ships no bundled threat intelligence either: you point it at an exposure catalog, and it reports exact (ecosystem, name, version) matches.
The catalogs live in the repo under threat_intel/, maintained by Perplexity and updated via pull requests as new campaigns are reported. That is why this automation simply pulls the latest before each scan: a git pull is all it takes to stay current.
Read the announcement: Perplexity is open-sourcing Bumblebee.
Prerequisites
- Node.js 22 or newer (for the Cline CLI).
- Go 1.22 or newer (to build Bumblebee).
- A Telegram account.
- An AI provider key, or a Cline account.
1. Install the Cline CLI
npm install -g cline
cline # run once to configure inference provider and model2. Clone and build Bumblebee
Clone the repository somewhere stable. The clone is both the scanner and the catalog source, so the scheduled job will run from inside it.
mkdir -p ~/tools
git clone https://github.com/perplexityai/bumblebee.git ~/tools/bumblebee
cd ~/tools/bumblebee
go build -o bumblebee ./cmd/bumblebeeConfirm it works with the built-in self test, which runs embedded fixtures and makes no network calls:
./bumblebee selftest
# selftest OK (2 findings in 1ms)3. Run a scan manually
Point --exposure-catalog at the whole threat_intel/ directory to use every maintained catalog at once. The --findings-only flag suppresses the full inventory so you only get matches.
cd ~/tools/bumblebee
./bumblebee scan --profile deep --root "$HOME" \
--exposure-catalog ./threat_intel/ \
--findings-onlyOutput is NDJSON, one JSON object per line. A match looks like this:
{ "record_type": "finding", "severity": "critical", "ecosystem": "npm",
"package_name": "example-pkg", "version": "1.2.3",
"source_file": "/Users/you/code/app/pnpm-lock.yaml",
"evidence": "exact name+version match (version=1.2.3)" }If you are clean, you get no finding records. Exit code is 0 on a successful run, 1 if the scan hit errors, 2 for bad arguments.
Scan profiles control where Bumblebee looks. baseline checks standard global tool, editor, and browser locations. project scans your development directories (pass --root ~/code). deep walks whatever roots you give it, typically your whole home directory. Use deep for the most thorough "am I exposed anywhere" check, or project for a faster daily scan of your repos.
4. Create a Telegram bot and start the connector
Create a bot
Open Telegram, start a chat with @BotFather, send /newbot, and follow the prompts. Copy the bot token it gives you (it looks like 7123456789:AAH...). Treat it like a password.
Start the connector
Run the connector and point its working directory at your Bumblebee clone, so the scheduled agent runs there:
cline connect telegram -k "<BOT-TOKEN>" --cwd ~/tools/bumblebeeThe connector starts in the background and keeps running after the command returns. It polls Telegram and delivers scheduled results.
Open the chat
In Telegram, search for your bot's username and send it any message (for example /whereami). This creates the thread binding that delivery needs.
By default, anyone who finds your bot can message it and it will run tasks on your machine. Lock it down before leaving the connector running. The cline connect wizard can guide you through Telegram user ID setup, or you can message @userinfobot and restart the connector with your allowed user ID:
cline connect telegram -k "<BOT-TOKEN>" --cwd ~/tools/bumblebee \
--allowed-user-id 12345Replace 12345 with your Telegram user ID.
5. Schedule the scan
There are two ways to create the scheduled scan. Both run the same agent and deliver the result to Telegram, so pick whichever you prefer.
Option A: From the Telegram chat
Creating the schedule from the chat automatically targets that thread for delivery, so results come straight back to you. Send this to your bot as a single message:
/schedule create "supply-chain-watch" --cron "0 8 * * *" --prompt "Pull the latest Bumblebee catalogs and scan this machine for compromised packages. Run: git pull --quiet && go build -o bumblebee ./cmd/bumblebee && ./bumblebee scan --profile deep --root $HOME --exposure-catalog ./threat_intel/ --findings-only. Read the NDJSON output. If any line has record_type set to finding, reply starting with '🚨 COMPROMISE DETECTED' and list each package name, version, ecosystem, and source_file. If there are no findings, reply with exactly '✅ Clean: no compromised packages found.'"The bot replies with the new schedule, including its id.
Option B: From your terminal
First send /whereami to your bot. It replies with the chat's deliveryThread, such as telegram:123456789. Then create the schedule on the same machine and pass that thread. The running Telegram connector delivers the result to that chat:
cline schedule create "supply-chain-watch" \
--cron "0 8 * * *" \
--workspace ~/tools/bumblebee \
--delivery-adapter telegram \
--delivery-thread <deliveryThread> \
--prompt "Pull the latest Bumblebee catalogs and scan this machine for compromised packages. Run: git pull --quiet && go build -o bumblebee ./cmd/bumblebee && ./bumblebee scan --profile deep --root \$HOME --exposure-catalog ./threat_intel/ --findings-only. Read the NDJSON output. If any line has record_type set to finding, reply starting with '🚨 COMPROMISE DETECTED' and list each package name, version, ecosystem, and source_file. If there are no findings, reply with exactly '✅ Clean: no compromised packages found.'"Either way, this schedules a daily scan at 8am.
Why the green check matters
Scheduled delivery always sends the run's final reply, so the prompt is written to make that reply meaningful either way:
- Clean run: one line,
✅ Clean: no compromised packages found.You get a daily heartbeat confirming the scan actually ran. - Exposure:
🚨 COMPROMISE DETECTEDfollowed by the package, version, and the file where it was found, so you can act immediately (rotate credentials, remove the package, pin a safe version).
Test it
Trigger the scan now instead of waiting for 8am.
First find your schedule id. The create step returns it (the Telegram bot's reply shows id=...), or list your schedules at any time:
cline schedule listThen trigger it with that id. From the terminal:
cline schedule trigger <schedule-id>Or from Telegram: /schedule trigger <schedule-id>. Within a few seconds you should get the result in your chat.
To see a real alert, add a package and version that matches a catalog entry to a throwaway project's lockfile and run the scan against it. Bumblebee reports the match, and the agent texts you the red alert.
Keep it running
- The connector must be running for delivery to work. It runs in the background, and the hub starts it again whenever the hub itself starts. Neither starts when the computer boots: after a reboot, run
cline hub start, which brings the connector back. - The hub runs the schedule and starts automatically when you create one. If it is not running, start it with
cline hub start. cline connect --stop telegramstops the connector and keeps the hub from starting it again.- Manage schedules anytime with
cline schedule list,cline schedule pause <id>,cline schedule resume <id>, andcline schedule delete <id>.
Customize
- Cadence: change the cron expression.
0 */6 * * *scans every six hours;0 8 * * MON-FRIruns on weekdays only. - Scope: swap
--profile deep --root $HOMEfor--profile project --root ~/codefor a faster scan of just your repos, or--profile baselinefor global tools, editors, and browser extensions. - Channels: the same delivery pattern works for Slack, Discord, WhatsApp, and Google Chat. See Connectors.
- Fleet use: Bumblebee can
POSTNDJSON to an ingest endpoint with--output http --http-url <url>if you want to centralize findings across many machines.
Credits
Bumblebee is built and open-sourced by Perplexity. See the announcement and the repository.