~/f4n6 $ grep -r "utcp-gql SSRF: CVE-2026-44661 fix not applied to the GraphQL and WebSocket plugins" ./investigations/ --include="*.md"

utcp-gql SSRF: CVE-2026-44661 fix not applied to the GraphQL and WebSocket plugins

Jeff Davies 25 Aug 2026 6 min read

1. Executive summary

CVE-2026-44661 is a CWE-918 server-side request forgery vulnerability affecting utcp-gql 1.1.0 and utcp-websocket 1.1.0; both are fixed in 1.1.1. The verified rating is CVSS 4.7 MEDIUM; it is NOT in CISA KEV, and EPSS is 0%. An attacker who can influence a UTCP tool manual can direct GraphQL or WebSocket connections to internal services, loopback addresses or cloud metadata endpoints and may receive API keys, Basic credentials or OAuth bearer tokens attached to the connection. EMEA financial-services exposure is conditional on use of these plugins, acceptance of attacker-influenced manuals, internal network reachability and configured authentication headers. The vulnerable paths, proof of concept and patch details are single-sourced to the GitHub advisory; the supplied sources provide no evidence of exploitation in the wild or actor attribution.

2. Regulatory framing

No specific DORA/NIS2 article is directly engaged by this item. The supplied facts also do not establish a trigger for UK NIS 2018: UK Network and Information Systems Regulations — OES/RDSP duties.

Clients should reassess incident-classification and reporting obligations if investigation identifies credential disclosure, unauthorised internal access, service impact or exploitation in a regulated service.

3. Technical analysis & attack chain

The authoritative vulnerability metadata is CVE-2026-44661 — CVSS 4.7 MEDIUM — NOT in CISA KEV — EPSS 0% — CWE-918 (Server-Side Request Forgery).

Identifier discrepancy: the supplied external rendering labels GHSA-ppx3-28rw-8fpf as CVE-2026-12210, while the authoritative reference supplied for this advisory identifies CVE-2026-44661. This advisory uses CVE-2026-44661 and its verified metadata; clients should also retain the GHSA identifier when searching SBOM and advisory tooling.

Source-confirmed attack chain

  1. Required initial condition: an attacker supplies or influences a UTCP tool manual containing a GraphQL or WebSocket call-template url. The source does not establish a direct, unauthenticated network exploit against UTCP itself.
  2. GraphQL validation bypass: plugins/communication_protocols/gql/src/utcp_gql/gql_communication_protocol.py applies _enforce_https_or_localhost() to manual_call_template.url in register_manual at line 102 and to tool_call_template.url in call_tool at line 181. The validator uses string prefixes:

python url.startswith("https://") or url.startswith("http://localhost") or url.startswith("http://127.0.0.1")

Consequently, http://127.0.0.1.attacker.example/graphql and http://localhost.evil.com/graphql pass validation even though their parsed hostnames are not loopback hosts.

  1. GraphQL connection: the accepted URL is passed to AIOHTTPTransport and used for a live GraphQL request. If the attacker controls the hostname’s DNS, the source states it can resolve to 169.254.169.254, 127.0.0.1 or an internal 192.168.x.x address reachable from the UTCP runtime.
  2. WebSocket validation omission: plugins/communication_protocols/websocket/src/utcp_websocket/websocket_communication_protocol.py claims to enforce “WSS or localhost only,” but _get_connection() performs no scheme or hostname validation. This shared connection path is used by register_manual, call_tool and call_tool_streaming and calls:

python ws = await session.ws_connect(call_template.url, headers=headers, ...)

A WebSocketCallTemplate can therefore specify direct destinations such as ws://169.254.169.254/, ws://127.0.0.1:<internal-port>/ or an internal hostname.

  1. Credential attachment and impact: both plugins use _prepare_headers() before connecting. ApiKeyAuth is attached as a configured header, BasicAuth as Authorization: Basic, and OAuth2Auth as Authorization: Bearer. When the destination is an attacker-controlled host, these credentials can be delivered to that host over plain HTTP or WebSocket. Connections to internal targets can expose otherwise unreachable services or metadata endpoints to attacker-directed requests.
  2. Exploitation state: CVE-2026-44661 is CVSS 4.7 MEDIUM, NOT in CISA KEV, and has EPSS 0%. The supplied material demonstrates the vulnerable code paths and a proof of concept but contains no incident telemetry showing exploitation against production systems.

Affected and fixed versions

Package Affected version established by source Fixed version Fix
utcp-gql 1.1.0 1.1.1 Replaces prefix validation with hostname-based ensure_secure_url at register_manual and call_tool; refuses GraphQL endpoint 3xx responses after connection.
utcp-websocket 1.1.0 1.1.1 Adds ensure_secure_ws_url in the Pydantic field validator and _get_connection; calls ws_connect with allow_redirects=False; uses redirect-safe OAuth2 token retrieval.

The source does not define the status of versions earlier than 1.1.0; do not infer an affected range beyond the stated version. Both plugins duplicate _security.py from utcp-http rather than introducing a runtime dependency, creating a requirement to keep validator behaviour synchronised.

A separate advisory concerning utcp-http documents SSRF through unvalidated HTTP redirects. It supports the need for redirect controls but does not independently corroborate the GraphQL and WebSocket findings.

No malware, persistence, privilege escalation, command-and-control, lateral movement or ransomware behaviour is reported. No confirmed data theft or operational disruption is documented. The plugin findings remain single-sourced; verify affected code and runtime behaviour before enforcement.

4. Mitigation & containment

P1 — within 24 hours

  • Inventory installed versions:

bash python -m pip show utcp-gql utcp-websocket

  • On deployments that accept externally supplied or otherwise attacker-influenced manuals, upgrade each installed affected package immediately:

