Skip to content

notify/telegram: wrap Send error with notify.RedactURL - #5254

Merged
SoloJacobs merged 1 commit into
prometheus:mainfrom
otmyards-crypto:fix/telegram-redact-url
Aug 30, 2026
Merged

notify/telegram: wrap Send error with notify.RedactURL#5254
SoloJacobs merged 1 commit into
prometheus:mainfrom
otmyards-crypto:fix/telegram-redact-url

Conversation

@otmyards-crypto

@otmyards-crypto otmyards-crypto commented May 24, 2026

Copy link
Copy Markdown
Contributor

Pull Request Checklist

This PR addresses a small inconsistency left over from #3887.

Which user-facing changes does this PR introduce?

[SECURITY] notify/telegram: redact bot token from Send errors

Context

#3887 introduced notify.RedactURL and applied it to every notifier's HTTP error return path so that bot tokens, webhook URLs, and other secrets embedded in *url.Error are stripped before the error is logged.

notify/telegram/telegram.go was the only notifier that was missed. When telebot.Bot.Send fails for transport reasons (dial timeout, connection refused, TLS handshake error, etc.), the underlying http.Client returns a *url.Error whose URL field is the full Telegram API URL — which contains the bot token as a path segment:

https://api.telegram.org/bot123456789:ABCdefGHIjklMNOpqrSTUvwxYZ/sendMessage

That error is returned verbatim from Notify, then logged by the surrounding notify.RetryStage (l.Warn("Notify attempt failed, will retry later", "err", err)) and dispatch.aggrGroup (logger.Error("Notify for alerts failed")). The result is that the bot token ends up in operator logs on every transport failure — observed in production with alertmanager v0.28.1 going through a flaky outbound link.

Change

One-line fix at the only relevant call site:

 	if err != nil {
-		return true, err
+		return true, notify.RedactURL(err)
 	}

Other return paths in Notify were checked and do not need wrapping:

  • getBotToken and getChatID errors come from os.ReadFile on local files and contain no URL.
  • createTelegramClient runs telebot.NewBot with Offline: true, so it never contacts the API and never returns a *url.Error. (Constructor errors don't go through Notify anyway.)

Tests

TestTelegramNotifyRedactURL covers both error paths:

  1. Transport error (*url.Error): a httptest.Server is started and immediately closed so the next Send call fails to dial. The test asserts the bot token is absent from the returned error and that the URL is replaced with <redacted>.
  2. Telegram API error (non-*url.Error): a fake server returns {"ok":false,"description":"Bad Request: chat not found"}. telebot wraps this in its own error type that does not contain *url.Error, so notify.RedactURL is a no-op — but the token is also not present in the resulting error string (telebot's API error formatter doesn't include the URL). The test asserts the token is absent in this path too.

Notes

notify.RedactURL uses errors.As(err, *url.Error) and is a no-op when the error chain doesn't include *url.Error, so this change is safe for the API-error path and does not depend on assumptions about telebot's internal error wrapping.

@otmyards-crypto
otmyards-crypto requested a review from a team as a code owner May 24, 2026 20:18
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8379e143-6a5f-48e9-921a-1540a406564f

📥 Commits

Reviewing files that changed from the base of the PR and between 4653ffc and f253fcd.

📒 Files selected for processing (2)
  • notify/telegram/telegram.go
  • notify/telegram/telegram_test.go

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

This PR redacts Telegram bot tokens from send errors before classification and return. Tests cover transport-level failures and Telegram API error responses.

Changes

Telegram notifier error redaction

Layer / File(s) Summary
Error redaction in Notify function
notify/telegram/telegram.go
Notify passes n.client.Send errors through notify.RedactURL before wrapWithFailureReason.
Redaction test coverage
notify/telegram/telegram_test.go
TestTelegramNotifyRedactURL verifies token redaction for transport-level failures and Telegram API errors.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to f253f

Telegram transport errors now redact bot tokens before reaching logs while preserving existing retry behavior. No actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Telegram notifier and the primary change: wrapping Send errors with notify.RedactURL.
Description check ✅ Passed The description is complete and directly explains the security issue, implementation, affected error paths, tests, and release note. It also records the bugfix test and commit sign-off checklist items…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is complete and directly explains the security issue, implementation, affected error paths, tests, and release note. It also records the bugfix test and commit sign-off checklist items.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@notify/telegram/telegram_test.go`:
- Line 288: There is an unmatched closing brace in
notify/telegram/telegram_test.go (a stray "}" at the end of the file) that
prevents the tests from compiling; remove that extra brace so the file's braces
properly match and the surrounding test functions (e.g., the test function
blocks in this file) close correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a883295a-cfc2-45c6-97ac-6a546fb58436

📥 Commits

Reviewing files that changed from the base of the PR and between 36afed4 and 4653ffc.

📒 Files selected for processing (2)
  • notify/telegram/telegram.go
  • notify/telegram/telegram_test.go

Comment thread notify/telegram/telegram_test.go Outdated
require.NotContains(t, err.Error(), token, "bot token leaked in API error")
})
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from pathlib import Path

path = Path("notify/telegram/telegram_test.go")
src = path.read_text()

i = 0
line = 1
stack = 0
state = "code"

while i < len(src):
    c = src[i]
    n = src[i + 1] if i + 1 < len(src) else ""

    if state == "code":
        if c == "/" and n == "/":
            state = "line_comment"; i += 1
        elif c == "/" and n == "*":
            state = "block_comment"; i += 1
        elif c == '"':
            state = "double_quote"
        elif c == "'":
            state = "single_quote"
        elif c == "`":
            state = "raw_quote"
        elif c == "{":
            stack += 1
        elif c == "}":
            stack -= 1
            if stack < 0:
                print(f"unmatched closing brace near line {line}")
                break

    elif state == "line_comment":
        if c == "\n":
            state = "code"

    elif state == "block_comment":
        if c == "*" and n == "/":
            state = "code"; i += 1

    elif state == "double_quote":
        if c == "\\":
            i += 1
        elif c == '"':
            state = "code"

    elif state == "single_quote":
        if c == "\\":
            i += 1
        elif c == "'":
            state = "code"

    elif state == "raw_quote":
        if c == "`":
            state = "code"

    if c == "\n":
        line += 1
    i += 1
else:
    print(f"brace_balance={stack}")
PY

Repository: prometheus/alertmanager

Length of output: 105


Remove the stray closing brace at Line 288 in notify/telegram/telegram_test.go

The file contains an unmatched }, so it will fail to parse/compile.

