Repository navigation
Conversation
redact() matches secrets by shape, so a bare secret value under a
credential-named key ({"client_secret": "x"}) reached the audit JSONL
unmasked. _clean now masks string values whose normalized key name is a
known credential name or ends in secret/password/passwd/token/apikey/
privatekey/secretkey. Exact/suffix matching only, so usage and identifier
fields (input_tokens, token_endpoint, auth_mode, vulnfix_key) are kept.
Closes #37
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The masked-keys test only used keys ending in a bare suffix, so removing the "_" normalization (which api_key/private_key/secret_key depend on) or dropping cookie/setcookie/passwd/privatekey/secretkey left it green. Add a key for each; every such mutant now fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Address the non-blocking review items on #40: - Mask list/tuple elements and bytes under a sensitive key (multi-valued Set-Cookie, lists of tokens); dicts are still walked so their own keys decide. Empty values and ints still pass through. - Add the credential/credentials suffixes from #37, plus secrets, passwords, passphrase, apikeys, accesskey (aws_secret_access_key, access_key), the exact name proxy-authorization, and a "privatekey" substring so private_key_pem is caught. - Document the accepted suffix false positives (e.g. next_page_token, operator-named repo_properties). - Tests pin every new rule, list/bytes masking and the non-str key guard; each corresponding mutant fails. No real audit/config field is matched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #37.
Problem
_cleaninagent/audit.pyredacted string values by their shape (viaredact()) and never looked at keys. A bare secret under a credential-named key has no shape to match, so it was written to the audit JSONL unmasked:Fix
A key is treated as credential-named after it's normalized: lowercased, with
_and-removed. It then matches one of three rules:authorization,proxyauthorization,cookie,setcookiesecret(s),password(s),passwd,passphrase,token,apikey(s),secretkey,accesskey,credential(s)privatekeyonly, so thatprivate_key_pemis caughtWhat happens to a value under such a key depends on its type:
***.Set-Cookieor a list of tokens.{"token": {"access_token": "x", "expires_in": 3600}}masks onlyaccess_token.Why suffix/exact matching, not substring
Audit records and config already contain fields such as
input_tokens,cache_read_input_tokens,token_endpoint,token_budget_fraction,broker_token_dir,auth_mode,vulnfix_keyandaccess_key_id, and masking any of those would destroy audit value. For the same reason atokens(plural) suffix is deliberately left out.I checked every key emitted by the
build_*builders inaudit.py, plus the agent's config and usage field names: none of them match. The accepted false positive is any string under a key ending in e.g.tokenorsecret, such as a futurenext_page_tokenor an operator-namedrepo_propertiesfield. That trade-off is documented next to the rules.Tests
In
tests/test_audit.py:test_sensitive_key_values_masked: every exact name and suffix, snake/camel/kebab case, nesting, and lists of dicts.test_extended_sensitive_key_shapes_masked: parametrized overcredentials,aws_secret_access_key,private_key_pem,proxy-authorization, plurals, and more.test_sensitive_key_non_string_values: list, tuple, bytes, nested dicts, empty values and ints.test_non_sensitive_token_and_key_fields_preserved: real usage, endpoint, mode and identifier fields come through unchanged.test_non_string_key_not_treated_as_sensitive.Mutation-tested: removing any exact name, suffix or substring, the
_/-normalization, list or bytes masking, the empty-value guard, or the non-string key guard each makes at least one test fail. Full agent suite: 1154 passed, 1 skipped.Scope note
This covers the structured audit path (
_serialize→_clean). The stream-event path (agent/_stream_events.py) still uses shape-basedredact()only, and isn't changed here.🤖 Generated with Claude Code