Skip to main content

Command Palette

Search for a command to run...

How to redact JSON logs without losing debugging context

A practical checklist for removing secrets, preserving useful fields, and validating structured logs before sharing them with support or AI.

Updated
•6 min read•View as Markdown

A support engineer asks for the failing request's JSON log. You find one record with a timestamp, a status code, and a useful error message. Unfortunately, it also contains an access token, an email address, and a private account ID.

Deleting the whole record protects the data but removes the evidence. Replacing every value with REDACTED leaves valid-looking JSON that may be useless for debugging.

The goal is a smaller, reviewed copy that explains the failure without exposing credentials or unnecessary personal information. Here is a workflow for that handoff.

1. Decide what the recipient actually needs

Start with the question you want answered. For a timeout, the useful fields might be the event name, elapsed time, retry count, status code, and a short sequence of related events. A billing issue may require a different subset.

Keep only the smallest relevant time window. Do not send an entire day's logs just because the export button makes it convenient.

Even seemingly harmless fields deserve context: an exact timestamp, a rare route, and a location can identify a person when combined. Keep the precision necessary for diagnosis, not every detail available.

2. Remove credentials before cosmetic identifiers

Inspect authorization headers, cookies, passwords, API keys, session values, connection strings, and signed links first. A private ID can disclose information; an active token can also grant access.

OWASP's Logging Cheat Sheet identifies access tokens, passwords, and other primary secrets as data that usually should not be recorded directly. Cleaning an export is useful, but preventing unnecessary secret logging at the source is a better long-term fix.

If a real credential has already been shared, removing it from a later copy does not undo the exposure. Follow your organization's incident process and rotate or revoke it where appropriate.

3. Inspect nested objects, arrays, and embedded text

Do not stop at a top-level token field. Sensitive values may appear in:

  • Request and response bodies inside nested objects.
  • Array elements containing customer records.
  • URL query parameters or path segments.
  • Error messages and stack traces.
  • A JSON object serialized inside a string field.

A field named message is not automatically safe. Nor does renaming a secret field make its value safe to share. Review both names and contents, including application-specific identifiers a generic scanner may not recognize.

4. Preserve useful types and explain your substitutions

JSON distinguishes strings, numbers, booleans, null, objects, and arrays. Substituting a string for a numeric field may produce valid JSON while breaking the recipient's schema or analysis script.

For sensitive strings, a quoted placeholder is often sufficient. For a private numeric identifier, decide whether to omit the field, use an allowed null, or construct a documented synthetic number that satisfies the expected schema. Do not silently turn 123 into "[ID_REMOVED]" if the consumer expects a number.

Here is a synthetic record. None of the example values are real credentials or customer data:

{
  "timestamp": "2026-10-03T09:20:00Z",
  "level": "error",
  "event": "checkout.request_failed",
  "requestId": "req_demo_001",
  "status": 504,
  "durationMs": 12500,
  "user": {
    "email": "demo-user@example.com",
    "accountId": "account_demo_42"
  },
  "request": {
    "method": "POST",
    "path": "/api/checkout",
    "headers": {
      "Authorization": "Bearer SYNTHETIC_TOKEN_NOT_VALID"
    }
  },
  "error": {
    "code": "UPSTREAM_TIMEOUT",
    "message": "Payment gateway did not respond before the deadline"
  }
}

For a handoff focused on the timeout, a manually reviewed copy could be:

{
  "timestamp": "2026-10-03T09:20:00Z",
  "level": "error",
  "event": "checkout.request_failed",
  "requestId": "request_A",
  "status": 504,
  "durationMs": 12500,
  "user": {
    "email": "[EMAIL_REMOVED]",
    "accountId": "account_A"
  },
  "request": {
    "method": "POST",
    "path": "/api/checkout",
    "headers": {
      "Authorization": "[CREDENTIAL_REMOVED]"
    }
  },
  "error": {
    "code": "UPSTREAM_TIMEOUT",
    "message": "Payment gateway did not respond before the deadline"
  }
}

The numeric status and duration remain numbers. The sensitive strings are replaced. This example keeps an exact timestamp because it is synthetic; real exports require a separate decision about timestamp precision and sharing policy.

5. Keep relationships only when they are needed

When two events belong to the same request, using request_A in both can preserve that relationship without sharing the original ID. Use a different synthetic label for a different request.

This is a deliberate mapping, not a guarantee offered by every redaction tool. Some tools number each match independently, so two occurrences of the same input may receive different placeholders. Check the output if correlation matters.

Do not include the mapping back to real IDs in the shared file. Consistent labels also do not guarantee anonymity: surrounding event details may still identify a person or organization.

6. Parse the copy and review it again

Keep the original unchanged in its approved location. Validate only the sanitized copy, using a local parser rather than uploading private logs to an unfamiliar online validator.

For a single JSON document, this command checks syntax with Python:

python -m json.tool sanitized.json

That checks JSON syntax, not your application's schema, privacy, or semantic correctness. If the export is JSON Lines, parse each non-empty line as a separate JSON document instead of treating the whole file as one object.

Then inspect the rendered or parsed result: are the important fields still present, do expected types remain intact, and can the recipient understand what changed? Search again for leftover credentials, internal domains, private paths, and identifying free text.

A local review aid

We build TraceSafe, a browser-local tool for reviewing and redacting diagnostic text, including JSON logs. You can start with the sample before using your own files, review detected findings, and export a sanitized copy.

Treat the scan as an aid, not a certification. Pattern matching can miss custom secrets or flag harmless values. TraceSafe's text replacement does not automatically enforce JSON schemas or stable identifier mappings, so parsing and human review remain part of the workflow.

For other diagnostic formats, see our HAR sharing guide and cURL secret checklist.

Before you send

  • Share the smallest useful excerpt.
  • Remove active credentials and unnecessary personal data.
  • Check nested fields and embedded strings.
  • Preserve required types and useful relationships deliberately.
  • Parse the sanitized copy and validate the expected schema.
  • Review remaining context and use the recipient's approved sharing channel.

Which JSON log field has surprised you most during a pre-sharing review?

Disclosure: This article was prepared with AI assistance and reviewed against the linked references and TraceSafe's current implementation. All log examples are synthetic. The publisher is affiliated with TraceSafe.