CVE-2026-65975 Overview
CVE-2026-65975 is an authorization flaw [CWE-863] in Pydantic AI, a Python agent framework for building applications and workflows with Generative AI. The vulnerability affects the UI adapters Agent.to_ag_ui()/AGUIAdapter and VercelAIAdapter in versions 1.88.0 up to 1.107.1, and 2.0.0b1 up to 2.5.0. A defense-in-depth routine called sanitize_messages fails to correctly re-anchor its index after dropping empty client messages. As a result, a remote client can trigger execution of a registered, non-approval server tool with client-supplied arguments the model never emitted.
Critical Impact
A remote unauthenticated client can cause registered server tools to execute with attacker-controlled arguments, bypassing before_model_request/after_model_request guardrails.
Affected Products
- Pydantic AI versions 1.88.0 up to but not including 1.107.1
- Pydantic AI versions 2.0.0b1 up to but not including 2.5.0
- Applications using Agent.to_ag_ui(), AGUIAdapter, or VercelAIAdapter
Discovery Timeline
- 2026-07-29 - CVE-2026-65975 published to NVD
- 2026-07-30 - Last updated in NVD database
Technical Details for CVE-2026-65975
Vulnerability Analysis
Pydantic AI's UI adapters accept message history from untrusted clients. To prevent attackers from injecting fabricated tool calls, the framework applies sanitize_messages to strip unresolved ("dangling") client-submitted tool calls before the history reaches the agent. This routine acts as a defense-in-depth default that prevents the agent from executing tool calls the model never emitted.
The sanitization logic anchors its strip operation to a message index computed before sanitization runs. When a trailing client message sanitizes to empty and gets dropped, the index no longer points at the intended tail. For example, with the default manage_system_prompt='server', a client-submitted system message is removed. A preceding assistant response that carries an unresolved tool call then becomes the new tail and is dispatched without inspection.
Root Cause
The root cause is a Time-of-Check Time-of-Use pattern in message index handling. The sanitizer computes the tail boundary before mutating the message list, and never recomputes the boundary after removals. This lets a forged assistant tool call slip past the check even though the sanitization pass technically ran.
Attack Vector
A remote client submits a crafted message history to any endpoint exposed by AGUIAdapter or VercelAIAdapter. The payload contains an assistant message bearing a forged tool call followed by a client message that will sanitize to empty (such as a system message under the default server-managed prompt policy). After sanitization drops the trailing message, the forged assistant call becomes the tail and dispatches to the registered tool. Tools marked requires_approval=True are not auto-executed on this path. Tools gated only by before_model_request or after_model_request hooks are bypassed because the forged call skips the model turn entirely.
No verified public exploit code is available. See the GitHub Security Advisory GHSA-jpr8-2v3g-wgf9 for maintainer analysis.
Detection Methods for CVE-2026-65975
Indicators of Compromise
- Tool invocations in agent logs whose arguments do not correspond to any prior model output within the same conversation trace.
- Requests to AG-UI or Vercel AI adapter endpoints containing an assistant message with tool_calls followed by a system-role client message.
- Increased volume of tool executions that skip the before_model_request/after_model_request hook telemetry.
Detection Strategies
- Correlate every server tool execution with the immediately preceding model response and alert when the tool arguments were not produced by the model.
- Instrument sanitize_messages or wrap the adapter dispatch path to log the sanitized message list and the tail message role before tool dispatch.
- Compare running Pydantic AI package versions in production inventories against the fixed releases 1.107.1 and 2.5.0.
Monitoring Recommendations
- Enable structured logging on all agent tool calls, including caller identity, argument payloads, and the originating message index.
- Alert on any tool invocation reaching a server tool without a matching model_request span in the trace.
- Monitor deployment pipelines for pinned Pydantic AI versions in the vulnerable range and flag them for upgrade.
How to Mitigate CVE-2026-65975
Immediate Actions Required
- Upgrade Pydantic AI to 1.107.1 on the 1.x branch or 2.5.0 on the 2.x branch.
- Audit registered tools exposed through AGUIAdapter and VercelAIAdapter for side effects that could be abused with attacker-controlled arguments.
- Convert high-impact server tools to requires_approval=True until the upgrade is complete, since approval-gated tools are not auto-executed by this path.
Patch Information
The issue is fixed in Pydantic AI 1.107.1 and 2.5.0. Both releases correct the tail index computation in sanitize_messages so the strip operation applies after empty-message removal. Details are documented in the Pydantic AI security advisory.
Workarounds
- Set requires_approval=True on any tool that performs state-changing or sensitive operations to force a human-in-the-loop step.
- Validate tool arguments inside the tool function itself rather than relying solely on before_model_request/after_model_request hooks, since forged calls skip the model turn.
- Reject or pre-filter client-supplied message histories that contain assistant-role messages with tool_calls at the server boundary.
# Upgrade to a fixed release
pip install --upgrade 'pydantic-ai>=1.107.1,<2.0.0'
# or, for the 2.x branch
pip install --upgrade 'pydantic-ai>=2.5.0'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

