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

@alikhanmammadli/secret-sentinel

v0.1.0

Published

A Claude Code PreToolUse hook that blocks hardcoded secrets, missing auth checks, open CORS, and disabled DB rules before they are written to disk.

Readme

Secret Sentinel

A Claude Code hook that blocks security flaws the moment they'd be written to disk — not after they're committed, deployed, or exploited.

Hardcoded secrets, missing auth checks, open CORS, disabled database rules. Secret Sentinel runs inside your Claude Code session as a PreToolUse hook, inspects every file Claude is about to write or edit, and stops the write before it happens.

🛑 BLOCKED — Hardcoded Stripe secret key detected

File: src/payments.ts, line 3
Found: Stripe live secret key — sk_l************zXcV

Why this matters: this is a live Stripe key, not a test one. Anyone who can see
this file can charge your Stripe account, issue refunds, or read your customer data.

Why this exists

AI-generated code ships with a higher vulnerability rate than hand-written code, and vibe-coded apps disproportionately leak secrets, skip auth, and leave databases wide open.

Traditional workflows caught this with friction — code review, a senior engineer spotting a hardcoded key, a deploy checklist. Vibe coding removes that friction on purpose. That's the point of it. But it also removes the people who used to catch the mistakes.

Existing tools — gitleaks, GitHub secret scanning, post-deploy scanners — all catch the problem after the fact: at commit time, at push time, or once the app is already live. By then you've already looked at the change, said "looks good," and moved on.

Secret Sentinel sits one step earlier, inside the loop itself.

Install

npx @alikhanmammadli/secret-sentinel init

That's it. It adds a PreToolUse entry to your project's .claude/settings.json and prints exactly what it wrote:

Secret Sentinel: added the PreToolUse hook in
  /your/project/.claude/settings.json (created)

  matcher: Write|Edit
  command: node /path/to/secret-sentinel/dist/src/hook.js

It will check every file Claude Code writes or edits in this project.

No account, no dashboard, no server. It merges into an existing settings.json without touching your other settings or hooks, and re-running it updates in place rather than adding a duplicate.

Requires Node 20.10+.

What it catches

| Scanner | Catches | Severity | |---|---|---| | secrets | AWS / Stripe / GitHub / Slack / Google keys, private key blocks, DB connection strings with credentials, generic API_KEY = "..." assignments, plus a Shannon-entropy fallback for secrets that match no known format | blocks | | db-rules | Firestore allow read, write: if true, Supabase RLS policies with USING (true) and no auth check, DISABLE ROW LEVEL SECURITY | blocks | | cors | Wildcard origins, origin: true, bare cors() | warns — blocks when paired with credentials | | auth | Express routes and Next.js API routes defined with no auth guard | warns |

Blocks stop the write. Warns prompt you in-session, and you approve or reject right there.

Before / after

Blocked: a hardcoded secret

Claude tries to write src/payments.ts:

import Stripe from "stripe";

export const stripe = new Stripe("sk_live_51QwErTyUiOpAsDfGhJkLzXcV");

The write never lands. Claude sees this instead:

🛑 BLOCKED — Hardcoded Stripe secret key detected

File: src/payments.ts, line 3
Found: Stripe live secret key — sk_l************zXcV

Why this matters: this is a live Stripe key, not a test one. Anyone who can see
this file can charge your Stripe account, issue refunds, or read your customer data.

Fix: move it to an environment variable instead:
  1. Add STRIPE_SECRET_KEY=... to your .env file, using the value currently on line 3
  2. Add .env to .gitignore if it isn't already
  3. Reference it in code as process.env.STRIPE_SECRET_KEY

If this credential was ever committed or shared, rotate it — removing it from
the file does not un-leak it.

Override: if this is deliberate, tell Claude why and it can go ahead.
To stop it being flagged here again, add this to "allow" in .secret-sentinel.json:
  { "id": "secrets/stripe-live-key", "paths": ["src/payments.ts"] }

Note the key is masked. The finding goes into your transcript, so it doesn't echo the credential back.

Blocked: an open database

Claude tries to write firestore.rules:

