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

cc-scrub

v0.1.1

Published

Find and remove exposed secrets from Claude Code session history, plus a live hook to catch them before they land in context.

Readme

cc-scrub

Find, redact, and prevent secrets leaking into local Claude Code session transcripts.

Claude Code stores every session as a .jsonl file under ~/.claude/projects/. If you ever pasted an API key, token, or credential into a session — or Claude read a file/ran a command that echoed one back — it's sitting in that transcript in plaintext. cc-scrub finds it, lets you redact it in place without breaking Claude Code's ability to resume the session, and can install a live hook that catches secrets before they ever land in context.

Quick Start

npx cc-scrub scan          # scan every local session for secrets
npx cc-scrub clean <id>    # preview redactions for one session
npx cc-scrub clean <id> --yes   # redact in place (writes a .bak first)
npx cc-scrub protect       # install a live redaction hook going forward

No required external dependencies. If gitleaks is on your PATH, cc-scrub uses it; otherwise it automatically falls back to a bundled in-process ruleset (see "Detection engines" below). Run cc-scrub doctor to see which one is active.

Usage

| Command | What it does | |---|---| | cc-scrub list | List local sessions, newest first | | cc-scrub scan [session-id] | Scan one session, or all of them if omitted. Exit code 1 if anything is found | | cc-scrub clean <session-id> | Dry run — show what would be redacted | | cc-scrub clean <session-id> --yes | Redact in place. Always backs up to <session>.jsonl.bak first, never overwrites an existing backup | | cc-scrub doctor | Show which detection engine is active and how many rules loaded | | cc-scrub protect | Add a PostToolUse hook to ~/.claude/settings.json that redacts secrets from tool output before Claude sees it | | cc-scrub unprotect | Remove that hook |

Add --engine auto\|gitleaks\|local to scan/clean to control which engine runs (default auto: gitleaks binary if installed, else the bundled ruleset). Flag values can be passed as --engine local or --engine=local.

Install as a plugin

If you install cc-scrub via the Claude Code plugin system instead of npm, the bundled .claude-plugin/plugin.json registers the same PostToolUse redaction hook automatically — no need to run protect separately.

Detection engines

cc-scrub ships two interchangeable engines rather than committing to just one:

  • gitleaks (binary) — shells out to the real gitleaks CLI when it's on PATH. Full fidelity: this is the actual upstream engine, regex dialect and all.
  • local (bundled, in-process) — vendor/gitleaks.toml is gitleaks' own public MIT-licensed ruleset (pinned to the version this package was built against), vendored directly into the repo. src/rules.ts parses it and src/localDetect.ts runs it line-by-line in plain TypeScript: keyword pre-filtering, regex matching, Shannon-entropy thresholding, and per-rule/global allowlist filtering — no subprocess, no temp files, no external binary required. cc-scrub doctor reports how many rules loaded (221 of 222 at last check; the one skip is a path-only rule with no content regex, correctly inapplicable here).

--engine auto (the default) prefers the gitleaks binary when present and falls back to local otherwise — including inside the live protect hook, which no longer goes fully silent just because gitleaks isn't installed.

Why not just ship local as the only engine? Two RE2-to-JS regex dialect differences had to be translated (Go/Python-style named groups (?P<name>...) → JS's (?<name>...), and RE2's scoped inline case-insensitivity toggle (?i)/(?i:...), which JS has no equivalent for — approximated by making the whole pattern case-insensitive instead of just the scoped portion). That's a real, if small, parity gap against the actual gitleaks binary, so auto prefers the binary when it's available and treats local as the (very close, but not byte-for-byte identical) fallback.

RE2 also guarantees linear-time matching by construction; JS's backtracking regex engine doesn't. Since the vendored ruleset was written for RE2, local caps scanned lines at 10,000 characters (real secrets are always far shorter) to bound worst-case regex cost on adversarial input — this is checked, not theoretical (see test/localDetect.test.ts), and skipped lines are reported to stderr rather than silently dropped.

How it works

  • Retroactive clean: scans a session file with the selected engine, groups findings by line, and replaces only the exact matched secret substring with [REDACTED:<rule-id>] — line count and per-line JSON validity are verified before and after every write. If a redaction would corrupt a line's JSON, cc-scrub refuses to write anything and tells you which line.
  • Live hook: on PostToolUse for Read/Bash/Grep/Glob, scans the tool's output with the same auto engine selection and, if it finds anything, replaces the output via the hook's updatedToolOutput field before Claude ever sees it.

Limitations

  • local engine gaps vs. the real gitleaks binary: line-by-line matching only (no multi-line secrets, e.g. PEM key blocks spanning several lines), and the regex-dialect approximations noted above. See "Detection engines."
  • Doesn't scan settings.json. Only session transcripts are covered. Secrets embedded in your Bash permission allowlist or other config are out of scope.
  • Structured tool output is flattened. If a tool's response is a structured object rather than a plain string, the live hook normalizes it to a JSON string before scanning/redacting — Claude receives a redacted string instead of the original shape.
  • Already-sent data can't be recalled. This is local cleanup only. If a secret was already sent to a model provider's API, cc-scrub cannot undo that — rotate the credential.

Roadmap

Keeping vendor/gitleaks.toml in sync with upstream gitleaks releases is currently a manual re-pin (bump the version in the download step and re-verify against test/localDetect.test.ts) — automating that check is a natural next step. Closing the remaining regex-dialect gaps (proper scoped case-insensitivity, multi-line matching) would bring local to full parity with the binary, but isn't blocking anything today since auto already prefers the binary whenever it's present.

Development

npm install
npm run build   # tsc -> dist/
npm test        # tsx test/*.test.ts — degrades gracefully if gitleaks isn't installed

License

MIT