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

scrubpii

v0.1.1

Published

Find and redact PII & secrets — emails, Luhn-valid credit cards, JWTs, API keys, IBANs, SSNs, IPs — from JSON, logs and text. 100% local, no upload. Deterministic detection, referential-integrity pseudonyms, JSON-path & key-aware redaction. CLI + library,

Readme

🧽 scrubpii

Make any payload, log, or fixture safe to share — strip PII & secrets locally, in one pipe.

npm version bundle size CI types license

🌐 Try the browser playground →  ·  paste a payload, get a safe-to-share copy. Nothing is uploaded — it all runs client-side.

You need to attach a production API response to a GitHub issue. Or commit a realistic test fixture. Or drop a log into Slack so a teammate can repro. But it's full of emails, card numbers, JWTs, API keys, IPs, SSNs — and the one tool everyone reaches for, an online redactor, asks you to upload the very data you're trying to protect.

scrubpii finds and redacts PII & secrets from JSON, logs and text — 100% locally, deterministically, in one command. Nothing is uploaded. Nothing leaves your machine.

cat payload.json | npx scrubpii redact
- "email": "[email protected]",
+ "email": "[email protected]",
- "card_number": "4242 4242 4242 4242",
+ "card_number": "redacted_1",
- "authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...",
+ "authorization": "redacted_2",

Why scrubpii (and not a quick sed or an LLM)?

  • 🔒 Local & deterministic. No server, no API key, no telemetry. Same input → same output, every time. Safe for secrets because it never sees the network.
  • 🎯 Precision over noise. Credit cards are confirmed with the Luhn checksum, IBANs with mod-97, JWTs by decoding the header — so a random 16-digit order ID isn't flagged as a card. A redactor that cries wolf gets turned off.
  • 🔗 Referential integrity. [email protected] becomes [email protected] everywhere it appears — so the redacted document still shows that two log lines are the same user. sed and online tools destroy that.
  • 🧩 JSON-aware. Walks the document, redacts values whose key is sensitive (password, authorization, api_key — even with no detectable pattern) and scrubs PII hiding inside free-text fields. Output is still valid JSON, same shape.
  • 🪶 Zero-dependency core. The library imports nothing at runtime and runs in the browser, Node, Deno and Bun. The CLI adds only cac + picocolors.

Why not just ask an LLM? You can't paste a 50 MB log into a chat, you can't put a chatbot in CI, and "redact the secrets" from a model is non-deterministic — it will miss some and hallucinate others. scrubpii is a checksum, not a guess.

Install

# zero-install, run it now
npx scrubpii scan payload.json

# or add it
npm install -g scrubpii      # global CLI
npm install -D scrubpii      # CI / pre-commit dependency
npm install scrubpii         # library

Node ≥ 18. Ships ESM + CJS + TypeScript types.

Quick start

# 1. See what's in there (read-only, nothing changes)
scrubpii scan payload.json

# 2. Get a safe copy on stdout
cat payload.json | scrubpii redact > safe.json

# 3. Use it as a CI / pre-commit guard — exit 1 if anything is found
scrubpii scan ./src --max-findings 0

scan — find, don't touch

$ scrubpii scan examples/app.log

examples/app.log (text)  10 findings
  1:42  Email address              a***@***.com
  2:41  JWT                        eyJ…90
  3:46  Credit card (Luhn-valid)   **** **** **** 4242
  4:45  URL credentials            svc…ss
  6:36  AWS access key             AKI…LE
  6:62  GitHub token               ghp…AB

Summary  4 secrets · 4 PII · 2 network across 1 file

Previews are always masked — scrubpii never prints the full secret, not even in its own reports.

redact — produce a safe copy

scrubpii redact users.json --out clean.json          # pseudonyms (default)
scrubpii redact users.json --strategy hash            # stable [EMAIL:32oeg5] tokens
scrubpii redact users.json --strategy label           # [EMAIL], [REDACTED]
scrubpii redact ./logs --in-place                      # rewrite a whole folder
echo "ping [email protected]" | scrubpii redact                  # pipe anything

