It's Not Just XSS Anymore: Agent Frameworks Are Failing on Access Control

By Beatriz Costa

It's Not Just XSS Anymore: Agent Frameworks Are Failing on Access Control

TL;DR

We analyzed all 1,352 PyPI advisories published between January and June 2026: GitHub-reviewed, OSV format, withdrawn advisories excluded. Then we read the severity and vulnerability type profile for each one. Four findings stand out.

  • AI/LLM tooling was the fastest-growing category we measured in H1 2026. Its share of advisories roughly doubled, from 16% in January to 34% in June, and it's more severe than everything else too: 71% High/Critical versus 45%.
  • The most-affected packages of the half are AI tools, not web frameworks. open-webui (78) and PraisonAI (76) lead the ranking; Django, the top traditional web framework, sits 14th with 16.
  • Published AI/LLM advisories show a different failure profile. Where mature web apps skew toward XSS and other output-handling and exposure bugs, AI frameworks skew toward authorization: broken access control, IDOR, and missing authentication make up roughly a third of their bugs.
  • 12% of advisories never get a CVE, and they cluster right where the risk is growing fastest: AI.
  • The trend: the AI advisory wave is measurable, and it accelerated through H1 2026

    Here is the share of PyPI advisories that affect AI/LLM tooling, month by month:

    By June, more than a third of Python advisories touched the AI ecosystem.

    "Isn't this just one big audit inflating the numbers?"

    Fair question. We checked. One project, the agent framework PraisonAI, accounted for 120 advisories from a concentrated disclosure cluster (more on that in the case study below). So we pulled it out entirely and reran the trend.

    The wave survives. Excluding PraisonAI, AI advisories still grew 2.9x, from 16 in January to 47 in June, spread across 20 distinct projects: open-webui, vLLM, MLflow, LiteLLM, LangFlow, and more. This is a broad ecosystem trend, not an artifact of one disclosure cluster.

    The packages: an X-ray of what is failing

    Ranking every package by advisory count, then reading the bugs inside, tells a sharper story than the trend line alone. Top 15 PyPI packages, H1 2026:

    Counted together as distinct advisories, the PraisonAI family (praisonai, praisonaiagents, praisonai-platform) totals 120, more than any other project in the dataset. That total is lower than the row sum above because some advisories affected multiple PraisonAI package names. We keep the names split anyway, so the concentration stays visible rather than being flattened into a single tidy number.

    The fingerprints

    Aggregating CWE classes across each full category group, not a top-N subset, so the split stays unambiguous and reproducible, gives three distinct fingerprints.

    AI/LLM tools: broken authorization and code execution. 347 advisories, 71% High/Critical. Path traversal (12%), missing authorization (12%), IDOR (9%), SSRF (9%), missing authentication (8%), code injection (8%). The pattern in this dataset is unambiguous: who is allowed to do what. These are the bugs in software that shipped HTTP endpoints and agent APIs before its access-control model caught up, layered on top of the execution surface these tools provide in the first place (code injection, SSRF). An AI agent's entire job is to act on your behalf. Remove authorization, and that capability becomes an exploit.

    Web apps and frameworks: output handling, the classics. 160 advisories, 40% High/Critical. XSS (15%), information exposure (11%), SSRF (8%), path traversal (6%). Long-familiar bug classes in mature, well-understood code: failures at neutralizing output and handling sessions.

    Everything else: libraries, parsers, clients. 845 advisories, 46% High/Critical. Path traversal leads (13%), then SSRF (7%), XSS (6%), and resource-consumption DoS (6%). That's the signature of libraries parsing untrusted input, and it's where aiohttp's request-smuggling and DoS profile lives, right next to pypdf's allocation bombs.

    The takeaway: in this H1 2026 PyPI dataset, mature web projects skew toward output-handling and exposure bugs, while AI/LLM projects skew toward authorization, authentication, and execution boundaries. That second class is less likely to be caught by simple sink-based matching alone, because the vulnerable condition often depends on authorization context and object ownership rather than a recognizable tainted sink.

    Count is not danger

    aiohttp (29 advisories, 3% High/Critical) and pypdf (26, 0%) are high-volume because they're mature, widely used, and aggressively audited: plenty of real but low-impact robustness bugs. PraisonAI (76, 87%) is high-volume and high-severity. Same metric, "number of CVEs," hiding two opposite realities. Counting advisories to measure risk is a bit like counting parking tickets to judge who the reckless driver is: volume and severity sit on entirely different axes. Read the profile. Not the tally.

    A case study in modern auditing: PraisonAI

    The per-package ranking above lists praisonai, praisonaiagents, and praisonai-platform separately, so it hides this: rolled up as a single project, PraisonAI, an AI agent framework, is the single most-affected project of H1 2026. 120 advisories across those three package names. More than open-webui's 78. No other multi-package AI project in the dataset comes close: the next-largest family, langchain plus its siblings, totals just 6. The pattern matters because it shows what happens once a popular agent framework draws concentrated security attention. Think of it as a home inspection: the house didn't fall apart overnight; somebody finally opened every cabinet.

    These weren't evenly distributed over time. In our H1 2026 GHSA snapshot, the PraisonAI family appears in concentrated disclosure bursts, including 38 advisories on a single publication date (2026-06-18). That daily count comes from our raw GitHub Advisory Database export, not from any single public advisory page, and we reran the export to confirm it against the same filtering logic used throughout this post.

    The public records back up the broader pattern: multiple PraisonAI advisories share the same upstream repository, are GitHub-reviewed, and include detailed, line-numbered technical write-ups. Several follow a repeated source-to-hop-to-sink style. The OAuth authentication-bypass advisory traces oauth.py:364 to oauth.py:381 (CVE-2026-34953). The --mcp command-injection advisory traces cli/features/mcp.py:61 through the MCP client sink. The run_python() shell-injection advisory traces user-controlled input through incomplete escaping straight into subprocess.run(..., shell=True).

    That's why we treat the PraisonAI cluster as a systematic audit pattern rather than a pile of isolated one-off reports. We can't prove from advisory metadata alone whether the work was automated or AI-assisted, so we're calling it systematic and leaving it there.

    The bugs themselves read like a tour of the agent attack surface: a Python sandbox escape via a str subclass with an overridden startswith(), shell injection through unescaped $() substitution, and an --mcp CLI argument piped straight into a subprocess. Across the deduplicated 120-advisory PraisonAI family set, 83% were High or Critical.

    The lesson here isn't "PraisonAI is uniquely bad." All 120 of its advisories, and for what it's worth, all 78 of Open-WebUI's already carry a fixed version. These are actively maintained projects that have essentially patched everything reported to them. The real lesson: once a popular agent framework (8.4k GitHub stars) attracts concentrated research attention, large chunks of its dangerous surface are quickly enumerated. As more teams put these frameworks into production, expect more of this, and expect the response to look like PraisonAI's and open-webui's here. Not like neglect.

    "Are these real vulnerabilities, or just noisy records?"

    Fair challenge. High advisory counts can mean a noisy database just as easily as a dangerous package. To avoid treating volume as proof of risk, we manually spot-checked a subset of AI package advisories rather than relying on the labels. That subset covered the seven highest-volume AI packages, open-webui, praisonai, praisonaiagents, langflow, vllm, praisonai-platform, and mlflow, totaling 261 distinct advisories at the time of the check. For each, we reviewed provenance signals: fixed versions, fix commits, vendor advisories, affected ranges, and technical descriptions.

    This was a provenance check, not a full re-analysis of every AI advisory in the dataset. The remaining roughly 86 AI advisories come from longer-tail packages folded into the aggregate count above (347 total) but not individually re-read for this section. The spot-check exists only to test one thing: were the highest-volume AI packages dominated by thin, low-quality records? They were not.

    Structural provenance holds up. 250 of 261 (96%) declare a fixed version. 100% carry a technical description longer than 200 characters. Only 5 (1.9%) lack all three of {fixed version, fix commit, vendor advisory}, and reading those 5, all are legitimate: mlflow CVE-2026-0545, an auth bypass on job endpoints that escalates to unauthenticated RCE only when an operator has explicitly enabled job execution and allowlisted a privileged job function (not the default state), and langflow CVE-2026-0770, an RCE carrying a ZDI tracking ID.

    The cases that carry the thesis are concrete, technically detailed, and in several cases include PoCs:

    We checked the other side too, so as not to grade on a curve. The 53 advisories across Django, aiohttp, and wagtail show the same rigor: every one declares a fixed version, and the bugs are exactly the modest-impact classes their low severity implies. Algorithmic-complexity DoS for Django. Gated stored XSS for Wagtail. A duplicate-Host-header issue, conditional on a misconfigured reverse proxy, for aiohttp.

    So the asymmetry in the data isn't a labeling artifact. Both sides are well documented, but the AI bugs are genuinely more severe (authorization bypass, RCE), while the mature web and library bugs are genuinely more modest. This spot-check backs up the reading of the severity gap as a property of the bugs themselves, not a quirk of how the database labels things.

    The coverage gap: 12% of advisories have no CVE

    Of the 1,352 advisories, 167 (12%) carry no CVE identifier at all. They exist only as GitHub Security Advisories, and any workflow depending solely on NVD or CVE identifiers will miss every one of them. They also cluster in AI: 20% of AI advisories have no CVE (69 of 347), compared with 10% for everything else (98 of 1,005). An AI project is twice as likely to exist only as a GHSA record.

    This is exactly the population that Safety's database is built to track, CVE or not CVE. More on that here.

    What this means for your team

  • If you ship AI/LLM tooling, the public advisory surface grew faster than every comparison group we measured in this H1 2026 PyPI dataset, and it was more severe. Package-level CVE matching alone is a poor fit for this curve, because many of the highest-impact bugs are authorization and application-logic flaws, not the kind of thing a version-pin catches.
  • In this H1 2026 PyPI dataset, CVE-only coverage would miss one in eight GitHub-reviewed advisories. One in five for AI. A curated advisory source closes that gap.
  • The bugs that matter most in AI are logic and authorization flaws: the kind that demand contextual, curated intelligence. Not pattern matching.
  • How Safety helps

    Everything above is what we measured, on the public record, from the public GHSA dataset. That part doesn't need a sales pitch. But it's also why relying on GHSA or NVD alone isn't enough. Safety tracks vulnerabilities that never receive a CVE, which is exactly the population this analysis shows growing fastest and clustering hardest in AI/LLM tooling. If a one-in-five miss rate on AI advisories sounds like a gap you'd rather not carry, that's the gap we built the database to close.

    Coverage is only half the problem. The other half is noise. Knowing a package has a vulnerability doesn't tell you whether your code ever touches the part that's actually broken. Where function-level intelligence is available, Safety helps teams move past package-level triage and focus on the code paths actually affected.

    There's also a layer this whole analysis doesn't touch: what's already sitting on your developers' machines. Advisory data tells you which packages are vulnerable. It says nothing about the AI tool, MCP server, or IDE extension somebody pulled onto a laptop last Tuesday, outside any lockfile or dependency manifest. Endpoint detection and device management were built before coding agents existed, so none of them sees that workstation layer either. Safety does: agentless, deployed via MDM, no developer buy-in required, so it doesn't depend on someone remembering to ask permission before installing the next MCP server.

    Read the full article