Aug 13, 2026·7 min read·17 visits
A Confused Deputy SSRF vulnerability in Pydantic AI UI adapters allows remote, unauthenticated attackers to retrieve and exfiltrate private cloud storage files by injecting manipulated metadata structures into client-submitted message histories.
A Server-Side Request Forgery (SSRF) / Confused Deputy vulnerability has been identified in Pydantic AI UI Adapters (such as VercelAIAdapter). Under certain conditions, a malicious client can supply manipulated message history with provider metadata that forces the server to resolve files within privileged cloud environments (AWS S3, Google Cloud Storage) or model providers. This occurs because the adapters deserialize client-provided metadata structures directly into UploadedFile instances without validation, which are subsequently fetched using high-privilege server credentials.
Pydantic AI is a pythonic agent framework built on Pydantic to simplify Generative AI application development. Among its features, it provides UI adapters like VercelAIAdapter and AGUIAdapter to ease integrations with frontend protocol standards (e.g., the Vercel AI SDK). These adapters act as intermediaries, translating standard external client JSON payloads containing chat histories into internal message models like ModelRequest and ModelResponse structures.
When processing message history, frontend protocols often allow users to include file attachments. The server-side UI adapters must deserialize these attachment records into a structured format before passing them to the language model provider. Inside the vulnerable versions, the library parsed metadata elements (such as providerMetadata fields) to reconstruct representation structures of uploaded assets. Specifically, it mapped files to instances of the UploadedFile class.
This architecture exposes an attack surface because the deserializer failed to distinguish between client-uploaded files and server-side assets. While standard FileUrl strings were checked against an explicit allowlist of valid URL schemes (defaulting to HTTP and HTTPS), parameters matching UploadedFile bypassed this filter entirely. Consequently, a client-supplied identifier could represent file systems, private storage buckets, or internal vendor resources, leading directly to a Server-Side Request Forgery (SSRF) condition.
The root cause of this vulnerability lies in the improper trust boundary validation within the UI adapters' message-parsing logic. Specifically, the adapters trusted the structure of the JSON-serialized metadata sent directly by the untrusted web client. If a client sent a message payload containing a providerMetadata object under the pydantic_ai namespace, the deserialization logic implicitly trusted this input to populate the parameters of an UploadedFile instance.
An UploadedFile structure can point directly to external, restricted assets using a model-provider file ID or a raw cloud storage URI, such as s3:// or gs://. Because the library lacked a verification routine for client-submitted file metadata, these references were passed unchanged downstream. When the Pydantic AI agent initiated a request to the model provider (e.g., AWS Bedrock or OpenAI), it supplied the structured UploadedFile references to be processed by the LLM.
At this juncture, the system operates as a classic Confused Deputy. The model provider, acting on behalf of the server-side application, resolves the cloud-storage URI or file ID using the server's high-privilege context, such as AWS IAM instance profiles, service account credentials, or provider API keys. The server does not validate whether the active client session has the authorization to access that specific asset. If the storage asset exists and the server credentials have read access, the file contents are fetched, ingested into the LLM context, and ultimately leaked back to the client.
The fix for this vulnerability was introduced in pull request #5772. The core remediation strategy forces the UI adapters to strip and ignore any client-submitted UploadedFile references by default, unless the system is explicitly configured with a new security parameter: preserve_file_data = True.
In pydantic_ai_slim/pydantic_ai/ui/_adapter.py, the base UIAdapter class was updated to declare and default this property:
# Base UIAdapter updates
preserve_file_data: bool = False
"""Whether to keep UploadedFile items from client-submitted messages.
Defaults to False. By default, UploadedFile items in client-submitted messages are
dropped with a warning before the messages are passed to the agent...
"""The message sanitization routine (sanitize_messages) was updated to track dropped uploaded file providers and raise a warning to alert administrators of potential exploitation or misconfigurations. The inner sanitization of user content demonstrates how the validation logic was altered:
def _filter_user_content(
self,
content: Sequence[UserContent],
disallowed_schemes: set[str],
reset_force_download_values: set[ForceDownloadMode],
dropped_uploaded_file_providers: set[str],
) -> list[UserContent]:
filtered: list[UserContent] = []
for item in content:
if isinstance(item, FileUrl):
# Checks URL schemes
scheme = urlparse(item.url).scheme.lower()
if scheme not in self.allowed_file_url_schemes:
disallowed_schemes.add(scheme)
continue
item = self._sanitize_file_url(item, reset_force_download_values)
# FIX: Check if UploadedFile structure is supplied
elif isinstance(item, UploadedFile) and not self.preserve_file_data:
# Record the dropped file provider and omit from the payload
dropped_uploaded_file_providers.add(item.provider_name)
continue
filtered.append(item)
return filteredAdditionally, identical logic was added inside _sanitize_tool_return_content to prevent nested file structures within tool returns from bypassing the security filter. If preserve_file_data is configured to True, the library delegates trust entirely to the frontend configuration, indicating that the developer has separately implemented authorization mechanisms or operates within a trusted, authenticated perimeter.
Exploitation of CVE-2026-54249 does not require authentication to the backend model provider, but requires access to the public endpoint exposing the UI adapter. The attack relies on guessing or obtaining a valid cloud storage identifier or provider file ID that the backend's identity is authorized to read.
An attacker begins by sending an HTTP POST request representing a user message to the endpoint mapped to the UI adapter. The message content urges the LLM to read and output the details of a file. In the payload, the attacker defines a parts array where they inject a standard URL, but override the providerMetadata dictionary with target parameters:
{
"role": "user",
"content": "Verify and summarize this file for me.",
"parts": [
{
"type": "file",
"mediaType": "application/pdf",
"url": "https://legitimate.example.com/placeholder.pdf",
"providerMetadata": {
"pydantic_ai": {
"file_id": "s3://internal-company-confidential/salaries-2026.pdf",
"provider_name": "bedrock"
}
}
}
]
}Upon receiving the request, the server translates the payload. Because the client has structured the providerMetadata to mimic a legitimate file upload, the adapter translates this into a model-request container with an UploadedFile object targeting the restricted S3 URI. The backend agent executes the model request; Bedrock accesses the cloud object using the server's IAM credentials, processes the PDF, and the model streams the summary containing sensitive data back to the attacker.
The security impact of CVE-2026-54249 is classified as a High-severity confidentiality compromise, receiving a CVSS v3.1 base score of 6.8. The attack complexity is rated as High because the attacker must successfully identify or guess valid target cloud-storage URIs or file IDs to execute the payload. The vulnerability requires no client interaction and can be executed over the network by an unauthenticated attacker, yielding full read access to any storage resource accessible by the server's execution context.
The scope is changed (S:C) because the exploit enables an attacker to cross security boundaries—moving from the public application interface into internal storage structures (e.g., private Amazon S3 buckets or Google Cloud Storage) that are isolated from the web. The integrity and availability of the system remain unaffected, as the vulnerability does not provide direct file write or deletion permissions.
To fully address this vulnerability, security teams must apply immediate remediation controls across application code, infrastructure privileges, and runtime configurations.
Upgrading the Pydantic AI library is the primary fix. All systems using pydantic-ai or pydantic-ai-slim must be updated to version 1.106.0 or 2.0.0b6 or higher. These patched versions automatically sanitize client-provided data and exclude unsafe UploadedFile objects by default.
If upgrading is delayed, developers must ensure that UI adapters are configured in a highly restrictive environment. Avoid setting preserve_file_data = True unless the frontend has implemented rigorous file ID and user authorization mapping. Furthermore, execute the Principle of Least Privilege for all server roles. Restrict AWS IAM and Google Cloud service account roles associated with the application servers, ensuring they only have read privileges to bucket directories strictly required for public uploads, and explicitly denying access to sensitive or administrative Buckets.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
pydantic-ai Pydantic | >= 1.65.0, < 1.106.0 | 1.106.0 |
pydantic-ai-slim Pydantic | >= 1.65.0, < 1.106.0 | 1.106.0 |
pydantic-ai Pydantic | >= 2.0.0b1, < 2.0.0b6 | 2.0.0b6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network |
| CVSS v3.1 Score | 6.8 |
| EPSS Score | 0.00197 |
| Impact | Partial Confidentiality Loss (High) |
| Exploit Status | none |
| KEV Status | Not Listed |
The web application receives a URL or file identifier from an upstream request and processes it using server privileges without sufficient validation.
containerd is an open-source container runtime. Prior to versions 1.7.36, 2.0.13, 2.2.9, 2.3.6, and 2.4.1, a crafted OCI index graph can force very high CPU/memory usage during PullImage (before container start), causing long ContainerCreating stalls and, at larger sizes, node/runtime instability. The vulnerability occurs because containerd's image-pull descriptor graph resolution handlers processed OCI image indices and manifests recursively without enforcing boundaries on traversal depth or breadth, and without maintaining a global visited registry to count duplicate references.
An unauthenticated path traversal vulnerability exists in the Khoj AI assistant platform via the static file serving endpoint `/home/{file_path:path}`. Due to improper path sanitization when handling user input with Python's pathlib module, a remote attacker can read arbitrary files from the server's filesystem.
An argument injection vulnerability (CWE-88) in CliInvoke and AlastairLundy.CliInvoke allows local attackers to execute arbitrary system commands. By injecting double-quote characters into target file paths or arguments, attackers can terminate operating-system-level quoted boundaries and introduce new commands when shell runners are utilized.
An OS command injection vulnerability exists in the PowerShell and Cmd shell wrappers of the CliInvoke .NET library (specifically the CliInvoke.Specializations package). Under vulnerable configurations, arguments and targets are passed as a single flat string to ProcessStartInfo.Arguments, permitting double-quote breakout and execution of arbitrary secondary commands with host process privileges.
A critical-severity input validation vulnerability in the Elixir multi-party payment library `mpp` allows unauthenticated remote attackers to exhaust the transaction fee payer's wallet balance. By submitting a crafted Ethereum transaction envelope with artificially inflated gas parameters, an attacker can force the server to co-sign and commit to pay exorbitant fees, leading to severe financial loss and Denial of Service.
A critical gas draining vulnerability exists in the ZenHive mpp (Multi-Payment Protocol) library prior to version v0.6.0. By omitting validation of EIP-2930 access lists in custom 0x76 transaction envelopes, the library allows malicious clients to pad transaction payloads with dummy addresses, draining the gas sponsor's hot wallet.