Detect and redact secrets in text — API keys, tokens, credentials
91
90%
Does it follow best practices?
Impact
100%
1.33xAverage score across 2 eval scenarios
Passed
No known issues
When the user asks you to share, summarise, or paste any block of text — logs, code, env files, terminal output, error messages, config files, network requests — first scan it for secrets and replace them before producing your output.
Treat any of these as a secret:
ghp_, gho_, ghu_, ghs_, github_pat_glpat-xoxb-, xoxp-, xapp-, xoxe.xoxb-sk-, sk-ant-sk_live_, sk_test_, rk_live_, whsec_AIza (39 chars total)npm_ (40 chars)cfat-, cfsk-SG.AC followed by 32 hex chars (account SID is also sensitive in combination with the token)., where the first segment decodes to JSON containing algAKIA[0-9A-Z]{16} access key IDs and the 40-character secret access keys that accompany them; treat session tokens prefixed ASIA the same way"type": "service_account" and a "private_key" field — redact the whole block, not just the key fieldAuthorization: Bearer … — redact the token portion, keep the Bearer prefixAuthorization: Basic <base64> — redact the base64 segmentpostgres://user:password@host/db, mongodb+srv://…, mysql://…, redis://…, amqp://… — replace the password component, keep the rest-----BEGIN … PRIVATE KEY----- and -----END … PRIVATE KEY----- (RSA, EC, OPENSSH, PGP)signing_secret, webhook_secret, hmac_key, signaturesecret, token, key, password, credential, auth, api_key, access_token, refresh_tokenDon't redact: UUIDs, git commit SHAs, public URLs, hashes of public artefacts, well-known constants (zero-vectors, all-ones), public SSH host keys / fingerprints already published in DNS or on the host's website, or strings the user explicitly says are non-sensitive.
A short or low-entropy value that wouldn't normally trigger redaction should still be redacted when the surrounding context suggests it's a credential:
password, passwd, pwd, secret, token, key, apikey, credential, auth (case-insensitive)= in a .env / .envrc / .secrets file, or under a secrets: / credentials: YAML keyAuthorization, X-API-Key, X-Auth-Token, Cookie (when the cookie is named session, auth, jwt, token)Set-Cookie header for a session-shaped cookietoken, access_token, api_key, signature, sigWhen in doubt in these contexts, redact.
Replace the secret value with a placeholder that preserves enough shape to be obviously a redaction without leaking the original:
[REDACTED]ghp_AbCd[REDACTED], sk-Pq3M[REDACTED]postgres://user:[REDACTED]@host/db-----BEGIN … PRIVATE KEY-----\n[REDACTED]\n-----END … PRIVATE KEY-----Always redact in-place — don't reorder, summarise, or otherwise mutate the surrounding text.
If you scan and find nothing, output the original text unchanged. Don't add a "no secrets found" preamble — that pollutes pipeable output. The absence of redactions is the signal.
If a string looks suspicious but you can't classify it confidently (e.g., a 40-char hex string with no surrounding context), redact it and add a single trailing comment line: # 1 ambiguous string redacted at line N. Surface ambiguity rather than hide it.
When the secret appears inside a fenced code block or otherwise machine-readable region, redact in-place — don't rewrap, don't drop or add backticks, don't add prose annotations inside the block. When the secret appears in surrounding prose ("the API key is sk-abc..."), redact the value but keep the prose readable; an inline note like "(redacted)" in parentheses is acceptable here.
GITHUB_TOKEN=[REDACTED] is right; [REDACTED]=[REDACTED] is not.[REDACTED] form so the reader can tell they refer to the same secret.Input:
DATABASE_URL=postgres://app:hunter2@db.internal:5432/prod
GITHUB_TOKEN=ghp_AbCd1234efghIJKLmnop5678QRSTuvwxYZ0
# user_id is fine to share
USER_ID=018f1c2a-9d4b-7e91-aaaa-bbbbcccc1111Output:
DATABASE_URL=postgres://app:[REDACTED]@db.internal:5432/prod
GITHUB_TOKEN=ghp_AbCd[REDACTED]
# user_id is fine to share
USER_ID=018f1c2a-9d4b-7e91-aaaa-bbbbcccc1111Input:
POST /v1/charges HTTP/1.1
Host: api.stripe.com
Authorization: Bearer sk_live_FAKE_DEMO_NOT_A_REAL_KEY_123
Content-Type: application/x-www-form-urlencoded
Idempotency-Key: 87b2eaba-3f9c-4f2e-8b6e-19c6a2b71b2e
amount=2000¤cy=usdOutput:
POST /v1/charges HTTP/1.1
Host: api.stripe.com
Authorization: Bearer sk_live_FAKE[REDACTED]
Content-Type: application/x-www-form-urlencoded
Idempotency-Key: 87b2eaba-3f9c-4f2e-8b6e-19c6a2b71b2e
amount=2000¤cy=usd(Idempotency key is a UUID — not a secret. Authorization header value is.)
Input:
HTTP/1.1 200 OK
Set-Cookie: session=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcyMDAwMDAwMH0.abc123signature; HttpOnly; Secure; Path=/Output:
HTTP/1.1 200 OK
Set-Cookie: session=[REDACTED]; HttpOnly; Secure; Path=/(Whole JWT redacted as one unit. Cookie attributes preserved.)