Redacts secrets & PII before they leak into an LLM. Local-first. Zero network calls. One command.
You hit a bug. You copy the stack trace, the .env, the failing request, and paste it into ChatGPT or Claude. Buried in there: an AWS key, a database password, a customer's email, a live card number. It's now sitting in a third party's logs — and you can't take it back.
airlock is the checkpoint in between. Pipe text through it (or let it guard your clipboard) and every secret comes out as a typed placeholder — [AWS_ACCESS_KEY], [CONNECTION_STRING], [EMAIL] — so the model still understands the shape of your problem, but the secret never leaves your machine.
$ cat staging.env | airlock
# staging config — pasting this to debug a 500
DATABASE_URL=[CONNECTION_STRING]/prod
AWS_ACCESS_KEY_ID=[AWS_ACCESS_KEY]
AWS_SECRET_ACCESS_KEY=[SECRET]
ANTHROPIC_API_KEY=[ANTHROPIC_KEY]
stripe_key = "[STRIPE_KEY]"
support_email = [EMAIL]
DEBUG = True
MAX_RETRIES = 3
card_on_file = [CREDIT_CARD]
airlock: 7 findings redacted ← summary printed to stderr, so it never
high CONNECTION_STRING post…5432 (line 2) pollutes the piped output
high AWS_ACCESS_KEY AKIA…MPLE (line 3)
medium SECRET wJal…EKEY (line 4)
high ANTHROPIC_KEY sk-a…aaaa (line 5)
high STRIPE_KEY sk_l…5678 (line 6)
low EMAIL jane….com (line 7)
high CREDIT_CARD 4242…4242 (line 10)Notice what didn't get touched: DEBUG = True, MAX_RETRIES = 3. A redactor that mangles your normal config is a redactor you uninstall. Keeping quiet on ordinary code is the whole design (see below).
Install straight from GitHub (not on PyPI yet):
# core CLI — zero dependencies
pip install "git+https://github.com/KernelSpecter/AirLock.git"
# ...or with the live clipboard guard
pip install "airlock[clipboard] @ git+https://github.com/KernelSpecter/AirLock.git"Both put an airlock command on your PATH. Prefer isolation? Swap pip install for pipx install.
Or just clone and run — no install needed:
git clone https://github.com/KernelSpecter/AirLock.git && cd AirLock
python -m airlock.cli --helpRedact a file or stdin — the redacted text goes to stdout, the summary to stderr:
cat error.log | airlock # pipe anything through
airlock config.py .env # scan files
airlock error.log | pbcopy # redact straight into your clipboard (macOS)
airlock error.log | clip # …or on WindowsGuard your clipboard live — anything you copy is scrubbed in place before you can paste it:
airlock --watch
# airlock: watching clipboard — Ctrl-C to stop
# >> redacted 2 (ANTHROPIC_KEY, EMAIL) from clipboardJust audit, don't rewrite:
airlock --report error.log # list findings only
airlock --json error.log # machine-readable, for scripts/CI
airlock --all error.log # also catch phones, IPs, SSNs (noisier)Use it as a guardrail. airlock exits 1 when it finds anything, so it drops straight into a pre-commit hook or CI:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/KernelSpecter/airlock
rev: v0.1.0
hooks:
- id: airlockDetection is specific by default — provider-anchored patterns and real validators, not a grab-bag of loose regexes.
| Category | Detects |
|---|---|
| Cloud & API keys | AWS, GCP, Anthropic, OpenAI, Stripe, Slack, SendGrid, Twilio, Google OAuth, npm |
| Tokens | GitHub PATs (classic + fine-grained), JWTs |
| Credentials | Private keys (BEGIN … PRIVATE KEY), proto://user:pass@host connection strings |
| Generic secrets | API_KEY = "…" style assignments — gated by entropy so password="changeme" is ignored |
| PII | Emails, credit cards (Luhn-validated) |
PII (opt-in --all) |
Phone numbers, IPv4 addresses, US SSNs |
Most secret scanners are unusable because they flag everything. airlock is tuned the other way — specificity over recall for anything on by default:
- Provider-anchored patterns.
AKIA…,ghp_…,sk-ant-…— matched by their real prefixes and lengths, not "any 32-char string." - Luhn-checked cards. A 16-digit number only redacts if it's a mathematically valid card, so order IDs and timestamps stay put.
- Entropy-gated generics. The catch-all
secret = "…"rule only fires when the value is actually high-entropy —changemeandlocalhostdon't trip it. - The noisy stuff is opt-in. Phone numbers, IPs and SSNs generate the most false positives, so they live behind
--all.
airlock makes zero network calls, ever. No telemetry, no cloud, no account. Your secrets are scanned and redacted entirely on your machine — which is rather the point of a tool whose job is to stop data from leaving it. It's a single small pure-Python package you can read top to bottom in a few minutes.
- Scan — every detector runs over the text; validators (Luhn, Shannon entropy) confirm candidate matches.
- Resolve overlaps — when two detectors hit the same span, the higher-severity one wins, so nothing is redacted twice or mislabeled.
- Redact — each finding's span is replaced with a typed, ASCII-safe placeholder. Repeats are numbered (
[EMAIL_1],[EMAIL_2]) so the model can still tell two distinct values apart.
Detectors are plain data. Adding one is a few lines in airlock/detectors.py:
Detector(
kind="linear_key", category="secret", label="LINEAR_KEY", severity="high",
pattern=re.compile(r"\blin_api_[A-Za-z0-9]{40}\b"),
)Add a realistic fake key to POSITIVES and a look-alike to NEGATIVES in the tests, and you're done. PRs adding coverage for more providers are very welcome.
- Config file for custom patterns & allowlists
-
git diffmode (redact only what you're about to commit) - Editor/shell integrations (a pre-paste hook)
- Reversible redaction (restore placeholders locally after the model replies)
Issues and PRs welcome — especially new provider patterns and false-positive reports (paste the text that tripped it). Run the tests before opening a PR:
python -m pytest # or: python tests/run.pyMIT © KernelSpecter