match /{document=**} {
  allow read, write: if true;
}
🛑 BLOCKED — Firestore rules allow public read/write

File: firestore.rules, line 4
Found: a Firestore security rule granting access `if true` — that is, to everyone

Why this matters: this rule lets anyone on the internet read and write this
collection directly, without going through your app at all. They don't need an
account, and they don't need to find a bug — the database is simply open. This is
the single most common way vibe-coded apps leak their entire user table.

Fix: gate the rule on authentication and ownership instead of `true`:
  1. Require a signed-in user:      allow read: if request.auth != null;
  2. Scope writes to the owner:     allow write: if request.auth.uid == userId;
  3. Re-deploy the rules and re-test with the Firestore rules simulator

Warned: open CORS

Heuristic findings prompt rather than block, so you stay in control:

⚠️  WARNING — Open CORS policy detected

File: src/server.ts, line 2
Found: a CORS `origin` set to the `*` wildcard

Why this matters: any website on the internet can make browser requests to this
API and read the responses. If any endpoint returns data that isn't fully public,
another site can pull it out of your users' browsers.

Fix: replace the wildcard with an explicit allowlist:
  1. List the origins that actually need access, e.g.
     const allowed = ['https://app.yourdomain.com'];
  2. Pass that list as the origin: app.use(cors({ origin: allowed }))
  3. Keep the list in an environment variable if it differs per environment

You approve, and the write goes through. Reject, and Claude fixes it.

How it works

Claude Code fires a PreToolUse hook before a tool call runs, and lets the hook allow, block, or prompt. Secret Sentinel is that hook.

  1. Claude proposes a write. Claude Code sends the hook a JSON payload on stdin with the tool name and its arguments.
  2. The file is normalized. Write carries the whole file. Edit carries only old_string/new_string, so Secret Sentinel reads the current file and applies the edit itself — scanners always see complete file content, never a fragment.
  3. Scanners run. Each is a pure (filePath, content) => Finding[] function. Every finding carries a plain-English explanation of what was found, why it's risky, and what to do instead.
  4. Your config applies. Ignored paths, allowlisted findings, and severity overrides from .secret-sentinel.json.
  5. A decision goes back. deny blocks the write outright. ask prompts you. Nothing found means the write proceeds under your normal permission settings.

It fails closed. If a scanner crashes, the rules file is corrupt, or anything else goes wrong, Secret Sentinel blocks and tells you why, rather than waving the write through. A crash that blocks is a bug you report; a crash that allows is a leaked credential nobody notices.

Tuning it

False positives are the reason tools like this get uninstalled, so there's a .secret-sentinel.json in your project root:

{
  "ignorePaths": ["dist", "vendor", "**/*.generated.ts"],
  "allow": [
    { "id": "secrets/entropy", "paths": ["src/legacy/fixtures.ts"] }
  ],
  "severity": {
    "cors": "block",
    "auth": "warn"
  }
}
  • ignorePaths — globs that are never scanned at all.
  • allow — findings confirmed as false positives. Scope them to a path (as above) so you don't silence a rule everywhere; a bare "secrets/entropy" string suppresses it project-wide if that's genuinely what you want.
  • severity — override per scanner ("cors") or per finding ("cors/wildcard-origin-option").

The everyday override isn't this file, though — it's the in-session prompt. Reach for the config only when something keeps re-triggering.

Limitations

Worth knowing before you rely on it:

  • Write coverage is Write and Edit. Files written via Bash redirects or other tools bypass the hook.
  • The auth scanner sees one file at a time. A Next.js route protected only by middleware.ts will warn. Mark it // @public to silence it.
  • It is not a SAST tool. The goal is the specific, high-frequency mistakes that actually ship — not comprehensive coverage. Keep using gitleaks and friends.
  • Frameworks covered are Express and Next.js for auth, Supabase and Firestore for database rules.

Development

npm install
npm test

npm test builds first, then runs the suite: scanner fixtures (known-bad and known-good), config behavior, the installer's merge logic, and the fail-closed guarantees.

License

MIT #� �s�e�c�r�e�t�-�s�e�n�t�i�n�a�l� � �