fix(mcp): redact secrets from OAuth failure logs - #1976
Merged
Aaronontheweb merged 5 commits intoAug 17, 2026
Conversation
An OAuth token or DCR exchange failure can carry the provider's raw error body inside the exception message. That body can echo back the client secret or token the request sent. McpClientManager logged nine such exceptions directly, and a log sink can print the full exception text, so a secret could leave the daemon log. Add a RedactForLogging helper. It swaps in a redacted summary only when the exception text matches a secret pattern. Most exceptions keep their original type and full stack trace, because most carry no secret-shaped text. This also fixes a gap in SecretOutputRedactor: the env-style regex did not match compound keys like client_secret or refresh_token, only the JSON regex did. A form-urlencoded OAuth error body uses exactly those compound keys.
Aaronontheweb
enabled auto-merge (squash)
August 17, 2026 21:34
PR netclaw-dev#1970 changes only in-memory identity fallback logic and adds no logging, so it does not introduce a leak on its own. But an audit for the same issue found McpOAuthCredentialStore has the same shape of gap: it also logs a raw exception in its credentials-file load path. The secrets file is decrypted before that callback runs, so a malformed-JSON or decryption exception could in principle echo a fragment of plaintext credential content into the log. Move RedactForLogging out of McpClientManager and into SecretOutputRedactor, so both McpClientManager and McpOAuthCredentialStore route their exception logging through the same shared helper.
…o fix/mcp-oauth-log-redaction
Merged
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.
Problem
A review of #1969 raised a question: could the new OAuth diagnostic logging
print a secret? The new code does not. It logs only booleans and field
names, never the raw token or client secret value.
The review found a separate, pre-existing gap.
McpClientManagerlogs nineOAuth-related exceptions directly through
ILogger. A token or DCR exchangefailure can carry the provider's raw HTTP error body inside the exception
message, and that body can echo back the client secret or token the request
sent. A log sink prints the full exception text, so a secret could leave the
daemon log. This risk grows when OTLP export sends logs off the box.
A second gap made the fix harder than "add a redact call":
SecretOutputRedactoralready redacts secrets in JSON key form (
"client_secret": "..."), but itsenv-style regex (
key=valuetext) did not match compound keys likeclient_secretorrefresh_token. Only the JSON regex matched those keys. Aform-urlencoded OAuth error body (
client_secret=...&grant_type=...) usesexactly the compound-key shape the env-style regex missed.
A follow-up check against #1970 (which touches
McpOAuthCredentialStore)found the same shape of gap there: its credentials-file load path also logs
a raw exception. The secrets file is decrypted before that callback runs, so
a malformed-JSON or decryption failure could in principle echo a fragment of
plaintext credential content into the log. #1970's own diff adds no logging
and does not introduce this; it is pre-existing in the file it touches.
Change
SecretOutputRedactor's env-style regex to match the same compoundkey set the JSON regex already matches.
SecretOutputRedactor.RedactForLogging, a shared helper that swaps ina redacted summary only when an exception's rendered text matches a secret
pattern. The common case (network errors, cancellations, disposal
failures) keeps its original exception instance, type, and full stack
trace untouched.
_logger.LogWarning(ex, ...)/_logger.LogError(ex, ...)call sites in
McpClientManager.csthrough it, plus the two inMcpOAuthCredentialStore.cs.