{"schema":"threatline.record/2","record":{"id":"CVE-2026-107290","aliases":["GHSA-fpf4-vwcp-v4hp","PYSEC-2026-4277","PYSEC-2026-4286"],"summary":"Pydantic AI: Event loop blocked by quadratic title extraction in `web_fetch`","details":"### Summary\n\nThe local web-fetch tool (`web_fetch_tool`, also used as the `WebFetch` capability's local fallback) processed responses with several steps whose running time grows quadratically with the size of certain server-controlled inputs, and ran them on the event loop: decoding the body with whichever charset the server declared, extracting the page title with a backtracking regular expression, and converting the HTML to markdown. An application that exposes this tool to untrusted prompts can be steered to fetch an attacker-controlled page of a megabyte or two that blocks the event loop for minutes, stalling every other coroutine in the process — other agent runs, other requests being served — for the duration.\n\nThis is an **availability** issue only. SSRF protections and the download size limit introduced in GHSA-v2xh-2vp8-57h8 are unaffected; that limit bounds how much is downloaded, not how long the response takes to process.\n\n### Details\n\nTitle extraction used a backtracking pattern over the raw response body, so a body made of repeated unterminated tag openings cost time proportional to the square of its size. The HTML-to-markdown conversion had the same shape in three of its steps: normalizing whitespace, stripping preformatted blocks, and numbering ordered lists all took time proportional to the square of a run of spaces or a list's length. All of it ran on the event loop, and the regex steps hold the interpreter lock even when moved off it, so the whole process paid for the size of a server-controlled response.\n\nThe response body was also decoded on the event loop with the codec named by the `charset` parameter of the response's `Content-Type`, looked up in Python's codec registry. That registry includes `punycode`, whose decoder takes time proportional to the square of its input: a response of about one megabyte labelled `charset=punycode` blocked the event loop for roughly half a minute, with no HTML required. The registry also includes codecs that aren't text encodings at all, such as `rot_13` and `base64_codec`; a response labelled with one of those raised an unexpected exception out of the tool, aborting the agent run that fetched it.\n\nSeparately, the HTML-to-markdown conversion recursed once per nested element, so a page nested a few hundred elements deep raised a `RecursionError` out of the tool, aborting the agent run that fetched it. A JSON response nested deeper than the interpreter allows did the same. These only affect that one run.\n\n### Who Is Affected\n\nYou are affected if your application registers the local web-fetch tool (or relies on the `WebFetch` capability's local fallback) and exposes the agent to untrusted prompts. `allowed_domains` narrows the exposure to pages on those domains but does not remove it. Applications that only fetch developer-controlled URLs are not exposed to the model-chosen attack path.\n\n### Remediation\n\nUpgrade to a patched version. The title is now found with a single linear scan, the conversion steps above run in linear time, and decoding, title extraction and conversion all run in a worker thread. A charset naming a codec that isn't a text encoding, and a page too deeply nested to convert, are reported back to the model as a failed fetch instead of aborting the run; a JSON body too deeply nested to parse is returned as plain text.\n\n### Credits\n\nReported privately by @BrianWillows, whose report covered the quadratic title extraction. The response decoding, the codecs that are not text encodings, and the quadratic steps in the HTML-to-markdown conversion were found while fixing it.","categories":["Libraries & packages"],"product":"pydantic-ai","vendor":"pydantic","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai"},"range":">= 1.77.0, < 1.107.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai"},"range":">= 2.0.0b1, < 2.44.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai-slim"},"range":">= 1.77.0, < 1.107.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai-slim"},"range":">= 2.0.0b1, < 2.44.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107290","source_modified_at":"2026-10-09T15:15:26.958Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"pydantic-ai","vendor":"pydantic","versions":[{"version":">= 1.77.0, < 1.107.6","status":"affected"},{"version":">= 2.0.0b1, < 2.44.0","status":"affected"}],"defaultStatus":null},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107290","source_modified_at":"2026-10-09T15:15:26.958Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"pydantic-ai-slim","vendor":"pydantic","versions":[{"version":">= 1.77.0, < 1.107.6","status":"affected"},{"version":">= 2.0.0b1, < 2.44.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.77.0"},{"fixed":"1.107.6"}]}],"versions":["1.100.0","1.101.0","1.102.0","1.103.0","1.104.0","1.105.0","1.106.0","1.107.0","1.107.1","1.107.2","1.107.4","1.107.5","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","1.99.0"]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0b1"},{"fixed":"2.44.0"}]}],"versions":["2.0.0","2.0.0b1","2.0.0b2","2.0.0b3","2.0.0b4","2.0.0b5","2.0.0b6","2.0.0b7","2.1.0","2.10.0","2.11.0","2.12.0","2.13.0","2.14.0","2.14.1","2.15.0","2.16.0","2.17.0","2.18.0","2.19.0","2.2.0","2.20.0","2.21.0","2.22.0","2.23.0","2.24.0","2.25.0","2.26.0","2.27.0","2.27.1","2.28.0","2.29.0","2.3.0","2.30.0","2.31.0","2.31.1","2.32.0","2.32.1","2.32.2","2.33.0","2.34.0","2.35.0","2.35.1","2.35.3","2.36.0","2.37.0","2.38.0","2.39.0","2.4.0","2.40.0"]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai-slim","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai-slim"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.77.0"},{"fixed":"1.107.6"}]}],"versions":["1.100.0","1.101.0","1.102.0","1.103.0","1.104.0","1.105.0","1.106.0","1.107.0","1.107.1","1.107.2","1.107.4","1.107.5","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","1.99.0"]},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai-slim","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai-slim"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0b1"},{"fixed":"2.44.0"}]}],"versions":["2.0.0","2.0.0b1","2.0.0b2","2.0.0b3","2.0.0b4","2.0.0b5","2.0.0b6","2.0.0b7","2.1.0","2.10.0","2.11.0","2.12.0","2.13.0","2.14.0","2.14.1","2.15.0","2.16.0","2.17.0","2.18.0","2.19.0","2.2.0","2.20.0","2.21.0","2.22.0","2.23.0","2.24.0","2.25.0","2.26.0","2.27.0","2.27.1","2.28.0","2.29.0","2.3.0","2.30.0","2.31.0","2.31.1","2.32.0","2.32.1","2.32.2","2.33.0","2.34.0","2.35.0","2.35.1","2.35.3","2.36.0","2.37.0","2.38.0","2.39.0","2.4.0","2.40.0"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai"},"version":"1.107.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai"},"version":"2.44.0"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai-slim"},"version":"1.107.6"},{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-08T16:48:27Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pydantic-ai-slim"},"version":"2.44.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai"},"version":"1.107.6"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai"},"version":"2.44.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai-slim","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai-slim"},"version":"1.107.6"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","source_modified_at":"2026-10-15T14:56:08.216259462Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"pydantic-ai-slim","ecosystem":"PyPI","purl":"pkg:pypi/pydantic-ai-slim"},"version":"2.44.0"}],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.00442,"percentile":0.37375,"score_date":"2026-10-23"},"published_at":"2026-10-08T16:09:04.272Z","modified_at":"2026-10-15T14:56:08.216259462Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-08T16:48:27Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107290","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-09T15:15:26.958Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-fpf4-vwcp-v4hp","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-15T14:56:08.216259462Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107290","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-fpf4-vwcp-v4hp","tags":["x_refsource_CONFIRM"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/pull/8397","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/pull/8399","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/pull/8418","tags":["x_refsource_MISC"]},{"url":"https://github.com/pydantic/pydantic-ai/pull/8433","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/pull/8434","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/commit/2faa6181d8a17d83bc9516d035c5270db8730fa0","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/commit/9cdc952e4c3319e85a3e04f2de49fbbb765bd38b","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/commit/a93ea5226be1e93ae13131ae3f22287190411389","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/commit/c3fd1cc1f15fdbf750d78e4e3ec1e8b4d6a3d920","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/commit/fb92ccfc3ca2735dab877e2ed73856681bf72ad1","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/releases/tag/v1.107.6","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/releases/tag/v2.44.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-fpf4-vwcp-v4hp","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/pydantic/pydantic-ai/pull/84332","tags":["x_refsource_MISC"]}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-08T20:23:20.403829Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-15T14:56:08.216259462Z","content_hash":"7ba8dd34ac31f2cd01a2305cd0016bfe1c448b5bccd473249308afbfaac4bc5f"}}
