{"record":{"id":"9c17530d6b1ad49f","repo":"HKUDS/nanobot","slug":"unsafe-media-url-error","errorCode":null,"errorMessage":"unsafe media URL: {error}","messagePattern":"unsafe media URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"nanobot/channels/telegram/runtime.py","lineNumber":961,"sourceCode":"                    \"video\": app.bot.send_video,\n                    \"voice\": app.bot.send_voice,\n                    \"audio\": app.bot.send_audio,\n                }.get(media_type, app.bot.send_document)\n                param = {\n                    \"photo\": \"photo\",\n                    \"video\": \"video\",\n                    \"voice\": \"voice\",\n                    \"audio\": \"audio\",\n                }.get(media_type, \"document\")\n                extra: dict[str, Any] = {}\n                if media_type == \"video\":\n                    extra[\"supports_streaming\"] = True\n\n                # Telegram Bot API accepts HTTP(S) URLs directly for media params.\n                if self._is_remote_media_url(media_path):\n                    ok, error = validate_url_target(media_path)\n                    if not ok:\n                        raise ValueError(f\"unsafe media URL: {error}\")\n                    await self._call_with_retry(\n                        sender,\n                        chat_id=chat_id,\n                        **{param: media_path},\n                        reply_parameters=reply_params,\n                        **thread_kwargs,\n                        **extra,\n                    )\n                    continue\n\n                media_bytes = Path(media_path).read_bytes()\n                filename = Path(media_path).name\n                send_kwargs = {param: media_bytes, \"filename\": filename}\n                await self._call_with_retry(\n                    sender,\n                    chat_id=chat_id,\n                    reply_parameters=reply_params,\n                    **thread_kwargs,","sourceCodeStart":943,"sourceCodeEnd":979,"githubUrl":"https://github.com/HKUDS/nanobot/blob/42f37dc4c0e409eac7818a82d165c5f2757bc075/nanobot/channels/telegram/runtime.py#L943-L979","documentation":"In TelegramChannel.send(), a remote media item (http:// or https:// URL in msg.media) failed SSRF validation: validate_url_target(media_path) returned (False, error), so a ValueError is raised instead of handing the URL to the Telegram Bot API. This blocks server-side request forgery against internal networks via bot-sent media URLs; the URL at fault may resolve to a private/loopback/internal address or use a disallowed scheme.","triggerScenarios":"Thrown at nanobot/channels/telegram/runtime.py:961 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Send media from a public, resolvable HTTP(S) URL or upload local bytes instead","Add an explicitly approved host to the SSRF whitelist in tools.ssrf_whitelist if the target is intentionally internal","Download the media locally and send the file bytes rather than a URL"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"42f37dc4c0e409eac7818a82d165c5f2757bc075","analyzedAt":"2026-08-26T00:18:52.276Z","contentChangedAt":"2026-08-26T00:18:52.276Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}