{"id":"CVE-2026-46678","aliases":["EUVD-2026-50561","GHSA-cqp8-fcvh-x7r3","PYSEC-2026-2978","PYSEC-2026-2982","ROOT-APP-PYPI-CVE-2026-46678"],"status":"published","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"Pydantic AI is a Python agent framework for building Generative AI applications. In versions 1.56.0 through 1.98.0, when an application opts a URL into force_download='allow-local' (disabling the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64), exposing cloud IAM short-term credentials on dual-stack or translated networks. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580, whose remediation did not hold for IPv6-encoded forms of the metadata IPs. An application is affected only if it explicitly opts a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL influenced by untrusted input; it is not affected when using bundled integrations to ingest user input (Agent.to_web / clai web, VercelAIAdapter, AGUIAdapter / Agent.to_ag_ui), since they do not propagate force_download from external data, nor when downloading only from developer-controlled URLs. This issue has been fixed in version 1.99.0.","severity":{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.0038,"percentile":0.32462,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-918"],"published":"2026-05-21T21:35:18Z","modified":"2026-10-28T02:31:14Z","fixes":[{"ecosystem":"PyPI","package":"pydantic-ai","fixed_in":["1.99.0"],"sources":["ghsa","osv"]},{"ecosystem":"PyPI","package":"pydantic-ai-slim","fixed_in":["1.99.0"],"sources":["ghsa","osv"]},{"ecosystem":"Root:PyPI","package":"rootio-pydantic-ai-slim","fixed_in":["1.84.0+root.io.1","1.84.1+root.io.1","1.91.0+root.io.1","1.88.0+root.io.1"],"sources":["osv"]},{"ecosystem":"Root:PyPI","package":"pydantic-ai-slim","fixed_in":["1.84.0+aikido.1","1.84.1+aikido.1","1.91.0+aikido.1","1.88.0+aikido.1","1.84.0+aikido.2","1.88.0+aikido.2","1.84.1+aikido.2","1.91.0+aikido.2"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"pydantic-ai","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}]},{"source":"ghsa","ecosystem":"PyPI","package":"pydantic-ai-slim","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}]},{"source":"osv","ecosystem":"PyPI","package":"pydantic-ai","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}],"versions":["1.56.0","1.57.0","1.58.0","1.59.0","1.60.0","1.61.0","1.62.0","1.63.0","1.64.0","1.65.0","1.66.0","1.67.0","1.68.0","1.69.0","1.70.0","1.71.0","1.72.0","1.73.0","1.74.0","1.75.0","1.76.0","1.77.0","1.78.0","1.79.0","1.80.0","1.81.0","1.82.0","1.83.0","1.84.0","1.84.1","1.85.0","1.85.1","1.86.0","1.86.1","1.87.0","1.88.0","1.89.0","1.89.1","1.90.0","1.91.0","1.92.0","1.93.0","1.94.0","1.95.0","1.95.1","1.96.0","1.96.1","1.97.0","1.98.0"]},{"source":"osv","ecosystem":"PyPI","package":"pydantic-ai-slim","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}],"versions":["1.56.0","1.57.0","1.58.0","1.59.0","1.60.0","1.61.0","1.62.0","1.63.0","1.64.0","1.65.0","1.66.0","1.67.0","1.68.0","1.69.0","1.70.0","1.71.0","1.72.0","1.73.0","1.74.0","1.75.0","1.76.0","1.77.0","1.78.0","1.79.0","1.80.0","1.81.0","1.82.0","1.83.0","1.84.0","1.84.1","1.85.0","1.85.1","1.86.0","1.86.1","1.87.0","1.88.0","1.89.0","1.89.1","1.90.0","1.91.0","1.92.0","1.93.0","1.94.0","1.95.0","1.95.1","1.96.0","1.96.1","1.97.0","1.98.0"]},{"source":"osv","ecosystem":"PyPI","package":"pydantic-ai","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}],"versions":["1.56.0","1.57.0","1.58.0","1.59.0","1.60.0","1.61.0","1.62.0","1.63.0","1.64.0","1.65.0","1.66.0","1.67.0","1.68.0","1.69.0","1.70.0","1.71.0","1.72.0","1.73.0","1.74.0","1.75.0","1.76.0","1.77.0","1.78.0","1.79.0","1.80.0","1.81.0","1.82.0","1.83.0","1.84.0","1.84.1","1.85.0","1.85.1","1.86.0","1.86.1","1.87.0","1.88.0","1.89.0","1.89.1","1.90.0","1.91.0","1.92.0","1.93.0","1.94.0","1.95.0","1.95.1","1.96.0","1.96.1","1.97.0","1.98.0"]},{"source":"osv","ecosystem":"PyPI","package":"pydantic-ai-slim","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.56.0"},{"fixed":"1.99.0"}]}],"versions":["1.56.0","1.57.0","1.58.0","1.59.0","1.60.0","1.61.0","1.62.0","1.63.0","1.64.0","1.65.0","1.66.0","1.67.0","1.68.0","1.69.0","1.70.0","1.71.0","1.72.0","1.73.0","1.74.0","1.75.0","1.76.0","1.77.0","1.78.0","1.79.0","1.80.0","1.81.0","1.82.0","1.83.0","1.84.0","1.84.1","1.85.0","1.85.1","1.86.0","1.86.1","1.87.0","1.88.0","1.89.0","1.89.1","1.90.0","1.91.0","1.92.0","1.93.0","1.94.0","1.95.0","1.95.1","1.96.0","1.96.1","1.97.0","1.98.0"]},{"source":"osv","ecosystem":"Root:PyPI","package":"rootio-pydantic-ai-slim","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.84.0+root.io.1"},{"fixed":"1.84.1+root.io.1"},{"fixed":"1.91.0+root.io.1"},{"fixed":"1.88.0+root.io.1"}]}]},{"source":"osv","ecosystem":"Root:PyPI","package":"pydantic-ai-slim","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.84.0+aikido.1"},{"fixed":"1.84.1+aikido.1"},{"fixed":"1.91.0+aikido.1"},{"fixed":"1.88.0+aikido.1"},{"fixed":"1.84.0+aikido.2"},{"fixed":"1.88.0+aikido.2"},{"fixed":"1.84.1+aikido.2"},{"fixed":"1.91.0+aikido.2"}]}]}],"products":[{"vendor":"pydantic","product":"pydantic-ai"},{"vendor":"pydantic","product":"pydantic-ai-slim"},{"vendor":"pydantic","product":"pydantic_ai"}],"references":[{"url":"https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-cqp8-fcvh-x7r3","tags":["x_refsource_CONFIRM","Vendor Advisory","advisory","web"]},{"url":"https://github.com/pydantic/pydantic-ai/releases/tag/v1.99.0","tags":["x_refsource_MISC","Product","Release Notes","web"]},{"url":"https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3","tags":["web"]},{"url":"https://github.com/advisories/GHSA-cqp8-fcvh-x7r3","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/46xxx/CVE-2026-46678.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46678","tags":["advisory"]},{"url":"https://github.com/pydantic/pydantic-ai","tags":["package"]},{"url":"https://pypi.org/project/pydantic-ai","tags":["package"]},{"url":"https://pypi.org/project/pydantic-ai-slim","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-46678","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"Pydantic AI is a Python agent framework for building Generative AI applications. In versions 1.56.0 through 1.98.0, when an application opts a URL into force_download='allow-local' (disabling the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64), exposing cloud IAM short-term credentials on dual-stack or translated networks. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580, whose remediation did not hold for IPv6-encoded forms of the metadata IPs. An application is affected only if it explicitly opts a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL influenced by untrusted input; it is not affected when using bundled integrations to ingest user input (Agent.to_web / clai web, VercelAIAdapter, AGUIAdapter / Agent.to_ag_ui), since they do not propagate force_download from external data, nor when downloading only from developer-controlled URLs. This issue has been fixed in version 1.99.0.","status":"published","published":"2026-07-29T20:16:45.986Z","modified":"2026-07-30T14:37:27.447Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T13:47:06.353366Z"}],"euvd":[{"id":"EUVD-2026-50561","description":"Pydantic AI is a Python agent framework for building Generative AI applications. In versions 1.56.0 through 1.98.0, when an application opts a URL into force_download='allow-local' (disabling the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64), exposing cloud IAM short-term credentials on dual-stack or translated networks. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580, whose remediation did not hold for IPv6-encoded forms of the metadata IPs. An application is affected only if it explicitly opts a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL influenced by untrusted input; it is not affected when using bundled integrations to ingest user input (Agent.to_web / clai web, VercelAIAdapter, AGUIAdapter / Agent.to_ag_ui), since they do not propagate force_download from external data, nor when downloading only from developer-controlled URLs. This issue has been fixed in version 1.99.0.","status":"published","published":"2026-07-29T20:16:45Z","modified":"2026-07-30T14:37:27Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"updated_at":"2026-11-02T18:02:28.93005Z"}],"ghsa":[{"id":"GHSA-cqp8-fcvh-x7r3","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"## Summary\n\nWhen an application using Pydantic AI opts a URL into `force_download='allow-local'` (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials.\n\nThis is an incomplete fix of [GHSA-2jrp-274c-jhv3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3) / [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that \"cloud metadata endpoints are always blocked, even with `allow-local`.\" That guarantee did not hold for IPv6-encoded forms of the metadata IPs.\n\n## Severity\n\nSame impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into `allow-local` on a URL influenced by untrusted input.\n\n## Who Is Affected\n\nApplications are affected **only if** they explicitly opt for `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) into `force_download='allow-local'` on a URL that is, or could be, influenced by untrusted input.\n\nApplications are **not** affected if they use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data:\n\n- `Agent.to_web` / `clai web`\n- `VercelAIAdapter`\n- `AGUIAdapter` / `Agent.to_ag_ui`\n\nApplications that only download from developer-controlled URLs are not affected.\n\n## Remediation\n\nUpgrade to `1.99.0` or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges.\n\n## Workaround for Unpatched Versions\n\nAvoid passing `force_download='allow-local'` on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the `FileUrl`.\n\n## Credits\n\nReported by [j0hndo](mailto:dohyun4466@gmail.com).","status":"published","published":"2026-05-21T21:35:18Z","modified":"2026-05-21T21:35:19Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:40:13.628377Z"}],"nvd":[{"id":"CVE-2026-46678","description":"Pydantic AI is a Python agent framework for building Generative AI applications. In versions 1.56.0 through 1.98.0, when an application opts a URL into force_download='allow-local' (disabling the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64), exposing cloud IAM short-term credentials on dual-stack or translated networks. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580, whose remediation did not hold for IPv6-encoded forms of the metadata IPs. An application is affected only if it explicitly opts a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL influenced by untrusted input; it is not affected when using bundled integrations to ingest user input (Agent.to_web / clai web, VercelAIAdapter, AGUIAdapter / Agent.to_ag_ui), since they do not propagate force_download from external data, nor when downloading only from developer-controlled URLs. This issue has been fixed in version 1.99.0.","status":"published","published":"2026-07-29T21:17:47.04Z","modified":"2026-08-04T13:52:14.037Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"secondary"},{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N","level":"medium","assessor":"primary"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T14:12:33.629616Z"}],"osv":[{"id":"CVE-2026-46678","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"Pydantic AI is a Python agent framework for building Generative AI applications. In versions 1.56.0 through 1.98.0, when an application opts a URL into force_download='allow-local' (disabling the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64), exposing cloud IAM short-term credentials on dual-stack or translated networks. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580, whose remediation did not hold for IPv6-encoded forms of the metadata IPs. An application is affected only if it explicitly opts a FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL influenced by untrusted input; it is not affected when using bundled integrations to ingest user input (Agent.to_web / clai web, VercelAIAdapter, AGUIAdapter / Agent.to_ag_ui), since they do not propagate force_download from external data, nor when downloading only from developer-controlled URLs. This issue has been fixed in version 1.99.0.","status":"published","published":"2026-07-29T20:16:45.986Z","modified":"2026-10-28T02:31:14.373033258Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:45:06.231145Z"},{"id":"GHSA-cqp8-fcvh-x7r3","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"## Summary\n\nWhen an application using Pydantic AI opts a URL into `force_download='allow-local'` (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials.\n\nThis is an incomplete fix of [GHSA-2jrp-274c-jhv3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3) / [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that \"cloud metadata endpoints are always blocked, even with `allow-local`.\" That guarantee did not hold for IPv6-encoded forms of the metadata IPs.\n\n## Severity\n\nSame impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into `allow-local` on a URL influenced by untrusted input.\n\n## Who Is Affected\n\nApplications are affected **only if** they explicitly opt for `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) into `force_download='allow-local'` on a URL that is, or could be, influenced by untrusted input.\n\nApplications are **not** affected if they use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data:\n\n- `Agent.to_web` / `clai web`\n- `VercelAIAdapter`\n- `AGUIAdapter` / `Agent.to_ag_ui`\n\nApplications that only download from developer-controlled URLs are not affected.\n\n## Remediation\n\nUpgrade to `1.99.0` or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges.\n\n## Workaround for Unpatched Versions\n\nAvoid passing `force_download='allow-local'` on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the `FileUrl`.\n\n## Credits\n\nReported by [j0hndo](mailto:dohyun4466@gmail.com).","status":"published","published":"2026-05-21T21:35:18Z","modified":"2026-07-13T16:43:22.591175364Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-918"],"updated_at":"2026-11-02T15:46:45.28161Z"},{"id":"PYSEC-2026-2978","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"## Summary\n\nWhen an application using Pydantic AI opts a URL into `force_download='allow-local'` (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials.\n\nThis is an incomplete fix of [GHSA-2jrp-274c-jhv3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3) / [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that \"cloud metadata endpoints are always blocked, even with `allow-local`.\" That guarantee did not hold for IPv6-encoded forms of the metadata IPs.\n\n## Severity\n\nSame impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into `allow-local` on a URL influenced by untrusted input.\n\n## Who Is Affected\n\nApplications are affected **only if** they explicitly opt for `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) into `force_download='allow-local'` on a URL that is, or could be, influenced by untrusted input.\n\nApplications are **not** affected if they use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data:\n\n- `Agent.to_web` / `clai web`\n- `VercelAIAdapter`\n- `AGUIAdapter` / `Agent.to_ag_ui`\n\nApplications that only download from developer-controlled URLs are not affected.\n\n## Remediation\n\nUpgrade to `1.99.0` or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges.\n\n## Workaround for Unpatched Versions\n\nAvoid passing `force_download='allow-local'` on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the `FileUrl`.\n\n## Credits\n\nReported by [j0hndo](mailto:dohyun4466@gmail.com).","status":"published","published":"2026-07-13T15:19:11.194219Z","modified":"2026-07-13T16:43:22.591175364Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:56.429374Z"},{"id":"PYSEC-2026-2982","title":"Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)","description":"## Summary\n\nWhen an application using Pydantic AI opts a URL into `force_download='allow-local'` (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials.\n\nThis is an incomplete fix of [GHSA-2jrp-274c-jhv3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3) / [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that \"cloud metadata endpoints are always blocked, even with `allow-local`.\" That guarantee did not hold for IPv6-encoded forms of the metadata IPs.\n\n## Severity\n\nSame impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into `allow-local` on a URL influenced by untrusted input.\n\n## Who Is Affected\n\nApplications are affected **only if** they explicitly opt for `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) into `force_download='allow-local'` on a URL that is, or could be, influenced by untrusted input.\n\nApplications are **not** affected if they use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data:\n\n- `Agent.to_web` / `clai web`\n- `VercelAIAdapter`\n- `AGUIAdapter` / `Agent.to_ag_ui`\n\nApplications that only download from developer-controlled URLs are not affected.\n\n## Remediation\n\nUpgrade to `1.99.0` or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges.\n\n## Workaround for Unpatched Versions\n\nAvoid passing `force_download='allow-local'` on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the `FileUrl`.\n\n## Credits\n\nReported by [j0hndo](mailto:dohyun4466@gmail.com).","status":"published","published":"2026-07-13T15:19:11.3479Z","modified":"2026-07-13T16:43:22.591175364Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"updated_at":"2026-11-02T15:52:56.429374Z"},{"id":"ROOT-APP-PYPI-CVE-2026-46678","title":"CVE-2026-46678 in rootio-pydantic-ai-slim - Patched by Root","description":"Root has patched CVE-2026-46678 in the rootio-pydantic-ai-slim package for Root:PyPI. Multiple fixed versions available.","status":"published","published":"2026-08-03T06:38:38Z","modified":"2026-08-03T13:45:13.099720286Z","updated_at":"2026-11-02T15:53:28.259095Z"}]}}