| Strategy | [email protected] becomes | Keeps links? | Best for | | ------------ | ------------------- | :----------: | -------- | | pseudonym | [email protected] | ✅ | shareable, realistic fixtures (default) | | hash | [EMAIL:32oeg5] | ✅ | stable IDs across files, no counter state | | label | [EMAIL] | ❌ | quickest "just hide it" | | partial | a***@***.com | ❌ | keep a human hint | | remove | (deleted) | ❌ | strip entirely |

What it detects

Secrets — private keys, AWS access keys, GitHub / Slack / Stripe / OpenAI / Google / SendGrid keys, JWTs, user:pass@ URL credentials. PII — emails, Luhn-valid credit cards, mod-97 IBANs, US SSNs, phone numbers. Network — IPv4, IPv6, MAC addresses. JSON keys — any value under password, secret, token, authorization, api_key, cvv, pin, … (configurable), even when the value has no pattern.

Use it in your workflow

1. Sanitize before you paste. Bug report, Slack, screen-share — one pipe makes a prod payload safe to share, with relationships intact so it's still reproducible:

kubectl logs my-pod | scrubpii redact | pbcopy

2. Commit realistic fixtures from real data. Redact a prod export into test/fixtures with consistent pseudonyms, so foreign keys and "same user across rows" still hold — something hand-redaction always breaks:

scrubpii redact prod-export.json --strategy hash --out test/fixtures/users.json

3. Guard your repo / CI. Fail the build (or a pre-commit hook) the moment a real secret or customer record is about to be committed:

# .github/workflows/ci.yml
- run: npx scrubpii scan . --max-findings 0 --md scrubpii-report.md
# .husky/pre-commit
git diff --cached --name-only | xargs scrubpii scan --max-findings 0

Library API

import { redact, detect, Vault } from "scrubpii";

// Auto-detects JSON vs text:
const { output, findings, format } = redact(input, { strategy: "pseudonym" });

// Read-only detection with line/column (great for editors & CI):
for (const f of detect(logText)) {
  console.log(`${f.line}:${f.column}  ${f.label}  ${f.preview}`);
}

// Share one Vault to keep pseudonyms consistent across many documents:
const vault = new Vault("pseudonym");
const a = redact(file1, {}, vault);
const b = redact(file2, {}, vault); // same person → same alias in both

Also exported: redactText, redactJson, redactJsonValue, looksLikeJson, DETECTORS, luhnValid / ibanValid / jwtValid / ssnValid, and all types.

Configuration

scrubpii init writes scrubpii.config.json:

{
  "strategy": "pseudonym",
  "enable": [],            // [] = all types; or e.g. ["email", "credit-card"]
  "disable": ["phone"],    // turn specific detectors off
  "redactKeys": ["password", "token", "authorization", "..."],
  "salt": "",              // mixed into the hash strategy
  "maxFindings": 0          // CI gate threshold
}

CLI flags override the file: --only, --except, --strategy, --salt, --max-findings, --format json|text|auto, --config <file>.

Roadmap

  • 🤖 Optional --ai layer (bring-your-own key). A pluggable NER pass to catch free-text names/addresses that rules can't — strictly opt-in; the core stays 100% offline and deterministic.
  • 🔁 Reversible pseudonyms. Write the mapping to a local keyfile so a redacted fixture can be re-hydrated for debugging.
  • ➕ More secret providers, custom regex detectors, and per-path ignore rules.
  • 🌊 Streaming mode for multi-GB logs.
  • ✅ 🌐 A browser playground (paste a payload, see redactions — nothing uploaded). Live here.

Issues and PRs welcome — especially new detectors with test vectors.

💖 Sponsor

scrubpii is free and MIT-licensed, built and maintained in spare time. If it saved you from leaking a customer record (or an afternoon of manual redaction), please consider supporting it:

  • Star this repo — the simplest free way to help others find it.
  • 🍋 Sponsor via Lemon Squeezy — one-time or recurring.

License

MIT © scrubpii contributors