Add shared OutboundHostValidator anti-SSRF control - #542
Add shared OutboundHostValidator anti-SSRF control#542Rodrigo Brandão (rodrigobr-msft) wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in outbound host allow-list validator intended to mitigate SSRF risks by restricting which hosts the SDK will make server-side outbound calls to (starting with validation of Activity.service_url during inbound request processing in the core HTTP adapter). It also wires the validator through the FastAPI and aiohttp cloud adapters and exposes it from the hosting-core package API surface.
Changes:
- Added
OutboundHostValidatorto centralize outbound host allow-list checks (with default Microsoft host suffixes). - Integrated service URL validation into
HttpAdapterBase.process_request()to block disallowed/mismatched service URLs when enabled. - Updated FastAPI/aiohttp CloudAdapter constructors to accept and pass through an optional
host_validator, and exported the type from hosting-core.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/outbound_host_validator.py | Introduces the shared host allow-list validator used to gate outbound destinations. |
| libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py | Applies host validation to inbound activities’ service_url prior to processing. |
| libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/init.py | Exposes OutboundHostValidator as part of the public hosting-core API. |
| libraries/microsoft-agents-hosting-fastapi/microsoft_agents/hosting/fastapi/cloud_adapter.py | Plumbs an optional host validator into the FastAPI adapter. |
| libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py | Plumbs an optional host validator into the aiohttp adapter. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Suppressed comments (4)
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/outbound_host_validator.py:91
OutboundHostValidator.is_allowedis implemented to handleNone(it denies when enabled, allows when disabled), and tests passNone, but the type annotation doesn’t allow it. This makes the public API awkward for typed callers.
def is_allowed(self, url: str | URL) -> bool:
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/outbound_host_validator.py:27
- Type hints don’t match actual behavior:
_try_create_urlcurrently acceptsNoneat runtime (and callers/tests passNone), but the signature only allowsstr | URL. This will produce type-checking errors for valid usage.
This issue also appears on line 91 of the same file.
def _try_create_url(url: str | URL) -> URL | None:
"""Attempts to create a URL object from the given string or URL.
:param url: The URL string or URL object to create.
:return: A URL object if successful, None otherwise.
"""
try:
return URL(url) if isinstance(url, str) else url
except (ValueError, TypeError):
return None
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/outbound_host_validator.py:114
- Minor inefficiency:
host.casefold()is recomputed on every loop iteration over suffixes. Casefold once before the loop to keep the logic clearer and avoid repeated work.
for suffix in self._suffixes:
host = host.casefold()
if host == suffix or host.endswith("." + suffix):
return True
libraries/microsoft-agents-hosting-core/setup.py:22
- The repo’s
setup.pydependency specs consistently avoid upper bounds (e.g.,libraries/microsoft-agents-hosting-fastapi/setup.py:14-18,libraries/microsoft-agents-hosting-aiohttp/setup.py:14-17). Addingyarl<2.0here is a new constraint that can cause avoidable resolver conflicts. If there isn’t a known breaking change you’re explicitly avoiding, consider aligning with the existing convention.
"aiohttp>=3.11.11",
"yarl>=1.17.0,<2.0",
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Suppressed comments (7)
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py:196
- Use
AuthenticationConstants.SERVICE_URL_CLAIMinstead of the literal "serviceurl" to avoid duplicating claim-name strings.
claims_service_url = claims_identity.get_claim_value("serviceurl")
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py:25
_validate_service_urluses a hard-coded claim type string ("serviceurl"). There’s already anAuthenticationConstants.SERVICE_URL_CLAIMconstant in the authorization module; using it avoids drift if the claim name ever changes.
This issue also appears on line 196 of the same file.
from .rest_channel_service_client_factory import RestChannelServiceClientFactory
from .turn_context import TurnContext
from .outbound_host_validator import OutboundHostValidator, _try_create_url
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py:207
self._host_validatoris always set in__init__(defaults toOutboundHostValidator()), so theself._host_validator and ...portion is redundant and can be simplified.
if self._host_validator and self._host_validator.enabled:
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py:141
- A new early-return path was added when the service URL is denied by the host validator.
tests/hosting_core/telemetry/test_http_adapter_telemetry.pyhas thorough coverage for otherprocess_requestbranches; adding a case for the host-validator denial would help ensure spans/metrics stay correct for this new path.
if not self._validate_service_url(claims_identity, activity):
return HttpResponseFactory.unauthorized(
"Service URL is not allowed by the host validator."
)
libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/_http_adapter_base.py:46
host_validatorwas added to the initializer, but the docstring doesn’t mention it. Documenting the parameter will make this security control discoverable for adapter implementers/users.
"""Initialize the HTTP adapter.
libraries/microsoft-agents-hosting-fastapi/microsoft_agents/hosting/fastapi/cloud_adapter.py:35
- The constructor gained a
host_validatorparameter, but it’s not documented in the docstring. Adding it helps users discover and correctly configure outbound host validation.
"""
Initializes a new instance of the CloudAdapter class.
libraries/microsoft-agents-hosting-aiohttp/microsoft_agents/hosting/aiohttp/cloud_adapter.py:34
- The constructor gained a
host_validatorparameter, but it’s not documented in the docstring. Adding it helps users discover and correctly configure outbound host validation.
"""
Initializes a new instance of the CloudAdapter class.
This pull request introduces a new outbound host validation mechanism to the Microsoft Agents Hosting SDK, enhancing security by ensuring that outbound requests are only made to allowed hosts. The main changes include adding the
OutboundHostValidatorclass, integrating host validation into the HTTP adapter base, and updating both the FastAPI and Aiohttp cloud adapters to support host validation.Security: Outbound Host Validation
OutboundHostValidatorclass (outbound_host_validator.py) to centralize logic for validating outbound URLs against a configurable allow-list of host suffixes, with support for default Microsoft service hosts. (libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/outbound_host_validator.pyR1-R116)_http_adapter_base.py): outbound requests are now checked against the validator, and unauthorized requests are blocked with appropriate responses. ([1] [2] [3] [4])Adapter Integration
cloud_adapter.pyfiles for FastAPI and Aiohttp to accept an optionalhost_validatorparameter and pass it to the base adapter, enabling host validation in these hosting environments. ([1] [2] [3] [4] [5] [6])Core Module Export
OutboundHostValidatorfrom the core module’s__init__.py, making it available for external use and configuration. ([1] [2])These changes collectively improve the security posture of the SDK by helping prevent SSRF (Server-Side Request Forgery) attacks and giving developers fine-grained control over which hosts the agent can communicate with.