Original flaw
Earlier advisory · CVE-2026-42358The earlier depth cutoff returned nested values before evaluating sensitive key names.
Sink: SecretsMasker._redact returns item when depth exceeds the cap.
Originally written by Tzu-ping Chung
How AI contributed: Incomplete remediationPublished Aug 12, 2026 in
apache/airflow
Provisional finding. Full causal and release verification remains incomplete.
Default-enabled sensitive-field masking fails when an authorized Variable reader receives stored JSON with neutral outer names and a sensitive inner key behind a list encountered beyond depth five. ORM plaintext enters VariableResponse JSON parsing and the shared masker; early list return prevents visiting the key, and UI displays the serialized value. JSON supplies lists, not tuple/set values. Independent packaged-route inventory and fresh serializer source show public stable GET responses also mask; the advisory universal raw-REST rationale is not adopted. The raw execution route requires task-token authority. No authorization bypass is demonstrated.
Case facts
Only the highlighted steps are this advisory. The first step is the earlier flaw the AI tried, and failed, to close.
Original flaw
Earlier advisory · CVE-2026-42358Sink: SecretsMasker._redact returns item when depth exceeds the cap.
Originally written by Tzu-ping Chung
This advisoryCVE-2026-54183 (GHSA-G4QJ-5VXV-WGGF)
AI tried to fix this
The AI-assisted change was a real security patch, but it left the same advisory reachable.
Missed: Iterable traversal still followed the cutoff, leaving nested JSON-list children unvisited.
Incomplete AI-assisted fix · Claude
Fixed again
This is the patch that actually stops the same attack path.
Fix authorship not yet analyzed
@@ -359,9 +363,13 @@ ) for dict_key, subval in item.items() } return to_return+ # Avoid spending too much effort on pattern-based masking of+ # deeply nested non-dict structures.+ if depth > max_depth:+ return item if isinstance(item, Enum): return self._redact( item=item.value, name=name, depth=depth, max_depth=max_depth, replacement=replacement ) if _is_v1_env_var(item):@@ -374,2 +379,18 @@+ return tuple(+ self._redact(+ subval, name=None, depth=(depth + 1), max_depth=max_depth, replacement=replacement+ )+ for subval in item+ )+ if isinstance(item, list):+ return [+ self._redact(+ subval, name=None, depth=(depth + 1), max_depth=max_depth, replacement=replacement+ )+ for subval in item+ ]+ # The depth cutoff only bounds the work of pattern-based string+ # masking below — key-name redaction (dicts and iterables above) is+ # unbounded so sensitive keys fail closed at any depth. if depth > max_depth: return itemAI-assisted change afc4d3cdbc9a84d6eb8010a70a2bbe9e514c16829ef7e348db0a3994d5c914fc · Fix b5797cf3734c86e585e473579e98b90f9538ae17f9ed11a59b3735d77ad622be