Skip to content

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

Open
otmyards-crypto wants to merge 1 commit into
prometheus:mainfrom
otmyards-crypto:fix/telegram-redact-url
Open

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

Conversation

@otmyards-crypto
Copy link
Copy Markdown

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

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.

Summary by CodeRabbit

  • Bug Fixes
    • Error messages from Telegram notifications now redact sensitive authentication tokens to prevent accidental exposure in logs and error outputs.

Review Change Stack

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>
@otmyards-crypto otmyards-crypto requested a review from a team as a code owner May 24, 2026 20:18
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

📝 Walkthrough

Walkthrough

This PR adds error redaction to the Telegram notifier to prevent sensitive bot tokens from appearing in logged or returned errors. The implementation change wraps send errors with notify.RedactURL, and comprehensive tests verify redaction works for both transport-level and API-level failures.

Changes

Telegram notifier error redaction

Layer / File(s) Summary
Error redaction in Notify function
notify/telegram/telegram.go
The Telegram notifier's Notify method now passes errors from n.client.Send through notify.RedactURL to remove sensitive tokens before returning.
Redaction test coverage
notify/telegram/telegram_test.go
New test TestTelegramNotifyRedactURL with two subcases: one verifying transport-level errors (dial failures) have the token redacted and contain the redaction marker, and another verifying Telegram API errors have the token redacted.

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 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%. 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 and accurately summarizes the main change: wrapping the Send error with notify.RedactURL to redact the bot token.
Description check ✅ Passed The PR description is comprehensive and follows the template, including checklist items, context, change explanation, tests, and security release notes. All critical sections are properly filled out.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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

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.

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.

1 participant