What to know

  • Known sensitive field names are masked recursively.
  • The original object is preserved and unsupported shapes fail.
  • This is structured field redaction, not complete DLP or permission to share data.
limits
Local bounded fixtures passed; no external model or production benchmark tested. Free text, unknown aliases and inferred identities are not detected; no model or full DLP scan.
duration
20–30 minutes
difficulty
Intermediate
environment
Python 3.12.10; standard library; local synthetic fixtures
verified at
2026-10-16
prerequisites
Python 3.12; synthetic JSON-like data only; a reviewed field-name policy.

Choose a narrow, honest protection goal

Before sending a structured support record to an assistant, a team may need to remove specific fields such as email or a token. This workflow demonstrates that named-field transformation on synthetic data. It does not decide whether the organization is allowed to share the remaining record. The output preserves useful structure while replacing selected values. Calling it complete anonymization would be inaccurate: an unmasked note, a rare event or an unfamiliar field name can still reveal sensitive information.

Specify the allowed structure

The redact function accepts JSON-like dictionaries, lists and ordinary finite scalar values. It creates a new object rather than modifying the original. Sensitive names are compared case-insensitively against a small explicit set. Nested objects and lists receive the same rule, while depth, collection sizes and string length are bounded. Those limits keep this demonstration predictable. A real application should define which fields are permitted at all, rather than assuming that masking a few familiar names makes every other property appropriate for disclosure.

Run the synthetic example

Save redact_fields.py and run it with Python 3.12. Its example includes an invalid-domain email and a deliberately synthetic token. The printed output contains redaction markers and the retained ticket status. test_workflows.py checks nested masking, case-insensitive keys, preservation of the original object, excessive nesting and unsupported values. Another test deliberately retains a sensitive-looking sentence under note. That passing test documents the boundary: this implementation never scans or understands arbitrary prose.

Use an allowlist when the downstream task permits it

A destination often needs only a ticket category and processing status. Selecting those permitted fields can be safer and clearer than forwarding a large record after a blacklist transformation. The choice depends on the task and the original data contract. OWASP’s secrets-management material supports deliberate handling of secret access and lifecycle; it does not certify this function as a data-loss prevention product. Keep actual credentials out of model prompts even if a nearby preprocessing step is supposed to remove them.

Fail without repeating the source data

An unsupported object, non-finite number or excessive depth raises ValueError. A caller should report a field-policy failure without logging the original record. Preserve the source only in its existing protected system. Do not paste a failed payload into a public issue or chat to ask why redaction failed. If an unfamiliar key needs handling, review the policy and add a synthetic fixture first. A one-off exception that bypasses the transformation can defeat the purpose of the whole handoff.

Review what remains visible

Inspect a representative transformed record for the exact downstream task. Dates, account references and combinations of otherwise ordinary fields can remain identifying even when names are absent. A reviewer should decide whether the recipient needs each retained field. For a future model integration, also examine provider retention, purpose and organizational permissions separately. None of those questions is answered by the fact that this local function returned a dictionary successfully. The content and the authority to disclose it remain separate decisions.

Extend with clear test evidence

Use a versioned field policy and synthetic regression cases for aliases that the application actually receives. If free-text analysis is added, label it as another imperfect control with its own tests and failure handling. Do not change the existing claim into guaranteed anonymization. The useful result of this workflow is a reproducible, limited transformation whose omissions are visible. That makes it easier for an engineer or privacy owner to judge whether the output belongs in a particular handoff.

Runnable Python fixture

"""Redact named structured fields; deliberately not a complete DLP system."""
import math

SENSITIVE = frozenset({"email", "password", "token", "api_key", "recovery_code"})

def redact(value, depth=0):
    if depth > 10:
        raise ValueError("nesting bound exceeded")
    if type(value) is dict:
        if len(value) > 100 or any(type(key) is not str for key in value):
            raise ValueError("invalid object")
        return {key: "[redacted]" if key.casefold() in SENSITIVE else redact(item, depth + 1)
                for key, item in value.items()}
    if type(value) is list:
        if len(value) > 100:
            raise ValueError("list bound exceeded")
        return [redact(item, depth + 1) for item in value]
    if value is None or type(value) in (bool, int):
        return value
    if type(value) is float and math.isfinite(value):
        return value
    if type(value) is str and len(value) <= 5000:
        return value
    raise ValueError("unsupported scalar")

if __name__ == "__main__":
    import json
    fixture = {"ticket": "fixture-1", "email": "person@example.invalid",
               "events": [{"token": "synthetic-value", "status": "pending"}]}
    print(json.dumps(redact(fixture), indent=2))

Verification and references

The redactor passed four fixture tests on 16 October 2026 using Python 3.12.10, including a test proving that free text stays outside its scope. Run redact_fields.py for the example and test_workflows.py for the complete suite.

Editorial note: AI-assisted original BijliCoin educational workflow with locally tested synthetic fixtures. No external model, publisher feed, production service or private account was tested. AI-generated conceptual illustration.

Sources & context

  1. Python 3.12 JSON data types ↗
  2. OWASP secrets-management guidance ↗

See our editorial policy or report a correction.