How to safely share logs and API keys in a bug ticket
A bug ticket is a public artifact inside your company, and often beyond it. The log you paste to reproduce an issue gets indexed by the ticket tracker, copied into chat, screenshotted into a thread, and quoted in a postmortem six months later. Whatever sensitive value was in that log now lives in all of those places. Most people never go back to scrub it.
The fix is not "be careful." Careful fails under deadline pressure. The fix is a consistent redaction step that runs before anything leaves your machine.
What actually leaks in a log
Stack traces and request dumps are full of values that look harmless until someone reads them carefully. The common offenders:
- Bearer tokens and API keys. Anything in an
Authorizationheader, a query string like?api_key=..., or a config dump. These are live credentials. A leaked token is a working login until it is rotated. - Session cookies and CSRF tokens. A copied
Cookie:header can let someone replay a logged in session. - Emails and user identifiers. Customer emails, account IDs, and phone numbers in a log are a privacy incident, not just a debugging detail.
- Internal hostnames and IPs.
db-prod-3.internal,10.0.x.xranges, and S3 bucket names hand an attacker a map of your infrastructure. - JWTs. A JSON Web Token in a log is not encrypted, only encoded. Anyone can paste it into a decoder and read the claims, including user IDs, roles, and expiry. If you need to inspect one yourself, do it locally with a JWT Decoder rather than a public site that may log what you paste.
- Base64 blobs. A long base64 string in a payload is not obfuscation. It decodes back to plaintext in one step, so credentials hidden as base64 are still credentials. You can confirm what a blob contains with a Base64 decoder before deciding whether it is safe to share.
Why attackers care about "just a log"
The value to an attacker is not always the obvious token. Logs leak the shape of your system. An internal hostname plus a version string in a stack trace tells someone which CVEs might apply. An email format reveals your account naming. A token with a long expiry is a quiet way in that survives a password reset. Credential leaks through tickets, repos, and chat are one of the most common initial access vectors in breach reports, precisely because the values sit in plain sight in places nobody treats as sensitive.
Assume any log that leaves your laptop is permanent and copyable. Redact on that assumption.
Redact consistently, not just heavily
The instinct is to mash every secret into xxxxx. That destroys the log for debugging. If three different tokens all become xxxxx, you can no longer tell whether the same caller made all three requests or three different callers did. The bug might be exactly that distinction.
Consistent masking means the same input value always maps to the same placeholder, and different values map to different placeholders:
token= key_9f3a2b1c...becomestoken=<TOKEN_1>everywhere it appears- a second distinct token becomes
<TOKEN_2> alice@corp.combecomes<EMAIL_1>in every line
Now the reader can still follow which request belongs to which session, trace a single user across the log, and see that two events share a credential, all without ever seeing the real values. The structure that makes a log useful survives. The sensitive content does not.
This is the core idea behind a string obfuscator: stable, reversible-looking replacement that you control. You decide which patterns to mask, and identical values collapse to identical tags so relationships stay intact.
The redaction has to happen locally
Here is the trap. You find a log full of secrets, so you paste it into the first "log redaction" or "remove secrets" website you find. You have now uploaded every secret in that log to a stranger's server in order to hide it. The act of redacting became the leak.
Redaction is only meaningful if the sensitive text never travels. Do the masking locally, before you share, rather than trusting a remote service with the raw input.
So before a log, trace, or config snippet goes into a ticket, strip the secrets by hand: replace each token, key, email, and internal hostname with a clear placeholder like <API_KEY>, and reuse the same placeholder for the same value so the log still reads sensibly for whoever picks up the bug. If something must stay secret rather than be removed, encrypt it locally with the Encrypt / Decrypt Text tool, which runs entirely in your browser.
A simple workflow
- Copy the raw log into the obfuscator locally.
- Mask tokens, keys, emails, cookies, and internal hostnames, letting identical values share a tag.
- Read the masked output once to confirm no live secret slipped through.
- Paste the masked version into the ticket. Keep the raw log only on your machine if you still need it.
- If a real credential did appear anywhere it should not, rotate it. Redacting the log does not un-leak a token that was already pasted unmasked.
The goal is a habit, not heroics. Make the masking step as automatic as formatting JSON or decoding a token, and the log you share stays useful while the secrets stay yours.