canary
--:--:-- UTCagent𝕏Check your deps

supply-chain watch · npm + pypi · read-only

Every new package,read beforeanyone installs it.

An agent watches the npm and PyPI feeds. Each new release is fetched, unpacked in memory and read line by line: install hooks, hidden layers, secret files next to a network call, wallet grabs, download-and-run. It never installs, never executes. When the rules trip, the package goes on the wall with the exact lines. When the public record agrees, it says confirmed.

canary-agent · journal
connecting to the agent…
packages read
–
read in total
–
tripped, 24h
–
confirmed, 24h
–
rules first
–
  1. 01Every release, within minutesThe npm change feed and the PyPI update feed, polled every 20 seconds. New name or new version, it is fetched.
  2. 02Read, never runUnpacked in memory with a safe extractor. Seven rules read the files, base64 layers are decoded and read too. Each hit keeps its file and line.
  3. 03Tripped, then confirmedEnough weight puts it on the wall as tripped. Only a public advisory makes it confirmed. The gap between the two is measured and shown.
livethe agent, right now–
loading the log…
every line is a package the agent read, with the verdict
what the numbers mean

tripped means our rules added up to the line (score 7) on a new package, or one unmistakable finding landed in a version only hours old of a trusted name. The lines that did it are on the card. It is our word, not the record's.

confirmed means OSV / OpenSSF carries a malware advisory for exactly that version. Nothing else earns the word.

watch is the quiet list: something tripped but not enough. Never shown as a catch, never named on the wall. Established packages (a year old, or 50k downloads a week) stay there no matter what the heuristics say, unless the hijack rule fires.

The recall number appears once the public record confirms a package the agent has read.

a wrong catch gets cleared by a person, in public, with the reasonthe rules →

live

The wall

Newest first. Every card carries the lines that put it there: rule, file, line number, the text itself. No name goes on the wall without its lines. Click through for the full evidence and the registry page.

Scan one package →
loading the wall…

for you

Check your dependency file

Paste or drop a package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, requirements.txt, pyproject.toml or Pipfile. Every name is matched against the wall and against the public malware record. The text is parsed in memory and dropped; the agent keeps a counter, not your file.

⌘↵ to run

Up to 500 names per check, ten checks a minute. A clean result says nothing is on the record, which is a fact about the record, not a promise about the code.

the result shows here: a table of what is on the record, or a clear line

the method

How it works

One loop, four steps, all of it in the open. The code is a single Python package with no build step; the box runs it in a sandbox that cannot write outside its data directory.

The code on GitHub →
01 · feed

New releases, as they land

npm's replicate _changes stream and PyPI's updates and newest-projects RSS, polled every 20 seconds. Only names, no code yet. @types/* is skipped: generated typings, never a payload.

02 · fetch

Bytes, not an install

The tarball or sdist is downloaded and unpacked in memory by an extractor that drops absolute paths, .., symlinks and device files, caps file count, file size and total size, and keeps only the bytes. Nothing touches the disk. Nothing is imported.

03 · read

Seven rules, each with evidence

Install hooks, obfuscation, exfiltration (secret files and a network call), wallet grabs, shell shapes, stray binaries, lookalike names. Base64 blobs that decode to code become virtual files and get read too. Tests, docs and CI files count for nothing unless an install script points at them.

04 · record

Ask the record, then keep asking

Every package is looked up at OSV.dev, which carries the OpenSSF malicious-packages advisories. A hit is confirmed. A tripped catch is re-asked every six hours for a month; when the record catches up, the feed says how many hours after the rules did.

05 · trusted names

Established packages are not shamed

A year old or 50k downloads a week: heuristics alone never put it on the wall; it can only land in the quiet list. The one exception is the hijack rule: a version younger than 72 hours carrying one finding of weight 5 and a score over the line.

06 · corrections

A person can clear a catch

A file on the box, cleared.json, maps a package to a reason. The catch stays visible, marked cleared, with the reason. Nothing is deleted. The number of cleared catches is a public counter, because a scanner that hides its mistakes is not worth reading.

feed→fetch bytes→safe unpack→decode layers→7 rules→score→osv→wall · watch · clean→recheck 6h

published

The rules

Read straight from the agent's rules.json, so the page cannot drift from the code. A rule counts once, at its strongest hit; two weak rules do not add up to a catch on their own.

rules.py →
ruleweightwhat trips it
loading rules.json…
the line
7score at which a new package is tripped
quiet list
3score at which it is watched, never shown
strong finding
5one of these in a fresh version trips a trusted name
fresh
72 hhow young a version must be for the hijack rule

the token · solana

$CANARY

The project token. It gates nothing: the wall, the checks and the code stay free for everyone. It is how the project is funded and how it is held to account in public.

mintloading…

what holders get

The agent, the API and the wall are paid for by the project. The contract address, the burns and every change to the rules are posted on the project account first, so the token is the only place where the record of the project itself lives.

Nothing on this page asks for a wallet. The Buy button opens a swap in your own wallet; the site never holds funds, keys or packages.

by construction

Hard limits

Things the agent cannot do, because the code has no path to them. Read the source; the list is short.

×
Never installs or runs a package

Bytes are read from an in-memory archive. There is no npm install, no pip, no import, no subprocess anywhere in the agent.

×
Never names a package without its lines

A catch is a list of findings, each with a file, a line number and the text. A card without evidence cannot be rendered.

×
Never calls anything confirmed on its own

Confirmed is a word that only a public advisory at OSV / OpenSSF can earn. Our rules can say tripped, and that is all they can say.

×
Never keeps what you paste

The check endpoint parses the text, answers, and drops it. The data directory holds the wall and counters; your dependency file is never written.

×
Never posts, never trades

The agent has no credentials of any kind. No X account, no wallet, no tokens. It writes json files, and that is the whole of its output.

×
Never hides a mistake

Cleared catches stay on the wall with the reason. Misses against the public record are counted and shown as the recall number, even when that number is embarrassing.