microsoft/semantic-kernel · error · FunctionExecutionException
The request URI '{url}' is not allowed: host resolves to a {
Error message
The request URI '{url}' is not allowed: host resolves to a {category} address ({address}), which is blocked by default to prevent Server-Side Request Forgery (SSRF). To allow this URL, add it to server_url_validation_allowed_base_urls or set allow_private_network_access=True. What it means
Thrown when the host resolves to a non-public IP address. Categories blocked: loopback (127.0.0.0/8), RFC1918 private (10/8, 172.16/12, 192.168/16), link-local (169.254/16), unspecified (0/8), carrier-grade NAT, benchmarking, reserved, multicast, and IPv6 loopback/ULA/link-local/multicast/reserved. This is the core SSRF guard.
Source
Thrown at python/semantic_kernel/connectors/openapi_plugin/server_url_validator.py:186
) from exc
addresses: list[ipaddress.IPv4Address | ipaddress.IPv6Address] = []
seen_addresses: set[str] = set()
for family, _, _, _, sockaddr in addr_info:
if family not in (socket.AF_INET, socket.AF_INET6):
continue
address = ipaddress.ip_address(sockaddr[0])
address_string = str(address)
if address_string not in seen_addresses:
addresses.append(address)
seen_addresses.add(address_string)
return addresses
def _ensure_public_address(url: str, address: ipaddress.IPv4Address | ipaddress.IPv6Address) -> None:
blocked, category = try_categorize_non_public_address(address)
if blocked:
raise FunctionExecutionException(
f"The request URI '{url}' is not allowed: host resolves to a {category} address ({address}), "
"which is blocked by default to prevent Server-Side Request Forgery (SSRF). "
"To allow this URL, add it to server_url_validation_allowed_base_urls or set "
"allow_private_network_access=True."
)
def _try_classify_ipv4(address: ipaddress.IPv4Address) -> tuple[bool, str]:
b0, b1, b2, _ = address.packed
if b0 == 0:
return True, "unspecified"
if b0 == 10:
return True, "private (RFC1918)"
if b0 == 127:
return True, "loopback"
if b0 == 169 and b1 == 254:
return True, "link-local"View on GitHub (pinned to c028a0c7dc)
Solutions
- Add the specific trusted base URL to allowed_base_urls to bypass all host checks for that destination
- Set allow_private_network_access=True to skip the public-address check entirely (only when you fully trust and control the target)
- Ensure you are hitting a public hostname that resolves to a genuinely public IP
- Never allow untrusted/user-supplied URLs to reach internal or metadata addresses
Example fix
# before
options = ServerUrlValidationOptions() # default: blocks private addresses
await validate_server_url('https://internal.svc.cluster.local/api', options) # raises 1507
# after - explicitly trust the internal base
options = ServerUrlValidationOptions(allowed_base_urls=['https://internal.svc.cluster.local/api'])
await validate_server_url('https://internal.svc.cluster.local/api/run', options) Defensive patterns
Strategy: validation
Validate before calling
import ipaddress, socket
def host_is_public(host: str) -> bool:
# if host is already an IP
try:
ip = ipaddress.ip_address(host)
except ValueError:
try:
infos = socket.getaddrinfo(host, None)
except OSError:
return False
ips = [ipaddress.ip_address(i[4][0]) for i in infos if i[0] in (socket.AF_INET, socket.AF_INET6)]
else:
ips = [ip]
for ip in ips:
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_unspecified or ip.is_reserved or ip.is_multicast:
return False
return True
if not host_is_public(urlparse(url).hostname):
# either reject or add the base url to allowed_base_urls / set allow_private_network_access
... Try / catch
try:
await validate_server_url(url, options)
except FunctionExecutionException as e:
if 'blocked by default to prevent Server-Side Request Forgery' in str(e):
# add the trusted base url to allowed_base_urls, or set allow_private_network_access=True
... Prevention
- Never let untrusted/user-supplied URLs reach internal or metadata addresses
- Use allow_private_network_access=True only for destinations you fully control
- Prefer allow-listing specific trusted base URLs over broad private-network access
- Watch for DNS rebinding: the check resolves at request time, so recheck if URLs are dynamic
When it happens
Trigger: Server URL host resolves to 127.0.0.1, 10.x, 192.168.x, 169.254.169.254 (cloud metadata), fc00::/7, ::1, etc.; or a DNS rebinding attack that flips a public-looking name to a private IP at request time.
Common situations: Pointing at localhost/127.0.0.1 for local dev; reaching an internal service on a private IP; cloud metadata endpoint abuse (169.254.169.254); DNS rebinding from an attacker-controlled hostname.
Related errors
- The address '{address}' is not allowed for the '{operation.N
- The operation path resolves to '{requestAuthority}', which d
- The operation path resolves to '{requestPath}', which is out
- Path '{path}' contains a dot-segment, which could lead to pa
- The operation path resolves to '{request.scheme}://{request.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/f84525ea8cb38e8f.
Report an issue: GitHub.