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

prodguard

v0.10.0

Published

Fails your CI when an AI coding agent disables Supabase Row Level Security, widens a Postgres grant, exposes a service_role key, or skips Stripe webhook verification. Zero-dependency Node CLI and GitHub Action, 22 rules.

Readme

ProdGuard

Fails your CI when an AI coding agent disables Supabase Row Level Security, widens a Postgres grant, exposes a service_role key, or skips Stripe webhook verification. Zero-dependency Node CLI and GitHub Action, 22 rules.

npx prodguard check

Zero dependencies. Runs in about a second. Works with whatever agent you use — Claude Code, Cursor, Copilot, Codex.

prodguard.vercel.app


Why this exists

An AI agent asked to make something work will often take the fastest path, and the fastest path is frequently to remove whatever is blocking it. RLS switched off to fix a query. A paywall gate pinned to false for a demo. Email confirmations disabled to speed up testing.

None of it looks wrong afterwards. The tests still pass, because there are rarely tests on billing. The app still looks fine, because from the outside a broken paywall looks exactly like a working one.

This checks for that specific class of change — the things that quietly cost money or leak data — and fails your build when it finds them.

Never used a terminal command? Start here

Two minutes, and it installs nothing permanently.

1. Check you have Node. Open Terminal (Mac: press ⌘+Space, type terminal, enter) or PowerShell (Windows: Start menu). Paste:

node --version

A number like v20.11.0 means you're set. command not found means install Node from nodejs.org, then close and reopen Terminal.

2. See what it does, without touching your code.

npx prodguard check --demo

It asks Ok to proceed? (y) the first time — press enter. This runs against a broken example app inside the tool. Your files are not read.

3. Point it at your project. Type cd and a space, then drag your project folder onto the Terminal window (that pastes the path), press enter, then:

npx prodguard check

4. Read the results. Each finding names a file and line, like src/pages/Dashboard.jsx:20. Open it, go to that line, decide for yourself. A finding is a prompt to look, not a verdict.

5. Optional — run it automatically.

npx prodguard init

Writes two small files. Commit them and GitHub runs the check on every pull request, including the ones your agent opens.

Stuck? Open an issue and say where you got lost.


What it catches

| Check | Severity | What it means in plain English | |---|---|---| | paywall-disabled | 🔴 critical | Your paid features are unlocked for everyone | | stripe-webhook-unverified | 🔴 critical | Anyone can POST a fake payment and unlock an account | | service-role-key-exposed | 🔴 critical | Your admin database key can reach the browser | | rls-disabled | 🔴 critical | Row Level Security is off — users can read each other's rows | | live-secret-committed | 🔴 critical | A live Stripe/Anthropic/OpenAI key is in your source tree | | rls-never-enabled | 🟠 high | A table was created and RLS was never turned on for it | | email-verification-disabled | 🟠 high | Accounts go live without proving they own the email | | credential-file-committed | 🔴 critical | A recovery-codes or credentials file is sitting in the repo | | jwt-not-verified | 🔴 critical | Login tokens are decoded but never signature-checked | | firebase-rules-open | 🔴 critical | Firebase rules allow anyone to read or write | | cors-wildcard-credentials | 🟠 high | Any website can call your API with your users' cookies | | destructive-migration | 🟠 high | A migration drops or truncates a table | | security-definer-anon-executable | 🔴 critical | A SECURITY DEFINER function is granted to anon, so anyone can run it as the owner | | security-definer-view | 🟠 high | A view in public has no security_invoker, so it reads past RLS | | security-definer-search-path | 🟡 medium | A SECURITY DEFINER function has no fixed SET search_path | | anon-write-grant | 🔴 critical | Insert/update/delete granted to anon or PUBLIC on a table | | duplicate-permissive-policy | 🔴 critical | A USING (true) policy sits beside a real one — permissive policies are OR'd | | grant-all-on-table | 🟠 high | GRANT ALL supersedes column-level grants and includes TRUNCATE | | policy-missing-to-clause | 🟠 high | No TO clause plus an identity-independent predicate, so anon gets rows | | policy-references-missing-column | 🟡 medium | A policy predicate names a column no migration creates | | grant-schema-wide | 🔴 critical | GRANT ... ON ALL TABLES IN SCHEMA to a client-reachable role | | policy-write-check-open | 🔴 critical | Scoped USING paired with WITH CHECK (true), so writes are unrestricted |

Reports are written for humans, not scanners:

🔴 CRITICAL  Paid features are unlocked for everyone  paywall-disabled

   Your paywall is hardcoded open. Every visitor gets the paid product for
   free, and your Stripe subscriptions stop meaning anything.

   src/pages/Dashboard.jsx:20
     const locked = false
     → `locked` is pinned to `false` instead of being derived from the
     → user's subscription.

No CWE numbers. If you can build the app, you can read the report.

Usage

npx prodguard check --demo       # see all nine fire on a broken example app
npx prodguard check              # scan the current directory
npx prodguard check ./my-app     # scan somewhere else
npx prodguard check --strict     # also fail on HIGH, not just CRITICAL
npx prodguard check --json       # machine-readable
npx prodguard rules              # list every check

Exit code is 1 when something blocking is found, so it works in CI as-is.

Put it in front of your agent

npx prodguard init

Writes a config file and a GitHub Action that runs on every pull request — including the ones your agent opens. Commit both and dangerous changes stop merging.

Want it even earlier, before a commit is even made:

echo 'npx prodguard check' >> .husky/pre-commit

Configuration

.prodguardrc.json:

{
  "strict": false,
  "allow": [
    "destructive-migration:supabase/migrations/001_teardown.sql",
    "rls-never-enabled"
  ]
}

An allow entry is either a rule id (mute it everywhere) or ruleId:path-fragment (mute it in matching files only). Prefer the narrow form — muting a whole rule is how these things rot.

What it is not

  • Not a linter. It only looks for changes that cost money or leak data.
  • Not an observability dashboard. Nothing to sign up for, no data leaves your machine.
  • Not a guarantee. A clean run means these specific checks didn't fire. It does not mean your app is secure.

It uses pattern matching, not full program analysis. It will miss creative ways of breaking the same things, and it can be wrong — if it flags something that's genuinely fine, add an allow entry and move on.

Contributing a rule

Every rule lives in src/rules.js and is about twenty lines: an id, a severity, a plain-English explanation, and a run(files) that returns findings. If an agent broke something in your app in a way ProdGuard didn't catch, that's a rule worth adding — open an issue with the diff.

node test/run.js

The suite scans two fixture repos: test/fixtures/bad must trip every rule, test/fixtures/good must trip none.

Use it from inside Claude Code

The agent that turns these controls off can also be the one that checks. skill/SKILL.md in this repo is a Claude Code skill: drop it in and Claude runs the scan itself, reads the findings, and proposes the fix before you ship.

mkdir -p .claude/skills/prodguard
curl -o .claude/skills/prodguard/SKILL.md \
  https://raw.githubusercontent.com/Felix0731/prodguard/main/skill/SKILL.md

It tells Claude what the tool does not cover as clearly as what it does, so a clean run never gets reported to you as "your app is secure".

License

MIT