Panniantong/Agent-Reach · error · TranscribeError
SSRF blocked: internal host is not allowed
Error message
SSRF blocked: internal host is not allowed
What it means
Raised by _assert_safe_public_url (transcribe.py:244-245) when the canonicalized host is in _BLOCKED_HOSTS ({'localhost', 'metadata.google.internal'}) or ends with '.localhost'. These names resolve to the local machine or the cloud metadata service, so fetching them is exactly what the SSRF guard exists to prevent.
Solutions
- Serve the file from a publicly reachable host or pass the local file path directly to transcribe()
- If you control the media server, bind it to a real (non-localhost-resolving) hostname reachable from the machine
- Never feed agent-supplied URLs to this API without your own allowlist — the blocklist is deliberate but minimal
Example fix
# before
download_audio("http://localhost:8080/ep.m4a", out_dir) # SSRF blocked: internal host is not allowed
# after: local file takes the direct path
text = transcribe("/srv/media/ep.m4a") Defensive patterns
Strategy: validation
Validate before calling
_BLOCKED = {"localhost", "metadata.google.internal"}
def host_not_internal(host: str) -> bool:
h = host.strip().rstrip(".").lower()
return h not in _BLOCKED and not h.endswith(".localhost") Try / catch
from agent_reach.transcribe import TranscribeError
try:
transcribe(url)
except TranscribeError as e:
if "internal host" in str(e):
serve_locally_or_reject(url) # never 'fix' by bypassing the guard
raise Prevention
- Never point transcription at localhost or *.localhost — use local file paths instead
- Treat metadata.google.internal as an attack indicator in agent-facing logs
- Keep an allowlist of trusted media hosts in front of transcribe()
When it happens
Trigger: download_audio('http://localhost:8080/recording.m4a'), 'https://api.localhost/x', 'http://metadata.google.internal/computeMetadata/v1/...'. Dot-suffixed variants ('localhost.') are normalized first, so trailing-dot evasion also fails.
Common situations: Local e2e tests pointing the transcription pipeline at a dev server; agents on cloud VMs being tricked into reading the metadata endpoint (the attack this blocks); misconfigured env vars that default a media base URL to localhost.
Related errors
- only the V2EX HTTPS API is allowed
- SSRF blocked: encoded or ambiguous URL host
- SSRF blocked: only public http(s) URLs are allowed
- SSRF blocked: URL host is invalid
- gh hosts.yml 无法安全读取
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/3f21979b71199952.
Report an issue: GitHub.
Appendix: source
Thrown at agent_reach/transcribe.py:245
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")
try:
host = raw_host.encode("idna").decode("ascii").lower().rstrip(".")
except UnicodeError:
raise TranscribeError("SSRF blocked: URL host is invalid") from None
if host in _BLOCKED_HOSTS or host.endswith(".localhost"):
raise TranscribeError("SSRF blocked: internal host is not allowed")
if _is_private_ip(host):
raise TranscribeError("SSRF blocked: private/internal IP is not allowed")
def download_audio(url: str, out_dir: Path) -> Path:
"""Download audio with yt-dlp into out_dir; return the resulting file path."""
_assert_safe_public_url(url)
_require("yt-dlp")
template = out_dir / "source.%(ext)s"
_run(
[
"yt-dlp",
"-x",
"--audio-format",
"m4a",
"--audio-quality",
"0",
"--no-playlist",View on GitHub (pinned to 93ae1d18c3)