Skip to the content.

VRSEN/agency-swarm — security scan

Repository: VRSEN/agency-swarm — 4.4k★, MIT, a multi-agent orchestration framework that wires together specialist agents over OpenAI/MCP backends, including a FastAPI integration server and built-in tools. Commit scanned: f4317cde9248 (HEAD of main at scan time) Scan date: 2026-06-02 Disclosure status:Resolved. Public courtesy issue (#658) filed on the agency-swarm repo with the auth-heavy dependency advisory cluster (authlib + fastmcp + mcp — exactly the libraries this project depends on for OAuth and MCP server integration). The maintainer refreshed the lockfile in PR #659 ~15 hours after filing.

Summary

Severity Count
Critical 2
High 21
Medium 25
Low 0
Info 0 (filtered)

48 total findings. After curation: the headline is the auth-class CVE concentration in the pinned uv.lockauthlib carries 1 critical + 3 high all in the authentication-bypass / signature-verification class, fastmcp carries 1 critical SSRF + multiple high OAuth-related advisories, and mcp is pinned past a known DNS-rebinding-default CVE. For a multi-agent orchestration framework whose value-add is exactly OAuth/MCP integration, this is the dependency-tree-fits-the-product-shape concern that benefits most from a single coordinated refresh.

Top findings (curated)

1. uv.lock — auth-tier dependency advisories in the exact libraries the project depends on for auth

Tool: Trivy Verdict: Real, named, and unusually well-correlated with the project’s surface.

The two scanner-reported criticals plus the high-severity auth tail in authlib and fastmcp form a cluster that’s worth treating as one item rather than two:

CVE Package Class Why it lands here
CVE-2026-27962 authlib Authentication bypass via JWK Header Injection (critical) An attacker can craft a JWT whose JWK header steers signature verification to an attacker-controlled key — i.e. trusted-token forgery.
CVE-2026-32871 fastmcp Authenticated Server-Side Request Forgery (critical) A trusted MCP client pivots the FastMCP server into making requests to arbitrary internal URLs. Same advisory previously seen on Klavis and MemoryBear.
CVE-2026-28490 authlib Information disclosure via cryptographic padding High
CVE-2026-28498 authlib Authentication bypass via forged OpenID Connect tokens High
CVE-2026-28802 authlib Signature verification bypass via malicious JWT High
CVE-2026-27124 fastmcp OAuth-related advisory High
CVE-2025-69196 fastmcp Improper token issuance / incorrect resource High
CVE-2025-66416 mcp DNS rebinding protection disabled by default High

That’s 4 distinct authentication-bypass-class advisories in a single dependency (authlib) plus 3 OAuth/MCP advisories across fastmcp and mcp. The realistic exploitability depends on whether the project’s surface actually exercises the affected authlib API (token verification on inbound requests in the FastAPI integration is the most likely path), but the dependency-tree exposure is unambiguous: every consumer of agency-swarm pulls these versions.

The rest of the tail is the standard pile — urllib3 ×4 highs, tornado ×2, aiohttp ×1 high + ×7 medium, python-multipart ×1 high (path-traversal class), starlette CVE-2025-62727, pyjwt CVE-2026-32597, cryptography CVE-2026-26007. A single uv lock --upgrade pass clears the vast majority.

Dependabot is not configured on the repo (no .github/dependabot.yml, no Dependabot PRs in the history), so this tail has been accumulating uncollected — same pattern as MemoryBear yesterday.

2. src/agency_swarm/tools/built_in/PersistentShellTool.py:61subprocess.run(self.command, shell=True) in a shell-by-design tool

Tool: Semgrep (subprocess-shell-true) Verdict: By-design — the tool’s whole purpose is to give the agent a shell.

The same call-site shape as fast-agent’s interactive_shell.py: the LLM controls self.command because the agent is supposed to run shell commands. Opting into a PersistentShellTool is opting into LLM-driven shell execution on the host. The Windows branch uses ["powershell", "-Command", self.command] (no shell=True but the LLM still controls the command string fully), so the Unix branch’s shell=True doesn’t change the threat surface — both are intentional.

The right operator-level mitigation is the same as for fast-agent: don’t enable the persistent-shell tool on an agent whose prompt or input you don’t trust.

3. src/agency_swarm/integrations/fastapi.py:132 — wildcard CORS, but already mitigated

Tool: Semgrep (wildcard-cors) Verdict: FP at the exploitability level — the surrounding code handles the unsafe case correctly.

The CORS configuration block already does the conventional safe handling:

should_allow_credentials = True
if "*" in cors_origins:
    if app_token:
        logger.warning(
            "CORS wildcard '*' with credentials enabled is insecure and often "
            "blocked by browsers. Disabling credentials for wildcard origins."
        )
    should_allow_credentials = False

app.add_middleware(
    CORSMiddleware,
    allow_origins=cors_origins,
    allow_credentials=should_allow_credentials,
    ...
)

The rule fires on allow_origins=cors_origins because cors_origins could contain *, but the surrounding code explicitly downgrades allow_credentials to False when it does. That’s exactly the spec-compliant safe pattern.

4. src/agency_swarm/tools/utils.py:465exec(result, exec_globals) for schema→Pydantic compilation

Tool: Semgrep (exec-detected) Verdict: Real-but-design-context-dependent.

The pattern is schema-to-model compilation: take a generated Python source string for a Pydantic-like class, exec it into a controlled exec_globals namespace, then extract the class with exec_globals.get(class_name). The exec_globals is restricted to a small whitelist (datetime, date, Set, Tuple, Any, Callable, Decimal, Literal, Enum). The risk hinges entirely on where result comes from: if it’s developer-authored schemas at install time, the surface is low; if it’s LLM-generated code at runtime, the surface is “LLM-driven RCE within the exec sandbox limits.”

Worth a maintainer’s eyes on the call-site flow into this function — flagged in the issue as out-of-scope-for-now but mentioned.

5-N. Standard noise / by-design

Finding Files Verdict
logger-credential-leak src/agency_swarm/integrations/openclaw.py:517 Low confidence (per the series downgrade) — historically 6/6+ FPs
non-literal-import src/agency_swarm/utils/files.py:49 By-design — plugin / file-loader discovery

Patterns observed

Dependency advisory composition can be as informative as the count. Most scans surface dep tails that are essentially random (whatever pinned versions happen to be stale). agency-swarm’s tail is the opposite: the heavy hitters concentrate in exactly the libraries this project depends on for the value it providesauthlib, fastmcp, mcp. That’s the difference between “a stale lockfile” and “stale where it counts.” The curated issue leads with the auth-class concentration for exactly that reason.

Two uv lock scans in a row, two repos with no Dependabot, two coherent “this is what uv lock --upgrade would clear” issues. MemoryBear (yesterday) and agency-swarm (today) are both responsive non-strict-norm mid-popularity Python projects whose owners just haven’t wired Dependabot yet. After ten scans of “dep-CVE tail” mentions across the series, the takeaway is concrete: shipping a default .github/dependabot.yml template in any AI-stack project starter would remove this entire class of finding from the next year of scans.

shell=True in an agent-framework “shell tool” is now a recurring by-design pattern. fast-agent’s interactive_shell.py is the same shape. The class is large enough to deserve its own curation note across the series: when an agent framework ships a “Shell” / “Bash” / “PersistentShell” tool, the shell=True finding inside it is the feature, not a vulnerability. Treating it otherwise would either kill the feature or push maintainers toward more complex but no-more-secure workarounds.

Notes on the tool

Disclosure timeline

Reproduce

git clone https://github.com/elfrost/ai-patchlab
cd ai-patchlab
pip install -e ".[dev]"
python scanner/run_scan.py \
  --from-git-url "https://github.com/VRSEN/agency-swarm" \
  --reports-dir reports/vrsen-agency-swarm \
  --min-severity medium \
  --ignore-samples

External tools (Semgrep, Gitleaks, Trivy, pip-audit) need to be installed separately — see the project README.