Repository navigation
Redact multiline and duplicate-key JSON atomically #908
Copy link
Copy link
Open
Labels
area: ci-cdCI, GitHub Actions, checks, release, or supply chainCI, GitHub Actions, checks, release, or supply chainarea: dataDatabase, schema, migration, ETL, or lineageDatabase, schema, migration, ETL, or lineagearea: securitySecurity boundary, hardening, or vulnerability preventionSecurity boundary, hardening, or vulnerability preventionarea: ui-uxFrontend, interaction, design, or user experienceFrontend, interaction, design, or user experiencemaintenancepriority: mediumNormal-priority or P2 workNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmentOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capabilityNew or expanded product capability
Description
Outcome
A complete JSON document is redacted atomically before evidence is split into lines, while preserving valid JSON layout, duplicate-key order, scalar types, result markers, and bounded processing.
Current defect
The current redaction path splits text into lines before attempting structural JSON handling. A valid document such as:
{
"password"
:
"<opaque-credential>"
}can separate the sensitive key from its value, so line-local handling never associates them. Conventional json.loads also collapses duplicate object keys, which cannot prove duplicate-key or layout preservation.
This is distinct from the wrapper-recursion defect tracked for Draft #906.
Required repair
- recognize and process a complete bounded JSON document before line splitting;
- preserve whitespace/layout, duplicate-key order, scalar types, and stable result-marker/schema fields;
- redact values selected by sensitive keys and supported opaque credential semantics even when key, colon, and value span lines;
- cover escaped strings, arrays/objects, duplicate sensitive and benign keys, and multiple sensitive occurrences;
- keep invalid/non-JSON text on the bounded general redaction path without leaking raw parser diagnostics;
- retain depth/input-size/performance bounds and fail closed when a safe structural context cannot be established;
- do not normalize/re-serialize evidence in a way that destroys diagnostic layout or silently drops duplicate keys.
Security design constraints
- Use a bounded iterative token/span rewriter before line splitting. Preserve every untouched source slice; do not transform raw text with whole-value
json.loads/dict/json.dumpsorobject_pairs_hook. - Process complete JSON and bounded JSON spans surrounded by prefixes/suffixes or multiple diagnostic records. A malformed structural candidate that can bridge key, colon, and value across lines fails closed rather than leaking through line-local fallback.
- Decode key/string tokens only for classification. Preserve unchanged escape spelling, whitespace, CR/LF boundaries, duplicate-key order/count, punctuation, and stable result-marker/schema fields.
- Preserve value categories under sensitive keys: string →
"[REDACTED]"; integer/number → a zero value of the same JSON number category; boolean →false;nullremainsnull; arrays/objects retain shape and recursively scrub scalar leaves. - Apply explicit input-byte, depth, token, string, replacement, and cumulative work limits. Limit breach or unsafe parser state returns bounded fail-closed evidence without raw input or exception text.
- Keep
redact_json_value()for already-materialized trusted result objects; raw-text layout preservation belongs only to the text path. - Test JSON command fields containing nested wrappers and shell operands containing JSON so neither parser assumes the other already handled the credential.
- Do not claim end-to-end output-memory closure: unbounded PIPE/service-file capture remains separate Issue Bound sandbox subprocess output and long-running service logs #766.
- Implement on a separate stacked Draft from exact fix(sandbox): replay redaction after fixture-history contamination #906: hosted test-only RED, then bounded GREEN, then Secret Scan/full-history and exact 100% coverage before convergence.
Acceptance
- fail-first fixtures reproduce multiline key/value separation and duplicate-key loss;
- GREEN tests prove layout/order/type/marker preservation and complete credential removal;
- malformed, excessive-depth, high-volume, and mixed text/JSON cases remain bounded;
- no fixed credential-shaped literal is committed;
- Sandbox Log Redaction Quality CI passes at the exact head with 100% statement/branch coverage for the three owned production modules;
- full suite, Secret Scan, security/supply-chain gates, current source review, and independent approval pass;
- protected-main synthetic stdout/stderr/timeout/service-tail evidence is required after integration.
Related: #906.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area: ci-cdCI, GitHub Actions, checks, release, or supply chainCI, GitHub Actions, checks, release, or supply chainarea: dataDatabase, schema, migration, ETL, or lineageDatabase, schema, migration, ETL, or lineagearea: securitySecurity boundary, hardening, or vulnerability preventionSecurity boundary, hardening, or vulnerability preventionarea: ui-uxFrontend, interaction, design, or user experienceFrontend, interaction, design, or user experiencemaintenancepriority: mediumNormal-priority or P2 workNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmentOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capabilityNew or expanded product capability
Activity
seonghobae commentedon Aug 11, 2026
Current stacked active-PR evidence: #929 exact head
0b8b2a286094d6e52a9160faee678c5b75f1711eis a non-destructive two-parent merge of prior atomic-JSON head730274cceece6db95986bf65fc46f7c5a132f467and current #906 parentd573d21752e07d3cbbf9845b4b413baf81ecea7c; comparison is ahead 7, behind 0. The merged tree passes 158 focused tests with 1,044/1,044 statements and 420/420 branches, then 1,076 full-suite tests plus 16 subtests and 7,655/7,655 owned-production statements with 3,078/3,078 branches. This non-default-base Draft has no hosted PR workflow; absence is not passing evidence. Keep #908 open until #906 integrates, #929 is retargeted and revalidated against exact protected main, qualifying independent approval exists, and protected-main synthetic acceptance passes.