Conversation
NotificationService.Webhooks.cs logged every outbound provider request
at Information level with LogRedaction.RedactText(webhookUrl,
GetSensitiveValuesFromEnvironment()). RedactText only replaces values
sourced from the process environment, so a webhook URL typed into
Settings was never touched and went out whole. The credential lives in
the query string for Pushover and Pushbullet and in a path segment for
Telegram, Discord and Slack.
Add LogRedaction.SanitizeWebhookUrl: keeps scheme/host/port, drops
userinfo and the query string (same logic as the existing SanitizeUrl),
and for the four providers whose credential lives in the path, masks
just the segment(s) carrying it instead of dropping the whole path
(api.telegram.org/bot<redacted>/sendMessage,
discord.com/api/webhooks/<redacted>/<redacted>,
hooks.slack.com/services/<redacted>/...). Every other host keeps its
path and loses its query, matching SanitizeUrl's existing behavior.
Wire it into all 25 {WebhookUrl} logging call sites in
NotificationService.Webhooks.cs (NTFY, Pushover, Telegram, Pushbullet,
Slack, Discord, generic) and into
NotificationDiagnostics.LogFailedResponseAsync, replacing both the
RedactText call and the three call sites that already used SanitizeUrl.
Also drop the Pushover form body from its Information log line
entirely instead of trying to redact it: the body carries token= and
user= as plain form fields, which AggressiveRedact cannot catch for
the same environment-only reason. Checked the other providers' request
bodies (NTFY, Telegram, Pushbullet, Slack, generic) - none of them put
a credential in the body, so no change was needed there.
Fixes Listenarrs#982.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… call sites Per-provider unit tests for LogRedaction.SanitizeWebhookUrl (Telegram, Discord, Slack, Pushover, plus a control case with no credential-shaped content, so the tests can't pass from a version that just blanks the whole URL). Also three NotificationService integration tests that exercise the real Pushover/Telegram/Discord code paths in NotificationService.Webhooks.cs with a credential that is deliberately not an environment variable: if any of those call sites regressed to LogRedaction.RedactText(webhookUrl, GetSensitiveValuesFromEnvironment()), the credential would sail straight through into the captured log line and these would fail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
m4bard
force-pushed
the
fix/webhook-url-sanitize
branch
from
September 15, 2026 18:35
ffdc5e2 to
86ff24d
Compare
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.
Fixes #982.
NotificationService.Webhooks.cslogged every outbound provider request at Information level usingLogRedaction.RedactText(webhookUrl, LogRedaction.GetSensitiveValuesFromEnvironment()). That helper only replaces values sourced from the process environment, so a webhook URL typed into Settings was never touched and went out whole. The credential sits in the query string for Pushover and Pushbullet and in a path segment for Telegram, Discord and Slack.The fix
Added
LogRedaction.SanitizeWebhookUrl. It keeps scheme, host and port, drops userinfo and the whole query string (the same logicSanitizeUrlalready uses), and for the providers whose credential lives in the path, masks just the segment(s) carrying it instead of dropping the whole path:api.telegram.org/bot<token>/sendMessagebecomesapi.telegram.org/bot<redacted>/sendMessagediscord.com/api/webhooks/<id>/<token>becomesdiscord.com/api/webhooks/<redacted>/<redacted>hooks.slack.com/services/<team>/<bot>/<token>becomeshooks.slack.com/services/<redacted>/<redacted>/<redacted>SanitizeUrlWired it into all 25
{WebhookUrl}logging call sites inNotificationService.Webhooks.cs(NTFY, Pushover, Telegram, Pushbullet, Slack, Discord, generic), plusNotificationDiagnostics.LogFailedResponseAsync, replacing both theRedactTextcalls and the three call sites that were already using the query-onlySanitizeUrl.Also dropped the Pushover form body from its Information log line entirely instead of trying to redact it. That body carries
token=anduser=as plain form fields, which the existingAggressiveRedacthelper cannot catch for the same environment-only reason. I checked the other providers' request bodies (NTFY, Telegram, Pushbullet, Slack, generic) and none of them put a credential in the body, so no change was needed there.Tests
Added to
tests/Features/Application/Security/Redaction/LogRedactionTests.cs:SanitizeWebhookUrltest per provider shape (Telegram, Discord, Slack, Pushover), each checking that the credential is gone and the non-sensitive host/path survives.Added to
tests/Features/Application/Security/Redaction/SecurityRedactionTests.cs:NotificationService.SendNotificationAsyncwith a credential that is deliberately not an environment variable, capturing the actual formatted log line through a mockedILogger. If any of those call sites regressed to the oldRedactText(webhookUrl, GetSensitiveValuesFromEnvironment())shape, the credential would appear in the captured log line and these would fail.Ran the full backend suite:
dotnet test tests/Listenarr.Tests.csproj, 3126 passed, 130 skipped, 0 failed, at commit ffdc5e2.Sequencing
This touches
NotificationService.Webhooks.cs, which #754 and #943 are also open against, per the issue's note. Happy to rebase after either lands.Disclosure: drafted with Claude Code at my direction; I read the cited code at commit ffdc5e2 and reviewed this before posting.