Pydantic AI 1.102.0 Patches an SSRF Bypass, and the Real Lesson Is That Agent URL Fetching Is Network Security Now
There is a genre of security bug that looks too narrow to matter right up until it lands in the middle of the architecture everyone is rushing to ship. Pydantic AI’s v1.102.0 release is one of those. The advisory is not a cinematic breach. It is a medium-severity SSRF bypass, gated behind a specific opt-in setting, dependent on particular IPv6 transition forms, and likely irrelevant to many default deployments. That is precisely why it is worth reading: it shows how quickly “let the agent fetch a file URL” becomes network security engineering.
The patched issue is GHSA-cg7w-rg45-pc59, a CVSS 6.8 server-side request forgery vulnerability classified as CWE-918. The affected ranges are pydantic-ai and pydantic-ai-slim from >=1.56.0, <1.102.0 and from >=2.0.0b1, <2.0.0b3. The fixed versions are 1.102.0 and 2.0.0b3.
The scope is important. Pydantic AI says the vulnerable path requires an application to explicitly opt a FileUrl into force_download='allow-local', including media URL subclasses such as ImageUrl, AudioUrl, VideoUrl, or DocumentUrl. The URL also has to be, or become, influenced by untrusted input, and the runtime network has to route the affected address forms. That is a long precondition chain. It is also exactly the kind of chain production agent systems accidentally create when product teams add “upload by URL,” “summarize this document,” or “inspect this image” to a model-driven workflow.
The bug is in the uncomfortable gap between text validation and network reality. Prior protections blocked obvious private and metadata targets, but the new bypass encoded cloud-metadata IPv4 addresses inside IPv6 transition forms the old remediation did not decode before policy checks. The advisory calls out IPv4-compatible IPv6 addresses like ::a.b.c.d, NAT64 local-use prefixes such as 64:ff9b:1::/48, operator-chosen NAT64 prefixes, ISATAP, and defense-in-depth coverage for deprecated forms including Teredo. PR #5596 expands validation so embedded IPv4 addresses are resolved before private, internal, and cloud-metadata blocklists are applied.
URL fetching is no longer a helper function
The industry keeps treating SSRF as a web-app class from the pre-agent era: user supplies URL, server fetches URL, attacker points server at metadata endpoint. Agent frameworks make that model messier. The model may decide when to fetch. It may transform a user request into a URL-bearing object. It may pass typed media through adapters that look safe because they are structured. It may run in a cloud container with metadata endpoints one hop away from credentials. The user did not click anything, but the system still made a network request on their behalf.
That means URL policy belongs in the agent runtime, not just at the application edge. A builder can no longer say “we blocked 169.254.169.254” and call the review done. The policy has to understand DNS normalization, trailing root dots, IPv4-in-IPv6 representations, NAT64, provider metadata endpoints, and deployment-specific routes. If the model can influence a URL and the runtime can fetch it, network semantics become part of the prompt-to-tool security boundary.
Pydantic AI’s release reinforces this with another fix: PR #5592 corrects exact-match hostname policy in WebFetchTool and WebFetchLocalTool. A hostname like evil.com. could bypass blocked_domains=['evil.com'], while example.com. could be rejected even though DNS treats the trailing-root-dot form as equivalent. That is not a glamorous agent feature. It is the kind of normalization bug that decides whether your allowlist is policy or theater.
There is a second thread in v1.102.0: provider behavior is becoming runtime policy too. PR #5580 restores expected Bedrock behavior after the BedrockJsonSchemaTransformer auto-promoted strict=None tools to strict=True. That silently broke agents with more than roughly 20 tools because Bedrock and Anthropic cap strict tools at 20 per request. The fix also drops toolSpec.strict with a warning when older bundled botocore versions would reject it, a scenario common in AWS Lambda-style environments.
This matters because many teams still think of “strict tools” as a model-quality knob. In practice it is a provider contract with hard limits, SDK version dependencies, and failure modes that look like agent weirdness. If a framework silently changes strictness across 21 tools, the developer sees a broken workflow, not a clean policy decision. Good framework behavior here is not to pretend all providers are the same; it is to model their differences loudly enough that operators can reason about them.
PR #5582 fits the same pattern by disabling native structured output for Claude Opus 4.7 through Bedrock because the direct Anthropic API capability did not carry through to Bedrock Runtime structured output. That distinction sounds small until you are debugging why a capability worked in one environment and failed in another using “the same model.” In 2026, “same model” is not a sufficient runtime invariant. The path to the model matters.
Practitioners should treat this as a concrete checklist, not just an upgrade notice. First, upgrade to pydantic-ai>=1.102.0, or 2.0.0b3 if you are testing the v2 beta. Second, search your codebase for force_download='allow-local' and review every call site as if it were a network egress permission. Third, add regression tests for cloud metadata endpoints expressed through IPv6 transition forms and for trailing-dot hostnames in both blocked and allowed domain rules. Fourth, if you run on Bedrock, test agents with large tool sets and verify strict-tool behavior explicitly rather than assuming the SDK will infer the right thing.
The broader lesson is that agent framework security is converging with old-fashioned infrastructure security. The model loop may be novel, but the failure modes are painfully familiar: ambiguous URL parsing, provider-specific constraints, stale SDKs, hidden network routes, and policy encoded as string comparison. The difference is that agents connect those failure modes to autonomous action. That raises the bar.
Pydantic AI handled this release well: narrow scope, exact affected ranges, patched beta and stable lines, explicit unaffected integrations, and enough technical detail for serious teams to audit their exposure. The vulnerability may not hit most deployments. The pattern absolutely will.
Sources: Pydantic AI v1.102.0 release, GitHub security advisory, PR #5596, PR #5592, PR #5580.