Skip to content

fix: bound JSON redaction traversal - #398

Open
codeforester wants to merge 3 commits into
mainfrom
bug/395-20260930-bug-redact-json-value-recurses-without-depth-or-cycle-limits
Open

codeforester wants to merge 3 commits into
mainfrom
bug/395-20260930-bug-redact-json-value-recurses-without-depth-or-cycle-limits

Conversation

@codeforester

Copy link
Copy Markdown
Contributor

Fixes #395

Comment thread lib/python/base_cli/json_contracts.py Outdated
identity = id(value)
if identity in seen:
return REDACTED
branch_seen = seen | {identity}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Efficiency: cycle detection copies the whole ancestor id-set at every container node (branch_seen = seen | {identity}) instead of mutating one shared set and backtracking (add/discard), so cost scales with nodes × depth rather than nodes. Measured on a synthetic payload of ~2M dict nodes at depth 99: this implementation takes ~2.75s vs ~1.48s for the same traversal using a single mutable active set — the exact pattern lib/python/base_cli/config.py::_validate_config_graph (lines 108-134) already uses for the same cycle+depth-bounded-graph problem. The PR's goal is to stop pathological input from being CPU-expensive, but a large-but-legal payload under the depth cap can still cause multi-second stalls on every JSON envelope emission. Worth reusing the mutable-set-with-backtracking pattern from config.py instead.

if isinstance(value, tuple):
return [redact_json_value(item) for item in value]
if isinstance(value, (Mapping, list, tuple)):
if _depth >= MAX_JSON_REDACTION_DEPTH:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design concern: the same "[REDACTED]" sentinel is now returned both when a secret-looking key/value is found and when the depth cap or a cycle is hit, so callers can no longer distinguish "this was a secret" from "this was just deep/cyclic structure." A command emitting a legitimately deep (>100 level) but non-sensitive structure (e.g. a recursively-generated debug tree) in details would have everything below level 100 collapse to "[REDACTED]", identical to real secret redaction — a consumer investigating a redaction can't tell a scrub from a truncation. Consider a distinct sentinel (e.g. "[TRUNCATED]") for the depth/cycle case.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: redact_json_value recurses without depth or cycle limits

1 participant