How to Redact Tokens From Stack Traces Before Sharing
Before you share a stack trace, search it for anything that grants access, such as a bearer token, API key, password in a connection string or private key, and replace each value with a placeholder like <redacted>, keeping the surrounding text so the error still makes sense. Do it in an editor or with a script before the text reaches chat, a ticket or an AI assistant. If a real secret has already been shared, revoke it and issue a new one; deleting the message isn't enough.
Where secrets hide in stack traces and logs
A plain stack trace is file names, line numbers and an error message, but secrets get pulled in from around it:
- Error messages that echo their input. An HTTP client error that includes the full request URL also includes any
?api_key=or?token=in it. A connection error your code formats with the connection string includes the password. - Request details. Error pages, debug middleware and error-reporting tools often attach request headers, cookies and query strings, including
Authorizationheaders and session cookies. - Local variables. Some tools print variable values next to each frame, for example pytest with
--showlocals(-l) and error trackers that capture locals. A variable holding a token is printed with everything else. - Configuration and environment dumps. Startup logs or failure handlers that print settings or environment variables expose every secret in them.
- The command you ran. A
curlcommand with-H "Authorization: Bearer ..."or a password on the command line is a secret in your terminal history and in any log that records it.
The OWASP Logging Cheat Sheet lists access tokens, passwords, database connection strings, encryption keys and session identifiers as data that usually shouldn't be recorded in logs at all.
Patterns to search for
| What | What it looks like | Replace with |
|---|---|---|
| Bearer token | Bearer abc123... | Bearer <redacted> |
| JWT | Three dot-separated parts starting with eyJ | <redacted-jwt> |
| AWS access key ID | AKIA or ASIA plus 16 uppercase letters and digits | AKIA<redacted> |
| GitHub token | ghp_, gho_, ghu_, ghs_ or ghr_ plus 36 characters | <redacted-github-token> |
| Slack token | Starts with xox and a letter, then a hyphen | <redacted-slack-token> |
| Password in a URL | scheme://user:password@host | scheme://user:<redacted>@host |
| Key in a query string | ?api_key=..., &token=... | ?api_key=<redacted> |
| Key in JSON or a dict | "password": "..." | "password": "<redacted>" |
| Private key | -----BEGIN ... PRIVATE KEY----- block | <redacted-private-key> |
Keep the key name and the shape of the value. api_key=<redacted> tells the reader a key was present, which can matter for the diagnosis; an empty value looks like a bug.
Patterns miss things: a password in an unusual field, a token in a custom header, an internal hostname you'd rather not share. Read the result once before you paste it.
A small redaction script
This Python script reads text, applies the patterns above and writes the result. It uses only the standard library.
import re
import sys
PATTERNS = [
# "Bearer <token>" in headers or logs
(r"(?i)(bearer\s+)[A-Za-z0-9._~+/=-]+", r"\1<redacted>"),
# JSON Web Tokens
(r"\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*", "<redacted-jwt>"),
# AWS access key IDs (long-term AKIA, temporary ASIA)
(r"\b(AKIA|ASIA)[0-9A-Z]{16}\b", r"\1<redacted>"),
# GitHub tokens
(r"\bgh[pousr]_[A-Za-z0-9]{36,}\b", "<redacted-github-token>"),
# Slack tokens
(r"\bxox[abposr]-[A-Za-z0-9-]+", "<redacted-slack-token>"),
# Password in a connection URL: scheme://user:password@host
(r"(://[^:/\s@]+:)[^\s/]+@", r"\1<redacted>@"),
# Secrets in query strings: ?api_key=... &token=...
(r"(?i)([?&](?:api_?key|access_token|token|key|secret|password)=)[^&\s]+", r"\1<redacted>"),
# Secrets in JSON or dict output: "password": "..."
(r"(?i)([\"'](?:api_?key|token|secret|password)[\"']\s*:\s*[\"'])[^\"']+", r"\1<redacted>"),
# Private key blocks
(r"-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----", "<redacted-private-key>"),
]
text = sys.stdin.read()
for pattern, replacement in PATTERNS:
text = re.sub(pattern, replacement, text)
sys.stdout.write(text)
Save it as redact.py, then run it on a file. In Command Prompt or Git Bash (in WSL, use python3):
python -X utf8 redact.py < trace.txt > trace-redacted.txt
Or redact whatever is on the clipboard in PowerShell and put the result back:
Get-Clipboard -Raw | python -X utf8 redact.py | Set-Clipboard
The clipboard version is convenient for plain ASCII logs. If the text contains accented or non-Latin characters, use the file version, because PowerShell's pipeline to and from external programs depends on console encoding settings.
For scanning whole repositories or CI output, use a maintained scanner with a larger rule set, such as gitleaks or Yelp's detect-secrets, rather than growing this script.
Example: before and after
Before:
ConnectionError: could not connect to postgres://app_user:s3cretP@ss@db-prod-01:5432/app
GET https://api.example.com/v1/invoices?api_key=abc123SECRETvalue&page=2 returned 401
Headers: {"Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.c2lnbmF0dXJl"}
After:
ConnectionError: could not connect to postgres://app_user:<redacted>@db-prod-01:5432/app
GET https://api.example.com/v1/invoices?api_key=<redacted>&page=2 returned 401
Headers: {"Authorization": "Bearer <redacted>"}
The error, the host, the endpoint and the status code are all still there for whoever is debugging.
Why redact before the clipboard, not after
Once a secret is copied, it can end up in more places than the message you paste it into: Windows clipboard history if it's on, another device if clipboard sync is on, and any clipboard manager you run. Opening the raw trace in an editor, redacting there and copying only the clean version keeps the original out of all of them. If you do copy a secret, clear clipboard history (Win+V, then Clear all) once you're done; is an API key on the clipboard a security incident? covers the rest of the cleanup.
Online tools are another route out. Pasting a real token into a web-based JWT decoder or regex tester sends it to someone else's page; see whether it's safe to paste tokens into online debuggers.
Code review gives you a natural checkpoint: if you batch review comments in a pending review, reread any pasted logs for secrets before you click Submit review.
If a secret has already been shared
- Revoke or rotate it with the service that issued it. This is the step that actually ends the exposure.
- Remove or edit the message, comment or issue, so the value doesn't stay visible to new readers.
- Check where else it went, such as notification emails, linked tickets, CI logs and AI chat history.
- Fix the source, so the next trace doesn't print it: configure your logger or error tracker to mask known fields, and stop formatting connection strings into error messages.
On GitHub, secret scanning checks public repositories, including issue and pull request comments. For supported providers' tokens, GitHub notifies the provider, which can revoke the credential. Treat that as a safety net, not a reason to skip rotation.
FAQ
Is a stack trace without secrets safe to share publicly?
It still reveals file paths, internal hostnames, library versions and sometimes user data. For public issues, trim it to the frames that matter, as described in how to copy an error log without the noise, and replace internal names you don't want to publish.
Should I redact request IDs and user IDs?
Request IDs usually help the person debugging and don't grant access, so keep them for internal tickets. Remove personal data such as email addresses or names, especially anywhere public.
Can I just blur a screenshot of the log instead?
Share text instead. Text is searchable and copyable for the person helping you, and blurring or cropping can miss part of a value.
Related reading
- How to Copy an Error Log Without the Noise
- Copied an API Key or .env File? What to Do Next
- Is It Safe to Paste Tokens Into Online Regex and JWT Debuggers?
- Clipboard Tips for Developers on Windows
Sources
- Logging Cheat Sheet (OWASP) — data to exclude from logs.
- Secrets Management Cheat Sheet (OWASP) — handling and rotating leaked secrets.
- IAM identifiers (AWS docs) — AKIA and ASIA access key prefixes.
- Behind GitHub's new authentication token formats (GitHub Blog) — ghp_, gho_, ghu_, ghs_ and ghr_ prefixes.
- About secret scanning (GitHub Docs) — scanning of public repositories, issues and pull requests, and provider notification.
- pytest command-line reference — the --showlocals option.
- gitleaks (GitHub) and detect-secrets (GitHub) — maintained secret scanners.
- Get-Clipboard (Microsoft Learn) and Set-Clipboard (Microsoft Learn) — reading and setting the clipboard in PowerShell.
Deepender Yadav created Edge Drop and builds and tests it, from the edge-hover shelf to each release. A B.Tech Computer Science Engineering student, Deepender writes the Edge Drop guides, comparisons and developer posts, and checks product details against the app's source code.
GitHub · LinkedInCopy. Stack. Drop.
Transform your clipboard into an interactive edge shelf. Stack, pin, and drag assets into any app with zero friction.
Download for Windows Get from Microsoft Store
How to Install Guide · First 10 Minutes Guide · Drag & Drop Guide · Edge Drop vs Win+V · Support
Free · Lightweight · Privacy First