Skip to content

Security: Localhost Prefix Validation Bypass in utcp-gql and utcp-websocket #86

@gola-leya

Description

@gola-leya

Security: Localhost Prefix Validation Bypass in utcp-gql and utcp-websocket

Summary

A validation bypass vulnerability exists in python-utcp 1.1.0 affecting both:

  • utcp-gql
  • utcp-websocket

The localhost security validation relies on string prefix matching instead of validating the actual hostname/IP address.

As a result, attacker-controlled domains such as:

127.0.0.1.attacker-domain.com

or

127.0.0.1.x.x.x.sslip.io

can pass localhost validation even though they resolve to a remote host.

Affected Components

  • GraphQLCommunicationProtocol._enforce_https_or_localhost()
  • WebSocketCallTemplate.validate_url()

Root Cause

The implementation allows URLs beginning with:

using string prefix checks.

This does not verify that the hostname is actually a loopback address.

Example:

http://127.0.0.1.attacker-domain.com/graphql

The URL begins with "http://127.0.0.1/" and therefore passes validation, but the request is sent to a remote server.

Impact

If an attacker can influence endpoint URL configuration, authenticated requests may be redirected to attacker-controlled infrastructure.

Potential consequences include:

  • Authorization header disclosure
  • API key leakage
  • Tool-call data exposure
  • Security control bypass

Reproduction

A proof-of-concept was successfully reproduced using a crafted sslip.io hostname:

127.0.0.1..sslip.io

The URL passes validation and receives authenticated GraphQL/WebSocket traffic from the client.

Observed behavior:

  • Validation succeeds
  • Requests are sent to a non-loopback host
  • Authorization headers are transmitted to the remote endpoint

Suggested Fix

  • Parse URLs using a proper URL parser.

  • Validate the actual hostname rather than performing string prefix matching.

  • Only allow exact loopback hosts:

    • localhost
    • 127.0.0.1
    • ::1
  • Add regression tests for:

    • localhost.attacker.tld
    • 127.0.0.1.attacker.tld
    • 127.0.0.1.x.x.x.sslip.io

Environment

  • python-utcp 1.1.0
  • utcp-gql 1.1.0
  • utcp-websocket 1.1.0

I can provide the complete PoC and test output if additional information is required.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions