Panniantong/Agent-Reach · error · TranscribeError
SSRF blocked: only public http(s) URLs are allowed
Error message
SSRF blocked: only public http(s) URLs are allowed
What it means
Raised by _assert_safe_public_url (transcribe.py:216-221) during SSRF validation when the URL has no '://' scheme and the text before the first slash contains a colon whose part after the last colon is not pure digits — i.e. it looks like a scheme or malformed port rather than host:port. Scheme-less input is auto-prefixed with https:// only when it plausibly is a bare host[:port].
Source
Thrown at agent_reach/transcribe.py:221
(
ip.is_private,
ip.is_loopback,
ip.is_link_local,
ip.is_reserved,
ip.is_multicast,
ip.is_unspecified,
)
)
def _assert_safe_public_url(url: str) -> None:
"""Reject literal local/internal URLs without DNS-resolving public hosts."""
if "://" not in url:
before_slash = url.split("/", 1)[0]
if ":" in before_slash:
host_part, port_part = before_slash.rsplit(":", 1)
if not host_part or not port_part.isdigit():
raise TranscribeError("SSRF blocked: only public http(s) URLs are allowed")
normalized_url = f"https://{url}"
parsed = urlparse(normalized_url)
else:
normalized_url = url
parsed = urlparse(url)
if parsed.scheme not in {"http", "https"}:
raise TranscribeError("SSRF blocked: only public http(s) URLs are allowed")
raw_authority = normalized_url.split("://", 1)[1]
raw_authority = raw_authority.split("/", 1)[0]
raw_authority = raw_authority.split("?", 1)[0]
raw_authority = raw_authority.split("#", 1)[0]
if "\\" in raw_authority or "%" in raw_authority:
raise TranscribeError("SSRF blocked: encoded or ambiguous URL host")
raw_host = (parsed.hostname or "").strip().rstrip(".")
if not raw_host:
raise TranscribeError("SSRF blocked: URL host is missing")View on GitHub (pinned to 93ae1d18c3)
Solutions
- Pass a full http(s) URL including scheme: 'https://example.com/file.mp3'
- For bare hosts, use host or host:digits form ('example.com:8443') which normalizes correctly
- For rtsp/ftp/other-protocol sources, download the media yourself first, then pass the local file path to transcribe()
Example fix
# before
download_audio("rtsp:camera-stream", out_dir) # SSRF blocked
# after: fetch out-of-band, hand over a local file
subprocess.run(["ffmpeg", "-rtsp_transport", "tcp", "-i", "rtsp://cam/stream", "-t", "60", "cam.m4a"], check=True)
transcribe("cam.m4a") Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def is_http_url(url: str) -> bool:
if "://" in url:
return urlparse(url).scheme in {"http", "https"}
before_slash = url.split("/", 1)[0]
if ":" in before_slash:
_, port = before_slash.rsplit(":", 1)
return port.isdigit()
return True Try / catch
from agent_reach.transcribe import TranscribeError
try:
transcribe(source)
except TranscribeError as e:
if str(e).startswith("SSRF blocked"):
reject_user_input(source) # do not retry; fix the URL
raise Prevention
- Always pass full https:// URLs for remote media
- Convert rtsp/ftp/other-protocol sources to local files before transcribing
- Validate scheme-less strings for a proper host[:digits] shape
When it happens
Trigger: download_audio('ftp://...') goes to the scheme branch (error 64); this specific raise fires for inputs like 'example.com:notaport', 'rtsp:media', 'mailto:x', or a bare 'https:' fragment without '//'. Any scheme-less string whose colon suffix is non-numeric is rejected.
Common situations: Passing a URI copied with a custom scheme (rtsp:, rtmp:) or a mangled copy-paste like 'example.com:8080:extra'. Developers testing download_audio() with non-HTTP media URLs (RTSP cameras, FTP archives).
Related errors
- only the V2EX HTTPS API is allowed
- SSRF blocked: encoded or ambiguous URL host
- SSRF blocked: URL host is invalid
- SSRF blocked: internal host is not allowed
- gh hosts.yml 无法安全读取
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/3826560d35d46e2c.
Report an issue: GitHub.