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-guard

v0.3.2

Published

Block obfuscated build/commit-time code-injection payloads (hidden long-line JS stagers) before they enter your repo. Zero dependencies. Works as a pre-commit hook, in CI, or standalone.

Readme


The problem it solves

Modern supply-chain attacks hide a malicious payload on a single, space-padded line inside an ordinary-looking config or entry file — tailwind.config.js, ecosystem.config.js, .eslintrc.js, postcss.config.js, src/index.ts, etc. The line is hundreds of spaces wide, so the payload scrolls off-screen in your editor and sails through code review:

plugins: [tailwindcssAnimate];
};                                          global['!']='…';var d=String.fromCharCode(127);…require;…Function(…)(…)
//        ^ legitimate code                 ^ hundreds of spaces hide this →→→  obfuscated payload

When the project is built, that line runs with full Node.js access — reading your environment variables, .env, SSH keys, and tokens, and pulling a second stage. Because it sits in a file that's required during dev/build/test, it executes silently and automatically.

polin-guard catches it before it can ever be committed.

Built after a real incident in which this exact payload was committed across multiple repositories and reached production branches.

How it detects (beyond signatures)

polin-guard doesn't just match known payload strings — those are trivially renamed. It detects the necessary conditions of the attack and combines independent signals into a weighted risk score. To stay hidden and execute at build time, a payload is forced to do several of these at once:

| Signal | What it catches | Weight | |--------|-----------------|-------:| | concealment | code hidden after a long mid-line whitespace gap (the off-screen trick) | 80 | | signature | known-family markers (global['!'], global[_$_…], re-exposed require, fromCharCode(127)) | 60 | | escape-density | ≥25 \xNN/\uNNNN escapes on a line (obfuscated blob) | 50 | | exec-sink | dynamic execution: Function() / eval | 40 | | long-token | unbroken ≥120-char token (encoded blob) | 35 | | ctor-chain | constructor.constructor reach to Function | 35 | | oversized-line | line > 1000 chars (+30 more if it carries exec/require tokens) | 25 | | entropy | long, high-entropy line | 25 | | indirect-require · dyn-timer · vm-module | require(<var>), setTimeout("…"), require('vm') | 25 | | net-exec-combo | network + code-exec/file-write together (runtime-fetched payload) | 30 | | network · capability | fetch/http(s), or process.env/fs/child_process | 15 / 10 | | autoloaded-context | the above inside an auto-loaded config/entry file | +20 |

A file-level pass also aggregates across lines, so a payload split across many lines or fetched at runtime still trips the score.

Block at score ≥ 70, warn at ≥ 35 (configurable). Because the signals are independent, evading one (rename, split, runtime-fetch, drop the padding) still trips the others — so evasion becomes self-defeating: visible in review, inert, readable, or capability-less. Lockfiles, minified bundles, source maps, and node_modules are skipped to keep false positives near zero.

Evasion-tested. The suite proves that a renamed (signature-free), split-across-lines, and runtime-fetched payload are all still blocked, while legitimate long-data lines and ordinary dynamic require() are not.

Quick start

npm install --save-dev polin-guard

Scan right now:

npx polin-guard --all      # scan every tracked file in the repo

Block it on every commit (husky)

npm install --save-dev polin-guard husky
npx husky init
echo 'npx --no-install polin-guard --staged' > .husky/pre-commit

That's it. The hook runs on every commit and every git commit --amend, and scans the exact content being committed. A malicious payload makes the commit fail.

Add the CI backstop (recommended)

A local hook can be skipped (git commit --no-verify) or sidestepped by a force-push from a compromised machine. Re-scan on the server, where it can't be skipped — copy examples/github-action.yml to .github/workflows/polin-guard.yml.

No Node? Use the standalone script

Drop scan-injection.sh into your repo (works with the pre-commit framework too):

./scan-injection.sh --staged

Usage

polin-guard [scan] [options] [paths...]   Scan files for injected payloads (default)
polin-guard install-audit [--strict]      Audit dependencies for supply-chain risk
polin-guard harden [--fix]                Check/enable install-time hardening

Scan options:
  --staged     Scan staged content (default; for pre-commit hooks; covers --amend)
  --all        Scan all git-tracked files
  --ci         Alias for --all (use in CI)
  [paths...]   Scan specific files (no git required)
  --strict     Treat warnings as blocking too
  -h, --help   ·   -v, --version

Exit 0 = clean · 1 = blocking finding · 2 = usage error

Supply-chain audit (root-cause defense)

The scanner catches a payload that's already in your tree. install-audit attacks the entry point — the malicious dependency that runs code at npm install/build time — without installing anything:

npx polin-guard install-audit

It flags, by reading package.json and your lockfile:

  • 🔴 malicious lifecycle scriptspostinstall/prepare/… that pipe the network to a shell, eval, node -e, base64, raw-IP URLs, child_process
  • 🔴 non-default registry resolutions in the lockfile (registry hijack)
  • 🔴 typosquat / homoglyph dependency names (one edit away from popular packages)
  • 🟡 non-registry sources (git/http/tarball/file) dependencies
  • ℹ️ a count of packages that declare install/build scripts — your real attack surface

Then shut the door so dependency scripts can't execute at all:

npx polin-guard harden --fix     # writes ignore-scripts=true to .npmrc

Run install-audit in CI too — see examples/github-action.yml.

Configuration

Optional .polinguardrc.json in your repo root:

{
  "maxLineLength": 1000,
  "maxEscapes": 25,
  "excludeDirs": ["node_modules", "dist", "build", "vendor"],
  "includeExtensions": [".js", ".cjs", ".mjs", ".jsx", ".ts", ".tsx", ".vue", ".json", ".bat", ".cmd", ".ps1", ".sh"]
}

Acknowledging a verified false positive (e.g. a legitimate inline blob):

  • add // polinguard-allow-line on the same line, or
  • add // polinguard-allow-next-line on the line above it, or
  • raise maxLineLength / exclude the path in .polinguardrc.json.

Never use git commit --no-verify to push past a finding you don't understand.

Audit an existing repo or whole org

# one repo
npx polin-guard --all

# every branch of every repo in a GitHub org
for r in $(gh repo list YOUR_ORG --limit 200 --json name --jq '.[].name'); do
  git clone -q "https://github.com/YOUR_ORG/$r.git" "/tmp/scan/$r" || continue
  ( cd "/tmp/scan/$r"
    for b in $(git branch -r | grep -v HEAD | sed 's# *origin/##'); do
      git checkout -q "$b" 2>/dev/null && { npx --yes polin-guard --all || echo "FOUND in $r @ $b"; }
    done )
done

How it works

Pure Node, zero dependencies (so the security tool adds no supply-chain risk of its own). For each candidate file it reads the staged blob (git show :file) or the working copy, analyzes every line against the rules above, and exits non-zero on any critical finding so your hook or CI step fails.

Links

  • 📦 npm: https://www.npmjs.com/package/polin-guard
  • 🐙 GitHub: https://github.com/Valentin-Shyaka/polin-guard
  • 🐛 Issues: https://github.com/Valentin-Shyaka/polin-guard/issues
  • 🔒 Security policy: SECURITY.md
  • 🤝 Contributing: CONTRIBUTING.md

License

MIT © Valentin Shyaka