Skip to content

Add shared OutboundHostValidator anti-SSRF control - #542

Closed
Rodrigo Brandão (rodrigobr-msft) wants to merge 5 commits into
mainfrom
users/robrandao/ssrf
Closed

Add shared OutboundHostValidator anti-SSRF control#542
Rodrigo Brandão (rodrigobr-msft) wants to merge 5 commits into
mainfrom
users/robrandao/ssrf

Conversation

@rodrigobr-msft

Copy link
Copy Markdown
Contributor

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 OutboundHostValidator class, 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

Adapter Integration

  • Updated both cloud_adapter.py files for FastAPI and Aiohttp to accept an optional host_validator parameter and pass it to the base adapter, enabling host validation in these hosting environments. ([1] [2] [3] [4] [5] [6])

Core Module Export

  • Exported OutboundHostValidator from 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.

Copilot AI lite review requested due to automatic review settings August 17, 2026 16:33
@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) marked this pull request as ready for review August 17, 2026 16:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 OutboundHostValidator to 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.

Copilot AI review requested due to automatic review settings August 17, 2026 17:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_allowed is implemented to handle None (it denies when enabled, allows when disabled), and tests pass None, 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_url currently accepts None at runtime (and callers/tests pass None), but the signature only allows str | 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.py dependency 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). Adding yarl<2.0 here 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",

Copilot AI review requested due to automatic review settings August 17, 2026 17:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_CLAIM instead 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_url uses a hard-coded claim type string ("serviceurl"). There’s already an AuthenticationConstants.SERVICE_URL_CLAIM constant 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_validator is always set in __init__ (defaults to OutboundHostValidator()), so the self._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.py has thorough coverage for other process_request branches; 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_validator was 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_validator parameter, 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_validator parameter, 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants