GHSA-Q2XC-RRXJ-58X9

Vulnerability from github – Published: 2026-10-08 17:16 – Updated: 2026-10-08 17:16
VLAI
Summary
Pydantic AI Web chat UI (`Agent.to_web()`, `clai web`): the local chat endpoint does not validate the `Host` header
Details

Summary

The Pydantic AI development web chat UI (Agent.to_web(), clai web) does not validate the Host header of incoming requests. A website a developer visits can use DNS rebinding to make requests to a chat UI running on that developer's machine appear same-origin to the browser, causing the served agent to run and to execute its tools with the privileges and credentials of the local process.

Details

Once a name the attacker controls resolves to the loopback address, the browser treats the request as same-origin, so neither an Origin check nor a CSRF token constrains it — a same-origin page can read the served UI and any token in it.

Binding the web UI to localhost — the default — does not prevent this.

Impact

Applications and developers serving an agent through Agent.to_web() or clai web. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects.

Current browser protections reduce but do not remove this exposure: Chromium's Local Network Access gates loopback subresource requests, but does not cover top-level navigations, and Safari does not implement it.

Mitigation

Upgrade to pydantic-ai/pydantic-ai-slim >= 2.30.0, or >= 1.107.5 on the v1 maintenance line.

The fix validates the Host header and rejects anything other than localhost, a loopback/LAN IP address, or an explicitly allowed host, responding 421 Misdirected Request otherwise. If you serve the web chat UI under a real hostname — behind a reverse proxy, tunnel, or similar — name it explicitly:

app = agent.to_web(allowed_hosts=['ui.example.com'])
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pydantic-ai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.34.0"
            },
            {
              "fixed": "1.107.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pydantic-ai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0b1"
            },
            {
              "fixed": "2.30.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pydantic-ai-slim"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.34.0"
            },
            {
              "fixed": "1.107.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pydantic-ai-slim"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0b1"
            },
            {
              "fixed": "2.30.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-107292"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-346",
      "CWE-350"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-08T17:16:39Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nThe Pydantic AI development web chat UI (`Agent.to_web()`, `clai web`) does not validate the `Host` header of incoming requests. A website a developer visits can use DNS rebinding to make requests to a chat UI running on that developer\u0027s machine appear same-origin to the browser, causing the served agent to run and to execute its tools with the privileges and credentials of the local process.\n\n### Details\n\nOnce a name the attacker controls resolves to the loopback address, the browser treats the request as same-origin, so neither an `Origin` check nor a CSRF token constrains it \u2014 a same-origin page can read the served UI and any token in it.\n\nBinding the web UI to localhost \u2014 the default \u2014 does not prevent this.\n\n### Impact\n\nApplications and developers serving an agent through `Agent.to_web()` or `clai web`. The consequences depend on the tools the served agent exposes, and can include data disclosure as well as unwanted tool side effects.\n\nCurrent browser protections reduce but do not remove this exposure: Chromium\u0027s Local Network Access gates loopback subresource requests, but does not cover top-level navigations, and Safari does not implement it.\n\n### Mitigation\n\nUpgrade to `pydantic-ai`/`pydantic-ai-slim` \u003e= 2.30.0, or \u003e= 1.107.5 on the v1 maintenance line.\n\nThe fix validates the `Host` header and rejects anything other than localhost, a loopback/LAN IP address, or an explicitly allowed host, responding `421 Misdirected Request` otherwise. If you serve the web chat UI under a real hostname \u2014 behind a reverse proxy, tunnel, or similar \u2014 name it explicitly:\n\n```python\napp = agent.to_web(allowed_hosts=[\u0027ui.example.com\u0027])\n```",
  "id": "GHSA-q2xc-rrxj-58x9",
  "modified": "2026-10-08T17:16:39Z",
  "published": "2026-10-08T17:16:39Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-q2xc-rrxj-58x9"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/pull/7437"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/pull/7438"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/commit/394cc1d31656620704a703a2daed752afa5135fe"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/commit/871c7aeec5dfed2138655ccbccbf15c6d763bae7"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/pydantic/pydantic-ai"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.5"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pydantic/pydantic-ai/releases/tag/v2.30.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:H/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Pydantic AI Web chat UI (`Agent.to_web()`, `clai web`): the local chat endpoint does not validate the `Host` header"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…