microsoft/semantic-kernel · error · FunctionExecutionException
The request URI '{url}' is not allowed. It does not match an
Error message
The request URI '{url}' is not allowed. It does not match any of the allowed base URLs. What it means
Thrown by validate_server_url when you have configured a non-empty allowed_base_urls allow-list but the fully resolved request URL does not match any entry. Matching requires scheme, hostname, port, and path-prefix to all align (host/path compared case-insensitively). This is the explicit allow-list enforcement path of the OpenAPI plugin SSRF guard.
Source
Thrown at python/semantic_kernel/connectors/openapi_plugin/server_url_validator.py:50
async def validate_server_url(
url: str,
options: ServerUrlValidationOptions | None = None,
dns_resolver: DnsResolver | None = None,
) -> None:
"""Validate a fully resolved OpenAPI operation URL against the supplied policy."""
options = options or ServerUrlValidationOptions()
try:
parsed_url = _parse_absolute_url(url)
except ValueError as exc:
raise FunctionExecutionException(
f"The request URI '{url}' is not allowed because it is not a valid absolute URI."
) from exc
if _matches_allowed_base_url(parsed_url, options.allowed_base_urls):
return
if options.allowed_base_urls:
raise FunctionExecutionException(
f"The request URI '{url}' is not allowed. It does not match any of the allowed base URLs."
)
if parsed_url.scheme.lower() != DEFAULT_ALLOWED_SCHEME:
raise FunctionExecutionException(
f"The request URI scheme '{parsed_url.scheme}' is not allowed. "
f"Only '{DEFAULT_ALLOWED_SCHEME}' is permitted by default. "
"To allow this URL, add it to server_url_validation_allowed_base_urls."
)
if options.allow_private_network_access:
return
await _ensure_public_host(parsed_url, dns_resolver)
def try_categorize_non_public_address(
address: str | ipaddress.IPv4Address | ipaddress.IPv6Address,View on GitHub (pinned to c028a0c7dc)
Solutions
- Add the operation's exact base URL (scheme + host + port + path prefix) to ServerUrlValidationOptions.allowed_base_urls or the server_url_validation_allowed_base_urls setting
- Verify scheme, hostname, port, and path-prefix all match an allowed entry; host and path matching is case-insensitive
- Confirm the OpenAPI spec's servers entry matches what you allow-listed
- If the destination is legitimately trusted and private access is intended, set allow_private_network_access=True instead of widening the allow-list carelessly
Example fix
# before
options = ServerUrlValidationOptions(allowed_base_urls=['https://api.example.com'])
await validate_server_url('https://api.example.com/v2/search', options) # path /v2 not allowed
# after
options = ServerUrlValidationOptions(allowed_base_urls=['https://api.example.com'])
await validate_server_url('https://api.example.com/v2/search', options) # base path '/' matches
# or, allow only the v2 API:
options = ServerUrlValidationOptions(allowed_base_urls=['https://api.example.com/v2']) Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def url_matches_allowed(url: str, allowed_base_urls: list[str]) -> bool:
def parts(u: str):
p = urlparse(u)
port = p.port or (443 if p.scheme.lower() == 'https' else 80 if p.scheme.lower() == 'http' else None)
return p.scheme.lower(), (p.hostname or '').lower(), port, (p.path or '/')
u = parts(url)
for base in allowed_base_urls:
b = parts(base)
if u[0] == b[0] and u[1] == b[1] and u[2] == b[2] and (u[3] == b[3] or u[3].startswith(b[3].rstrip('/') + '/')):
return True
return False
# call before validate_server_url
if not url_matches_allowed(op_url, options.allowed_base_urls):
raise ValueError(f'{op_url} not in allow-list') Try / catch
from semantic_kernel.exceptions.function_exceptions import FunctionExecutionException
try:
await validate_server_url(url, options)
except FunctionExecutionException as e:
if 'does not match any of the allowed base URLs' in str(e):
# add url base to options.allowed_base_urls or reject the operation
... Prevention
- Maintain allowed_base_urls as the complete scheme+host+port+path-prefix of every legitimate destination
- When adding a new OpenAPI endpoint on a new host, update the allow-list in the same change
- Compare host and path case-insensitively when configuring the allow-list
When it happens
Trigger: An OpenAPI plugin operation resolves to a URL outside every configured base. Example: allowed_base_urls=['https://api.example.com/v1'] but an operation's server URL is https://api.other.com/v1/foo, or the path lies outside the /v1 prefix, or the scheme/port differ.
Common situations: OpenAPI spec lists a server URL that differs from the allow-listed base; a new endpoint lives on a different domain/subdomain; the allowed base URL was mistyped or is missing its path prefix; port mismatch (base on 443, request on 8443).
Related errors
- The request URI scheme '{parsed_url.scheme}' is not allowed.
- 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/ed0f16d16cb83a3e.
Report an issue: GitHub.