UTCP Patched the Same SSRF Four Times — and the Redirect Hop Was Still Open
NVD published five CVE records on 27 September 2026 for the Universal Tool Calling Protocol — the open-source tool-calling framework positioned as an alternative to MCP, with 652 stars on its Python implementation. Four of the five are server-side request forgery. Three of those four are incomplete-fix variants of an SSRF class the project already patched in May.
That is the story. Not a new bug class, not a novel technique: one validation gap, re-found in three places the original patch did not cover, four months after the first fix shipped. The highest-scoring record in the batch says so in its own advisory text.
The batch
- CVE-2026-101060 (CVSS 4.0 8.4, High) —
HttpCommunicationProtocol.call_toolvalidates the pre-redirect tool URL, then issues the request with aiohttp's defaultallow_redirects=Trueand never re-checks the destination. Fixed in utcp-http 1.1.4. - CVE-2026-101058 (7.1) — hand-written UTCP manuals fetched from a remote origin may declare tool URLs on the agent's own loopback interface, which
ensure_secure_urldeliberately permits for local development. Fixed in utcp-http 1.1.12. - CVE-2026-101059 (7.1) — the OAuth2
tokenUrlfield from a remote OpenAPI spec is never validated, so the client POSTs itsclient_idandclient_secretto whatever endpoint the spec names. Fixed in utcp-http 1.1.4. - CVE-2026-101061 (2.3) — utcp-gql used a prefix check defeated by hostnames like
http://127.0.0.1.attacker.example, and utcp-websocket performed no URL validation at all, despite documented requirements. Fixed in utcp-gql 1.1.1 and utcp-websocket 1.1.1. - CVE-2026-101057 (2.3) — utcp-mcp dialed HTTP and WebSocket MCP server URLs from
mcpServersconfiguration without the validation the HTTP-family plugins apply. Fixed in utcp-mcp 1.1.3.
All five were assigned by VulnCheck. The GHSA advisories behind them were published earlier — GHSA-9qhg-99ww-9mqc, the redirect SSRF, is dated 14 June 2026, more than three months before the CVE record appeared. That gap is now routine enough that we have written about it in the 72-CVE OpenClaw batch and the Obot batch two days ago: if your vulnerability intake begins at NVD, you were blind to these for a quarter.
The incomplete fix, stated plainly
CVE-2026-44661, published 14 May 2026, described a trust-boundary inconsistency in utcp-http: register_manual() validated the discovery URL against an HTTPS/loopback allowlist, but call_tool() reused the resolved template URL without revalidating, and the OpenAPI converter trusted whatever servers[0].url an attacker-hosted spec declared. The fix in 1.1.3 added an invocation-time URL check.
The advisory for the new redirect bug does not hedge about what happened next. In its own words, this is "the redirect invariant of the SSRF class fixed in GHSA-39j6-4867-gg4w; that fix added an invocation-time URL check but left the redirect hop unguarded." The validator runs once, at line 281 of http_communication_protocol.py, on the URL the caller supplies. The request that follows carries aiohttp's default redirect behaviour with no per-hop revalidation. An attacker who controls the endpoint a registered tool points at answers with a 302 and a Location header, and the client follows it into the internal network — returning the response body to the caller.
The preconditions are worth reading closely, because they are ordinary UTCP usage rather than misconfiguration. The initial URL only has to pass the validator, which any https:// host satisfies. The attacker supplies the redirect from their own server. The pattern that makes this reachable — registering a manual or OpenAPI spec discovered from a runtime-supplied URL — is described in the advisory as a core UTCP usage pattern. And the tool's return value flowing back to the agent, which is what makes this a full-read SSRF rather than a blind one, is simply how agentic tool calling works.
The advisory is careful about the credential-theft outcome in a way that deserves credit: IAM credential exfiltration through 169.254.169.254 requires IMDSv1, and IMDSv2-only hosts block that specific result because the session token needs a PUT. Other internal targets — admin panels, unauthenticated datastores, link-local endpoints — remain reachable regardless.
Loopback was an exception the patch could not see past
CVE-2026-101058 is the subtler of the two remaining high-severity records, and it illustrates why allowlists with development carve-outs are hard to secure. ensure_secure_url intentionally permits loopback HTTP so developers can point a client at a service on their own machine. Native, hand-written manuals bypassed the loopback check the OpenAPI converter performed. Put those together and an attacker who can serve a UTCP manual that a victim registers can declare tool URLs on 127.0.0.1 — reaching services on the victim's host that are bound to loopback precisely because their operators considered them unreachable.
The fix in utcp-http 1.1.12 is the right shape: reject manuals fetched from a non-loopback origin that declare loopback tool URLs, keyed off the final post-redirect discovery URL. That last clause is the lesson from CVE-2026-101060 being applied here — the origin that matters is where the fetch landed, not where it started.
CVE-2026-101059 is a different failure with the same root: a URL from remote data used without validation. Register an attacker's OpenAPI spec, invoke a generated OAuth2-protected tool, and the library POSTs your client_id and client_secret to the tokenUrl the spec named. This is not SSRF into the internal network; it is credential delivery out of it. Any operator who registered a third-party OpenAPI spec on utcp-http before 1.1.4 and used OAuth2-protected tools should treat those client credentials as disclosed and rotate them — the upgrade stops future submissions but tells you nothing about past ones.
The two low-severity records are the honest ones
CVE-2026-101057 and CVE-2026-101061 both score 2.3, and both descriptions do something unusual: they narrow the original researcher's claim. The utcp-mcp record states outright that "the OAuth2 token_url credential path described in the original report was not reachable in the affected versions, because the OAuth2 handler was never invoked and the call template's auth field was not read," and notes that mcpServers configuration is operator-authored rather than remote data. What remains is a real but limited issue — a plain-HTTP MCP handshake to a non-loopback host, exposed to network interception.
That correction is the opposite of the pattern we documented in the mcp-remote batch, where CVE descriptions overstated what the cited advisories said. Here the record is more conservative than the report it came from. Defenders benefit either way only if they read the record rather than the score — a 2.3 that accurately describes cleartext MCP handshakes to internal hosts is more useful than an inflated number.
CVE-2026-101061 carries the batch's most familiar mistake. utcp-gql checked whether a URL started with an allowed prefix, which http://127.0.0.1.attacker.example satisfies while resolving to whatever the attacker's DNS says. This is the string-versus-resolution confusion that also produced the mcp-atlassian header SSRF and, published the same day as this batch, the fast-mcp-telegram denylist that checked a hostname string and never resolved it (CVE-2026-55096, CVSS 7.1, fixed in 30.1). Meanwhile utcp-websocket performed no validation at all while the documentation said it should.
What to do
- Upgrade per plugin, not per framework. The fixed versions differ: utcp-http needs 1.1.12 or later to cover all three of its records (1.1.4 fixes the redirect and tokenUrl bugs but not the loopback manual), utcp-mcp needs 1.1.3+, utcp-gql and utcp-websocket need 1.1.1+. Current PyPI releases are ahead of all of these. Pin and verify each installed plugin separately — a single
utcpversion tells you nothing about the plugin wheels beside it. - Inventory every manual and OpenAPI spec you register from a remote URL. That is the attacker-controlled input in three of these five. If a spec came from a third party, assume its declared tool URLs, server URLs and
tokenUrlwere never validated on the affected versions. - Rotate OAuth2 client credentials used with third-party specs. CVE-2026-101059 delivered them to an attacker-named endpoint with no logging on your side that would distinguish it from a normal token request.
- Enforce IMDSv2 and default-deny egress on agent hosts. Both were explicitly noted as limiting factors in the advisories. Neither depends on the framework getting URL validation right, which — on this record — is the point.
- Treat "redirects enabled" as a validation bypass by default. Any check performed before an HTTP request is void if the client follows redirects without re-checking. Audit your own tool-calling code for this exact shape; it is one line of default behaviour in most HTTP clients.
- Watch advisory feeds, not CVE feeds, for agent tooling. The June advisory reached NVD in late September. Subscribe to GHSA and VulnCheck for the agent frameworks you run.
The uncomfortable summary: UTCP's maintainers have now fixed this SSRF class in the Python HTTP plugin twice, the TypeScript HTTP package once, and the GraphQL and WebSocket plugins once each. Each patch was correct for the path it inspected. The class survived because the validation lives at call sites rather than at a single chokepoint that every outbound request must pass through — and every new protocol plugin is a new call site. For anyone building tool-calling infrastructure, that is the design note worth taking: URL validation that must be remembered will eventually be forgotten.
Sources:
- NVD — CVE-2026-101060 (published 27 September 2026; CVSS 4.0 8.4; SSRF via unvalidated HTTP redirects in python-utcp before 1.1.4)
- GHSA-9qhg-99ww-9mqc — “SSRF: HTTP tool invocation follows redirects without re-validating the target” (published 14 June 2026; identifies itself as the redirect invariant of GHSA-39j6-4867-gg4w)
- NVD — CVE-2026-101058 (CVSS 4.0 7.1; loopback tool URLs in remotely discovered manuals; fixed in utcp-http 1.1.12)
- NVD — CVE-2026-101059 (CVSS 4.0 7.1; unvalidated OAuth2 tokenUrl from remote OpenAPI specs; fixed in utcp-http 1.1.4)
- NVD — CVE-2026-101061 (CVSS 4.0 2.3; utcp-gql prefix-check bypass and utcp-websocket missing validation; incomplete application of the CVE-2026-44661 fix)
- NVD — CVE-2026-101057 (CVSS 4.0 2.3; utcp-mcp dials unvalidated MCP server URLs; record narrows the original report's OAuth2 claim)
- NVD — CVE-2026-44661 (published 14 May 2026; the original utcp-http SSRF fixed in 1.1.3, cited by the new advisory as incompletely fixed)
- NVD — CVE-2026-55096 (published 28 September 2026; CVSS 3.1 7.1; fast-mcp-telegram SSRF denylist checks hostname string without resolving DNS; fixed in 30.1)