💡 Proposed fix
@@
-}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@notify/telegram/telegram_test.go` at line 288, There is an unmatched closing
brace in notify/telegram/telegram_test.go (a stray "}" at the end of the file)
that prevents the tests from compiling; remove that extra brace so the file's
braces properly match and the surrounding test functions (e.g., the test
function blocks in this file) close correctly.

telegram.go was the only notifier not applying notify.RedactURL to
errors from the underlying HTTP client. When telebot's Send call
fails for transport reasons (e.g. dial timeout), it returns a
*url.Error that includes the full API URL, which contains the bot
token as a path segment (https://api.telegram.org/bot<TOKEN>/...).
This error propagated verbatim into the slog attributes logged by
notify.go and dispatch.go, leaking the token.

All other notifiers (webhook, slack, discord, msteams, etc.) already
call notify.RedactURL on their HTTP errors following PR prometheus#3887. Apply
the same pattern to the one remaining call site in telegram.go.

Note: getBotToken errors are local file-read errors with no URL, and
createTelegramClient / telebot.NewBot runs in Offline mode and never
contacts the API, so neither site needs wrapping.

Adds a unit test covering both error paths:
- transport error (*url.Error): token redacted, URL shows <redacted>
- Telegram API error (non-*url.Error): RedactURL is a no-op, but
  telebot's own error message does not include the URL or token.

Signed-off-by: otmyards-crypto <245061101+otmyards-crypto@users.noreply.github.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Signed-off-by: Solomon Jacobs <solomonjacobs@protonmail.com>
@SoloJacobs
SoloJacobs force-pushed the fix/telegram-redact-url branch from 4653ffc to f253fcd Compare August 30, 2026 09:30
@SoloJacobs
SoloJacobs merged commit bccb5e5 into prometheus:main Aug 30, 2026
7 checks passed
@SoloJacobs

Copy link
Copy Markdown
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants