npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

polin-rider-scanner

v1.0.2

Published

Read-only PolinRider / Glassworm supply-chain malware (IOC) scanner — use as a library in CI/pipelines or as a CLI to scan local files and folders

Readme

polin-rider-scanner

Read-only IOC scanner for the Operation PolinRider / Glassworm supply-chain compromise (DPRK threat actor: obfuscated JS loader, blockchain C2, VS Code auto-run, asset-as-code fonts, invisible-Unicode injection, malicious npm packages).

Built to gate automated pipelines — any remote server or process that pulls and builds/processes application code (CI, build, release, deploy jobs, etc.): scan the code a job has pulled, and abort + quarantine if the verdict is unsafe.

Install

npm install polin-rider-scanner      # as a dependency (library)
# or run the CLI without installing:
npx polin-rider-scanner <dir>
# or install the CLI globally:
npm install -g polin-rider-scanner

Requires Node.js >= 18. ESM-only.

CLI

polin-rider-scanner <dir> [--all] [--git-history] [--json]
#   <dir>           directory to scan (default: current directory)
#   --all           also scan deps/build dirs (node_modules, dist, …)
#   --git-history    also grep git history for content signatures (needs git)
#   --json          machine-readable result on stdout
# exit 0 = safe, exit 1 = unsafe (HIGH found) or degraded scan

# examples
npx polin-rider-scanner .                 # scan the current folder
npx polin-rider-scanner ./app --all       # include dependencies
npx polin-rider-scanner ./app --json | jq .safe

The non-zero exit on unsafe/degraded lets you gate a pipeline directly:

npx polin-rider-scanner "$CHECKOUT_DIR" --all || exit 1

Library

import { scanForMalware } from "polin-rider-scanner";

const r = scanForMalware(sourceDir, { all: true });
if (!r.safe) {
  // r.reasons -> HIGH findings; quarantine the checkout and fail the job
  throw new Error("PolinRider IOC detected");
}

scanForMalware is a pure function: it returns a result object, prints nothing, and never calls process.exit — the caller decides what to do. TypeScript types are bundled (scanner.d.ts).

Result object

{
  safe,      // true ONLY when high === 0 AND not degraded
  blocked,   // !safe
  degraded,  // a check could not run (missing perms/tools) -> treat as unsafe
  high, med, low,
  reasons,   // HIGH findings, grouped by label, with file:line lists
  warnings,  // MED + LOW (advisory)
  findings,  // raw [{ sev, label, path, line, detail }]
  errors,    // capability failures (these set degraded)
  notes,     // informational (skipped large binaries, finding caps) — do NOT degrade
  stats,     // { files, bytes, elapsedMs }
}

Severity model — why all: true is safe and noise-free

The blocking verdict (safe) is driven only by HIGH signatures, which are malware-specific and do not occur in legitimate code — including across large dependency trees, where they produce zero false positives. So scanning node_modules is both safe and desirable (the payload often lands in a dependency or a config file).

HIGH (blocks the build):

  • polinrider:injection-markerglobal['x']='8-…' loader fingerprint
  • polinrider:global-require-rebindglobal[_$_1e42[0]]=require
  • polinrider:decoder-stub / -af_$_<hex> / _$af<n> obfuscator stubs
  • polinrider:sig-marker — shuffle-input strings rmcej%otb%, Cot%3t=shtP
  • polinrider:tron-exfil-queryonly_confirmed=true&only_from=true
  • addr:* — hardcoded attacker TRON/Aptos dead-drop addresses
  • npm:malicious-package — known PolinRider npm packages
  • fake-asset / fake-asset-payload — font/image with wrong magic bytes carrying JS, or a real binary asset with an embedded loader signature (the .woff2 vector)
  • known-malware-hash — known sample SHA-256
  • vscode:autorun-folderOpen — a .vscode/tasks.json task with runOn:"folderOpen"
  • git-history:IOC — content signature in git history (only with --git-history)

MED / LOW (advisory — listed in warnings, do not block): blockchain C2 endpoints (legit in real web3 code), shuffle-seed constants, allowAutomaticTasks, off-screen padded-payload lines, Glassworm invisible-Unicode in source files, fromCharCode(127), eth_getTransactionByHash.

What changed from the earlier scanner (v1) and why

  1. node-runs-asset text grep removed. It matched a Markdown shields.io badge (node version … jest-pnp-resolver.svg) in a dependency README and hard-blocked a build. Replaced by a magic-byte asset check that cannot match prose/URLs.
  2. Bare folderOpen grep removed. It matched a react-native-vector-icons glyph. Replaced by parsing .vscode/tasks.json for a real runOn:"folderOpen" task.
  3. Git force-push / commit-date heuristics removed. Legitimate force-pushes and rebases produced false flags. Detection is by file content signature instead; --git-history greps history for the same content signatures (no force-push count).
  4. Standard RPC strings demoted (eth_getTransactionByHash, bare endpoints) to advisory, so legit blockchain code doesn't fail the build.
  5. Fail-closed, but precisely. Real capability failures (unreadable files, missing git when --git-history is set) set degraded and make the scan unsafe. Skipped oversized binaries (.aab/.apk/.node/.zip/…) are notes, not errors — they can't hold a line-based payload, so they don't degrade the verdict.

Notes / limitations

  • Synchronous and single-threaded; a full --all scan of a large tree (incl. node_modules) takes tens of seconds to a few minutes. On a latency-sensitive path, run it in a worker thread / child process.
  • Symlinked directories are not followed (avoids loops); symlinks are skipped.
  • Native compiler / IDE output dirs are pruned in every mode (incl. --all) and recorded as notes (non-degrading): DerivedData, buildDerivedData, dSYMs, and *.xcbuilddata / *.dSYM / *.xcarchive / *.xcresult. They hold compiled binaries derived from source that is still scanned, so an injected loader is caught upstream; pruning them stops a post-build tree from fail-closing on an unscannable multi-MB build manifest. Generic dist/build/lib/out are not pruned under --all — published npm packages ship executable code there, and that is the primary supply-chain vector.
  • Oversized files (> maxFileBytes, default 24 MiB) are not content-scanned.
  • A clean result covers KNOWN IOCs and is not an absolute guarantee.

References

  • https://medium.com/@edawarekaro/operation-polinrider-the-complete-developers-guide-to-detection-containment-and-recovery-c3454bd660e3
  • https://opensourcemalware.com/blog/polinrider-attack
  • https://github.com/OpenSourceMalware/PolinRider