-
Notifications
You must be signed in to change notification settings - Fork 134
Add client_secret redaction pass to credential scrubber #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,9 @@ | |
| _RAW_TOKEN_RE = re.compile( | ||
| r"(ghp_|gho_|ghu_|ghs_|ghr_|github_pat_|sk-ant-)[A-Za-z0-9_-]+" | ||
| ) | ||
| _FORM_SECRET_RE = re.compile( | ||
| r"(?i)(client[_-]?secret\"?\s*[=:]\s*)[\"']?[^\s,}&\"']+[\"']?" | ||
| ) | ||
|
|
||
|
|
||
| def redact(text: str) -> str: | ||
|
|
@@ -42,6 +45,7 @@ def redact(text: str) -> str: | |
| s = _BEARER_RE.sub(r"\1***", s) | ||
| s = _QUERY_TOKEN_RE.sub(r"\1***", s) | ||
| s = _RAW_TOKEN_RE.sub(r"\1***", s) | ||
| s = _FORM_SECRET_RE.sub(r"\1***", s) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pass ordering is fine — this runs after the token-prefix pass and the patterns don't overlap, so no interaction to worry about. This new pass is the line with no test behind it. Please add a |
||
| # Residual risk (VULN-012, CWE-532): redaction is pattern-based over | ||
| # enumerated token formats; a novel/unknown secret format not in the pass | ||
| # list above would still pass through to the audit stream. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exclusion class
[^\s,}&\"']+is meant to stop at a closing quote, but it also blocks the opening one — so any quoted value fails to match at all and passes through verbatim. Probing the regex directly:This matters for the threat model in the PR description. RFC 6749 §5.2 specifies token-endpoint error responses as JSON, and
agent/auth.py:134interpolatesresponse.textstraight intoAuthTokenError— so the most likely shape of the leak is exactly the shape not covered. The TOML form is live too:tests/test_audit.py:496writesclient_secret = "csecret"in a config fixture, andagent/audit.py:368redacts every string in an audit record.Suggested fix — consume the opening quote explicitly, and pick up the
client-secret/clientSecretspellings that also leak today:Please re-check idempotence after changing this. The current pattern happens to be idempotent because
*isn't in the exclusion class, and that property is worth keeping — note thattest_property_redact_is_idempotent(tests/test_url.py:164) only generates URL inputs, so it won't check this for you.