Summary
TelegramBotHandler::sendCurl() silently swallows errors when the Telegram API (or an intermediary proxy) returns a non-JSON response. The handler returns as if the message was sent successfully, with no exception and no indication of failure.
Version: 3.10.0
Vulnerable code
TelegramBotHandler.php lines 277–285:
$result = Curl\Util::execute($ch);
if (!\is_string($result)) {
throw new RuntimeException('Telegram API error. Description: No response');
}
$result = json_decode($result, true);
if ($result['ok'] === false) {
throw new RuntimeException('Telegram API error. Description: ' . $result['description']);
}
Three layers of failure compound:
json_decode() returns null for non-JSON input — no null check follows
null['ok'] emits a warning and returns null in PHP 8+ — no type check
null === false evaluates to false — the error check is bypassed entirely
Why it triggers
curl_exec() returns the response body for HTTP error status codes (502, 503, etc.), not false. The is_string() check on line 278 passes. The HTML/plaintext error page then proceeds to json_decode, which returns null.
Common real-world triggers:
- Cloudflare 502 Bad Gateway (returns HTML)
- Nginx error pages during Telegram API downtime
- Truncated responses from network timeouts
- Any proxy/CDN intercepting the request with a non-JSON error page
Impact
The handler's purpose is critical alerting. When it fails silently during infrastructure issues — exactly when alerts matter most — log messages are permanently lost with zero indication. The Logger's try/catch (Logger.php:389) only works if an exception is thrown; since this bug suppresses the exception, the failure is completely invisible.
For comparison: SlackWebhookHandler, SendGridHandler, and IFTTTHandler don't attempt response validation at all. TelegramBotHandler is the only handler that validates, but gets it wrong for the non-JSON case.
Suggested fix
$result = json_decode($result, true);
if (!is_array($result)) {
throw new RuntimeException('Telegram API error. Description: Unexpected non-JSON response');
}
if ($result['ok'] === false) {
throw new RuntimeException('Telegram API error. Description: ' . ($result['description'] ?? 'Unknown error'));
}
Summary
TelegramBotHandler::sendCurl()silently swallows errors when the Telegram API (or an intermediary proxy) returns a non-JSON response. The handler returns as if the message was sent successfully, with no exception and no indication of failure.Version: 3.10.0
Vulnerable code
TelegramBotHandler.phplines 277–285:Three layers of failure compound:
json_decode()returnsnullfor non-JSON input — no null check followsnull['ok']emits a warning and returnsnullin PHP 8+ — no type checknull === falseevaluates tofalse— the error check is bypassed entirelyWhy it triggers
curl_exec()returns the response body for HTTP error status codes (502, 503, etc.), notfalse. Theis_string()check on line 278 passes. The HTML/plaintext error page then proceeds tojson_decode, which returnsnull.Common real-world triggers:
Impact
The handler's purpose is critical alerting. When it fails silently during infrastructure issues — exactly when alerts matter most — log messages are permanently lost with zero indication. The Logger's try/catch (Logger.php:389) only works if an exception is thrown; since this bug suppresses the exception, the failure is completely invisible.
For comparison: SlackWebhookHandler, SendGridHandler, and IFTTTHandler don't attempt response validation at all. TelegramBotHandler is the only handler that validates, but gets it wrong for the non-JSON case.
Suggested fix