ZeroTool Workbench
Secret Redactor
Redact API keys, JWTs, private keys and database passwords from logs and .env files before sharing with ChatGPT or Claude. Restore them after. No upload.
How to use
- Paste the log, stack trace,
.envfile or config you want help with into box ①. Detection runs as you type. - Check the category toggles and open Findings to see what was matched. Turn a category off if it flags something that is not a secret.
- Copy the redacted text from box ② and paste it into ChatGPT, Claude or any other assistant.
- Paste the assistant’s answer into box ③. Every placeholder it kept is swapped back to the real value, ready to copy into your terminal or editor.
Keep box ① as it is until you have restored the reply. The mapping from placeholder to value is rebuilt from that text every time it changes, and nothing else remembers it.
What gets redacted
| Category | Examples | What stays visible |
|---|---|---|
| AI provider keys | sk-ant-…, sk-proj-…, hf_…, other sk- keys (DeepSeek, OpenRouter, Moonshot) | The variable name |
| Cloud & SaaS tokens | AKIA… and the matching AWS secret, AIza…, ghp_…, github_pat_…, glpat-…, xoxb-…, Slack webhook URLs, sk_live_…, whsec_…, SendGrid, npm, PyPI, Telegram bot tokens | The variable name; Stripe pk_ publishable keys are not matched by the Stripe rule |
| JWT & auth headers | eyJ….eyJ….…, Authorization: Basic …, Bearer … | The header name and scheme |
| Private keys | PEM blocks from -----BEGIN … PRIVATE KEY----- to the matching END line (RSA, EC, OpenSSH, PGP, encrypted) | Nothing; the whole block becomes one placeholder |
| Passwords & connection strings | postgres://app:…@db, DB_PASSWORD=…, client_secret: …, ?api_key=… | User name, host, port and database name |
| High-entropy strings | Unlabelled random strings of 32+ characters | Everything around them |
A value assigned to a name only counts when the name ends in the keyword, so max_tokens: 1024 and token_count=12 are left alone. Environment references such as ${DB_PASS}, template placeholders like <your-key>, masked values like **** and literals such as true or null are skipped as well.
How the high-entropy check works
Anything that looks like a run of base64 or base64url characters at least 32 characters long is a candidate. It is redacted only when it contains an uppercase letter, a lowercase letter and a digit, and when its Shannon entropy reaches 4.2 bits per character. Random base64 of that length averages about 4.56 bits.
The mixed-case requirement is what keeps CI logs readable: git commit SHAs, MD5 and SHA-256 digests, Docker image digests and UUIDs are all hex or single-case, so none of them qualify. Lockfile integrity values (sha512-…), data: URIs, file paths and the bodies of certificates and public keys are excluded explicitly, because they are public by design.
The trade-off is deliberate. A bare 32-character hex token with no variable name next to it is not caught by this check. Give it a name (TWILIO_AUTH_TOKEN=…) and the password rule catches it.
Placeholder rules
- Placeholders look like
[LABEL_n]:[OPENAI_KEY_1],[URL_PASSWORD_1],[SECRET_2]. The label tells the assistant what kind of value it is without revealing it, so an answer such as “rotate[AWS_ACCESS_KEY_1]” still makes sense. - The same value always gets the same placeholder, even when it appears twenty times or two rules found it.
- Numbering is per label and skips any placeholder that already appears in your text, so a pasted
[SECRET_1]never collides with a generated one. - Running the tool on text it has already redacted changes nothing.
- Restore accepts
[OPENAI_KEY_1],\[OPENAI_KEY_1\],[openai_key_1],[ OPENAI_KEY_1 ]and placeholders inside code spans. It does not acceptOPENAI_KEY_1without brackets, because that is indistinguishable from an environment variable name. - Placeholders in the reply that are not in the mapping, for example one the assistant invented, are left unchanged and listed under the restore box.
Limits
| Not done here | Use instead |
|---|---|
| Scanning files, folders or git history | gitleaks git / gitleaks dir or trufflehog on your machine |
| Personal data: emails, names, phone numbers, IP addresses, hostnames | Edit by hand. Hostnames in connection strings stay visible on purpose so the assistant can still reason about your config. |
| Un-redacting one false positive | Turn off its category, or edit the copied text |
| Checking whether a key is still live | Nothing in this page does that, because it would mean sending the key to the provider |
| Restoring placeholders written without brackets | Ask the assistant to keep placeholders exactly as written |
Input is limited to 1,000,000 characters. Secrets split across a line break are not detected, since every rule except the private key rule stops at the end of a line.
FAQ
Why not just ask the AI to remove the secrets?
Because the request itself is the leak: the key reaches the provider's servers, logs and possibly training data before any model can remove it. Detection here is a fixed set of regular expressions plus an entropy check that runs in your browser, so the only text that ever leaves your machine is the version you copy after redaction.
Is anything uploaded or saved?
No. The page makes no network request with your text, and nothing is written to localStorage, sessionStorage, cookies or the URL. The placeholder mapping exists only in the page's memory: Clear, Ctrl/Cmd+L, reloading or closing the tab discards it. JavaScript cannot overwrite a string in place, so the browser frees the memory on its next garbage collection.
What does it detect?
Keys for Anthropic, OpenAI and OpenAI-compatible sk- providers, Hugging Face, AWS, Google, GitHub, GitLab, Slack, Stripe, SendGrid, npm, PyPI and Telegram; JWTs; Bearer and Basic authorization headers; PEM private key blocks; passwords inside connection strings such as postgres://user:pass@host; values assigned to names ending in password, secret, token or api_key; and long random-looking strings with at least 4.2 bits of entropy per character. It finds credentials only. Emails, hostnames and IP addresses stay as they are.
How does restoring work, and what if the AI changes a placeholder?
Each distinct secret becomes a numbered placeholder such as [OPENAI_KEY_1], and the same value always gets the same placeholder. Paste the AI's reply into the restore box and every placeholder is swapped back. Case changes, extra spaces inside the brackets and Markdown-escaped brackets are accepted. A placeholder the AI rewrote without its brackets is left untouched and the missing ones are counted, so tell the AI to keep placeholders exactly as written.
Why wasn't my secret caught?
Secrets split across two lines, hex-only tokens without a telling variable name, and keys shorter than 32 characters with no recognisable prefix or key name are not detected; hex was excluded so commit SHAs and checksums in CI logs do not drown the real findings. Review the redacted text before sending. For scanning whole repositories and git history, run gitleaks or trufflehog locally.