You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Both cases above can share domain agnostic machinery for URL validation.
The following requirements apply:
Composable: local addresses are perfectly fine for some deployments.
Validation should happen before the actual invocation and invocation should use "pinned" IP to protect from DNS rebinding.
Built-in rules: RequireScheme (to restrict HTTP(S)-only or HTTPS-only), BlockPrivateNetworks (with allowlist for deployments where using private networks is a legitimate use-case).
This issue scopes to UrlValidator only and should be a foundation for #975 and #786 where appropriate domain validators are going to be implemented.
flowchart TB
subgraph Wrappers["Domain wrappers (own which fields to validate + domain error type)"]
direction LR
PN["PushNotificationUrlValidator"]
AC["AgentCardUrlValidator"]
end
V["UrlValidator<br/>parse → resolve → run rules in order<br/>(rule raises = reject, returns = continue)"]
subgraph Rules["Composable rules"]
direction LR
RS["RequireScheme"]
BPN["BlockPrivateNetworks<br/>(allow_hosts, allow_cidrs)"]
CR["…custom…"]
end
PN --> V
AC --> V
V --> Rules
class PN,AC wrap
class V core
class RS,BPN,HD,CR rule
Loading
Sketch:
classInvalidUrlError(ValueError):
"""Raised by UrlValidator.validate when a URL is rejected."""classUrlValidationRule(ABC):
@abstractmethodasyncdefcheck(self, url: ResolvedUrl) ->None:
"""Raise InvalidUrlError to reject url."""classResolvedUrl:
raw: strparsed: SplitResultaddresses: tuple[IpAddress, ...]
classUrlValidator:
def__init__(
self,
rules: Sequence[UrlValidationRule] = (),
resolve: bool=True,
) ->None:
. . .
asyncdefvalidate(self, url: str) ->ResolvedUrl:
# Conditionally resolves IPs via getaddrinforesolved=awaitself._build(url)
# Just runs all rules one by one, they throw to stopforruleinself._rules:
awaitrule.check(resolved)
# Returns URL so that pinned address can be usedreturnresolved
Context
We have two places which can benefit from SSRF protection:
Description
Both cases above can share domain agnostic machinery for URL validation.
The following requirements apply:
RequireScheme(to restrict HTTP(S)-only or HTTPS-only),BlockPrivateNetworks(with allowlist for deployments where using private networks is a legitimate use-case).This issue scopes to
UrlValidatoronly and should be a foundation for #975 and #786 where appropriate domain validators are going to be implemented.flowchart TB subgraph Wrappers["Domain wrappers (own which fields to validate + domain error type)"] direction LR PN["PushNotificationUrlValidator"] AC["AgentCardUrlValidator"] end V["UrlValidator<br/>parse → resolve → run rules in order<br/>(rule raises = reject, returns = continue)"] subgraph Rules["Composable rules"] direction LR RS["RequireScheme"] BPN["BlockPrivateNetworks<br/>(allow_hosts, allow_cidrs)"] CR["…custom…"] end PN --> V AC --> V V --> Rules class PN,AC wrap class V core class RS,BPN,HD,CR ruleSketch: