---
id: CVE-2026-44661
aliases:
  - GHSA-39j6-4867-gg4w
  - PYSEC-2026-3396
title: >-
  utcp-http vulnerable to SSRF via attacker-controlled OpenAPI servers[0].url in
  HTTP communication protocol
summary: >-
  utcp-http vulnerable to SSRF via attacker-controlled OpenAPI servers[0].url in
  HTTP communication protocol
severity: medium
cvss: 4.7
cvssVector: 'CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N'
vendor: utcp-http
product: utcp-http
ecosystem: pip
affected:
  - utcp-http < 1.1.2
patched:
  - utcp-http 1.1.2
published: '2026-05-07'
updated: '2026-07-13'
source: OSV
sourceUrl: 'https://osv.dev/vulnerability/GHSA-39j6-4867-gg4w'
references:
  - url: >-
      https://github.com/universal-tool-calling-protocol/python-utcp/security/advisories/GHSA-39j6-4867-gg4w
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-44661'
  - url: 'https://github.com/universal-tool-calling-protocol/python-utcp'
tags:
  - osv
  - pip
epss: 0.00196
epssPercentile: 0.08297
ingestedAt: '2026-07-13T18:57:51.792Z'
---

## Overview

## Summary

The `utcp-http` plugin is vulnerable to a blind Server-Side Request Forgery (SSRF) caused by a trust-boundary inconsistency between manual discovery and tool invocation. `register_manual()` validates the discovery URL against an HTTPS / loopback allowlist, but `call_tool()` and `call_tool_streaming()` reuse the resolved `tool_call_template.url` directly without revalidating. An attacker who hosts a malicious OpenAPI spec on a legitimate HTTPS endpoint can declare `servers: [{ url: "http://169.254.169.254" }]` (or any internal address) in the spec; the OpenAPI converter blindly trusts that value and the tool becomes a blind SSRF primitive that exposes cloud metadata, internal services, and other firewalled-only endpoints to the LLM caller.

All three HTTP-class protocols (`utcp_http.http`, `utcp_http.streamable_http`, `utcp_http.sse`) shared the same gap, plus a separate prefix-bypass: the previous `startswith("http://localhost")` check let URLs like `http://localhost.evil.com` through.

## Impact

A remote attacker who can convince the agent (via the LLM context, prompt injection, or a tool-discovery surface) to register their HTTPS OpenAPI URL can:
- Map internal networks behind the agent.
- Read AWS/GCP IAM credentials from cloud metadata endpoints (`http://169.254.169.254`, `http://metadata.google.internal`).
- Reach unauthenticated internal services (Elasticsearch, Redis HTTP, internal admin panels).
- Have responses returned to the LLM, which combined with prompt injection enables exfiltration back to the attacker.

## Affected versions

`utcp-http <= 1.1.1`.

## Patched versions

`utcp-http 1.1.2`.

## Patch

Commit: 5b16e43 on `dev`.

- New `utcp_http._security` helper: `ensure_secure_url(url, context=...)` parses the URL with `urllib.parse.urlparse` and validates the hostname (not a string prefix) against the loopback set, closing the `localhost.evil.com` bypass.
- All three protocols call `ensure_secure_url(url, context="manual discovery")` in `register_manual` (replacing the duplicated prefix check) and `ensure_secure_url(url, context="tool invocation")` immediately before each aiohttp request in `call_tool` / `call_tool_streaming`. The runtime check is the actual SSRF fix.
- New regression tests in `test_security.py` pin the accept/reject decisions and explicitly cover the historical bypass cases.

## Workarounds

For users who cannot upgrade immediately:
- Refuse to call `register_manual` with any URL controlled by an untrusted party, even over HTTPS.
- Restrict outbound network access from the host running the agent so internal addresses (RFC1918, 169.254.0.0/16, loopback for cloud metadata) are unreachable.

## Credit

Discovered and reported by [@YLChen-007](https://github.com/YLChen-007) in #83.

## Affected packages

- `utcp-http < 1.1.2`

## Remediation

Upgrade to a patched release:

- `utcp-http 1.1.2`