bash python -m pip install --upgrade "utcp-gql>=1.1.1" "utcp-websocket>=1.1.1"

Update the applicable lockfile or image definition and rebuild/restart the deployed workload; do not rely solely on changing an unused local environment.

  • If immediate upgrade is impossible, disable the affected plugin or suspend registration and invocation of untrusted manuals. The vendor states that no workaround exists for earlier versions; disabling use and restricting egress are containment measures only.
  • Restrict the UTCP workload’s outbound access to approved tool endpoints. Block its access to cloud metadata, loopback and internal services not explicitly required. Do not use string-prefix hostname rules.
  • If suspicious manual URLs or connections are identified, revoke and rotate any API keys, Basic credentials and OAuth2 tokens attached to those call templates.

P2 — within 72 hours

  • Upgrade remaining utcp-gql and utcp-websocket 1.1.0 deployments to 1.1.1 or later and confirm the running environment, container or virtual environment loads the fixed package.
  • Search stored manuals and call-template configuration for:
  • http://localhost. and http://127.0.0.1. hostnames;
  • cleartext ws:// URLs targeting 169.254.169.254, loopback or internal hosts;
  • destinations outside the approved endpoint inventory.
  • Review UTCP application, DNS, proxy and network telemetry for manual registration followed by connections to those destinations. The source supplies no standard UTCP log path or event identifier.
  • Confirm that GraphQL redirects are refused and that WebSocket connections use both the field validator and _get_connection validation. Preserve relevant logs before rotating credentials.

P3 — within seven days

  • Add regression tests using the published bypass URLs and verify they are rejected. Include direct internal WebSocket URLs and 3xx redirect tests.
  • Enforce destination policy using parsed schemes and hostnames, resolved-address checks and redirect controls. Treat manual-provided URLs as untrusted input.
  • For maintained forks, keep the duplicated _security.py implementations aligned with utcp-http; GraphQL must use ensure_secure_url, while WebSocket must use ensure_secure_ws_url and allow_redirects=False.
  • Reduce credential scope for tool integrations and separate UTCP workloads from sensitive internal management services and metadata endpoints.

5. Indicators of compromise

No indicators of compromise available in the source material.

The following are published proof-of-concept behaviours, not confirmed malicious infrastructure. The evidence is single-sourced; verify before enforcement.

Behavioural indicators

Behaviour Where to observe Confidence
GraphQL call-template URL resembling hxxp://127[.]0[.]0[.]1[.]attacker[.]example/graphql or hxxp://localhost[.]evil[.]com/graphql Stored UTCP manuals, registration logs, application URL telemetry, DNS logs High for vulnerable behaviour; single-source code path and PoC, not proof of compromise
utcp-websocket initiates a cleartext connection such as ws[:]//169[.]254[.]169[.]254/ or to loopback/internal services Endpoint network telemetry, container network telemetry, proxy logs where WebSocket traffic is captured High for published PoC behaviour; single-sourced
API-key headers or Authorization: Basic/Authorization: Bearer are sent to a destination outside the approved tool inventory HTTP/WebSocket metadata and application telemetry; avoid recording raw credential values Medium; capability established by source, with no observed exploitation

Source: GitHub Security Advisory GHSA-ppx3-28rw-8fpf.

6. Detection

No YARA rule is appropriate because the source provides no malicious-file artefacts. The package paths and product/CVE names describe vulnerable software, not attacker payloads.

The following Sigma rule targets the exact published URL forms. Map url to the corresponding field in local UTCP, proxy or application telemetry.

title: UTCP GraphQL and WebSocket SSRF Published URL Patterns
status: experimental
description: Detects URL patterns published for the utcp-gql prefix bypass and utcp-websocket direct internal connection.
references:

  - https://github.com/advisories/GHSA-ppx3-28rw-8fpf
author: Adverse Trace
date: 2026-08-25
logsource:
  category: proxy
detection:
  selection_graphql_prefix:
    url|startswith:

      - 'http://127.0.0.1.'
      - 'http://localhost.'
  selection_websocket_internal:
    url|startswith:

      - 'ws://169.254.169.254/'
      - 'ws://127.0.0.1:'
  condition: selection_graphql_prefix or selection_websocket_internal
falsepositives:

  - Controlled testing using the published proof of concept
level: medium

This rule covers only the published forms. WebSocket exploitation can use other reachable internal hostnames, while loopback and link-local traffic may bypass central proxies; deploy equivalent application and endpoint-network monitoring around the UTCP runtime.

CVE assessment

1 referenced CVE

CVE CVSS Exploited EPSS Summary
CVE-2026-44661 4.7 Medium 0% python-utcp is the python implementation of UTCP. Prior to 1.1.3, the utcp-http plugin is vulnerable to a blind Server-Side Req…

7. Sources

8. Adverse Trace position

Adverse Trace retains the verified rating of CVSS 4.7 MEDIUM for CVE-2026-44661; it is NOT in CISA KEV, has EPSS 0%, and is classified as CWE-918. Client impact is conditional but material where affected UTCP deployments ingest attacker-influenced manuals, possess sensitive tool credentials and can reach internal services. We recommend immediate upgrade for deployments meeting those conditions and completion within 72 hours elsewhere, without elevating the issue to critical or treating the proof of concept as evidence of active exploitation. The specific plugin findings remain single-sourced; verify before enforcement. Adverse Trace will monitor the GHSA identifier discrepancy, maintainer releases, CISA KEV status, EPSS and credible exploitation reporting.


Read the original source →

Published via PulseTrace — Adverse Trace threat intelligence.

Post this to LinkedIn
Formatting is converted automatically — headings, bullets, a link back & hashtags. Paste straight in.
J
Jeff Davies