diff --git a/agent/redact.py b/agent/redact.py index 54b02a1e92..0479640e0b 100644 --- a/agent/redact.py +++ b/agent/redact.py @@ -618,6 +618,11 @@ def _redact_python_repr_fields(text: str) -> str: # programmatic env lookups just like the ENV/JSON/YAML passes do. if _ENV_LOOKUP_VALUE_RE.match(value): return match.group(0) + # An upstream pass (MCP probe header scrub, _mask_token) already masked this + # value; re-masking would erase the scheme word it deliberately kept + # (``'Authorization': 'Digest ***'`` → ``'***'``). + if "***" in value or value.startswith("«redacted:"): + return match.group(0) # Do not retain head/tail characters here: escaped repr atoms can cross # a slicing boundary and leave an unescaped quote behind. A full mask is # parseable for both str and bytes values and leaks no opaque bytes. diff --git a/tests/agent/test_redact.py b/tests/agent/test_redact.py index b703ddd6a2..3df2b82879 100644 --- a/tests/agent/test_redact.py +++ b/tests/agent/test_redact.py @@ -378,6 +378,12 @@ class TestPythonReprFields: text = "{'model': 'gpt-5', 'token_count': '123'}" assert redact_sensitive_text(text, force=True) == text + def test_already_masked_repr_value_keeps_its_scheme_word(self): + # An upstream scrub (MCP probe headers) leaves ``Digest ***``; the repr + # pass must not collapse that to a bare ``***`` and lose the scheme. + text = "headers={'Authorization': 'Digest ***'}" + assert redact_sensitive_text(text, force=True) == text + def test_code_file_preserves_secret_shaped_fixture(self): text = "CONFIG = {'BRAVE_API_KEY': 'fixture-value-1234567890'}" assert redact_sensitive_text(text, force=True, code_file=True) == text