Methodology & privacy

How LeakCheck works

LeakCheck scans the text you paste for things that look like API keys, tokens, and private keys — and it does the whole job inside your browser. This page explains exactly how that detection works, what it can and can’t see, and what to do the moment you find a real leak.

The privacy guarantee: nothing leaves your browser

This is the part that matters most, so we’ll be blunt about it: LeakCheck has no backend. When you paste code, a .env file, or config into the scanner, every byte stays on your machine. The scanning happens in JavaScript, locally, in the same tab you’re looking at.

Concretely, that means:

  • No network requests with your content. Your code and secrets are never uploaded, POSTed, beaconed, or sent to any server — ours or anyone else’s.
  • No logging or storage. We don’t keep what you paste. It isn’t written to a database, a log file, local storage, or analytics. Close or reload the tab and it’s gone.
  • It works offline. Load the page once, disconnect from the internet, and the scanner still runs. That’s the simplest proof there’s nothing to upload to.
Verify it yourself. Open your browser’s developer tools, switch to the Network tab, and run a scan. You won’t see a request carrying your input — because there isn’t one. The only network activity on the whole site is loading the page, its stylesheet, the script, and the web fonts.

We built it this way on purpose. A tool that asks you to paste your secrets somewhere, and then ships those secrets to a server, is a worse problem than the one it claims to solve. LeakCheck never puts you in that position.

What we detect

LeakCheck ships with a library of named patterns for common providers, plus a general high-entropy catch-all for credentials that don’t match a known format. Severity reflects how dangerous an exposure typically is — a live cloud or payment key is a Fail, a lower-blast-radius or context-dependent token is a Warn, and informational matches are Pass.

Provider / typeExample formatSeverity
AWS access key IDAKIA0123456789ABCDEFFail
AWS secret access key40-char base64-ish secretFail
Stripe live secret keysk_live_…Fail
Private key block (RSA/EC/PGP)-----BEGIN … PRIVATE KEY-----Fail
GitHub tokenghp_… / github_pat_…Fail
OpenAI / Anthropic API keysk-… / sk-ant-…Fail
Google API keyAIza…Warn
Slack tokenxoxb-… / xoxp-…Warn
Stripe test secret keysk_test_…Warn
JSON Web Token (JWT)eyJ….eyJ….<sig>Warn
Generic SECRET= / PASSWORD= assignmentAPI_SECRET="…"Warn
High-entropy string (unmatched)random 32+ char blobPass

The exact pattern set evolves; treat this table as representative, not exhaustive. Severities are defaults and reflect typical blast radius, not your specific setup.

How detection works

Detection runs in two complementary passes:

1. Named regular-expression patterns

Most cloud providers give their credentials a recognizable shape — a fixed prefix, a known length, a specific alphabet. LeakCheck carries a curated set of regular expressions for those formats (for example, AKIA followed by 16 base-32 characters for AWS, or sk_live_ for Stripe). When the text matches a named pattern, the finding is precise: we can tell you which provider it belongs to and assign a meaningful severity.

2. Entropy heuristics

Plenty of secrets don’t follow a public format — bespoke session tokens, hand-rolled API keys, raw passwords. For those, LeakCheck measures Shannon entropy: a score of how random and unpredictable a string is. Ordinary English words and code identifiers have low entropy; a genuinely random 32-character credential has high entropy. Long, high-entropy strings — especially ones sitting next to a tell like key, token, secret, or = — get surfaced even when no named pattern matches.

The two passes back each other up: named patterns give you accuracy on the providers we know, and entropy gives you coverage on the ones we don’t.

How matches are masked

When LeakCheck shows you a finding, it does not print the full secret back onto the screen. Each match is masked — typically the leading few characters of the prefix are shown for identification and the rest is replaced with dots (for example, sk_live_4eC•••••••••••••••••••). This keeps the results readable and identifiable while reducing the chance of shoulder-surfing, an accidental screenshot, or a copied screen-share leaking the very thing you’re trying to protect. The unmasked value never leaves your browser regardless, but masking means it isn’t casually visible even to you.

This is heuristic detection — not a security audit

Important: LeakCheck is a fast heuristic scanner, not a security guarantee, certification, or audit. A clean result does not mean your code is secure, and a flagged result does not always mean a real secret.

Like every pattern-based scanner, LeakCheck can produce both kinds of error:

  • False negatives. Secrets in formats we don’t recognize, encoded or split across lines, or below the entropy threshold can slip past unflagged.
  • False positives. Random-looking but harmless strings — hashes, UUIDs, test fixtures, example keys — can be flagged when they aren’t real credentials.

Use LeakCheck as a quick first pass before you commit or share code, not as the final word on whether your project is safe. A real audit considers your architecture, dependencies, access controls, and threat model — none of which a text scanner can see. If you need that level of assurance, talk to Copper Bay Labs.

I found a leaked key — now what?

If a real credential has been exposed, assume the worst and act fast. Treat the order below as a checklist:

  1. Rotate it immediately. Go to the provider’s dashboard and revoke or regenerate the key right now. Rotation is the only action that actually stops abuse — deleting it from your code does not.
  2. Remove it from your code. Take the hard-coded value out of every source file, config, and notebook where it appears.
  3. Move it to an environment variable or secret manager. Load secrets at runtime from .env (git-ignored) for local work, and from a real secret manager — AWS Secrets Manager, GCP Secret Manager, Vault, GitHub Actions secrets, your platform’s vault — for anything deployed.
  4. Scrub it from git history. A removed-then-committed secret still lives in every prior commit. Rewrite history with git filter-repo or BFG Repo-Cleaner, then force-push and have collaborators re-clone. Remember any forks and PRs may still carry it.
  5. Treat the old key as compromised forever. Once a secret has been public — even briefly, even in a private repo that was shared — assume it’s in someone’s scrape. The exposed value can never be trusted again. The rotated key is your real key; the old one is dead.
Order matters. Rotate first. Cleaning git history is important for hygiene, but it does nothing to protect a key that’s already been copied. Revoking access is what actually closes the door.

On the roadmap

Pre-commit & CI ruleset pack. The best place to catch a secret is before it’s ever committed. We’re packaging LeakCheck’s patterns into a drop-in ruleset for pre-commit hooks and CI pipelines, so the same detection that runs here can block secrets at the door of your repo — automatically, on every push. Stay tuned.

Scan your code now