Skip to content

Host header field contains scope of IPv6 link-local address #13401

Description

@jaltendorfer

Describe the bug

When a request is made to a URL containing a IPv6 link-local address with a zone id (e.g. http://[fe80::1%eth0]/), aiohttp sends the zone id verbatim as part of the Host header (Host: [fe80::1%eth0]).
Per RFC 6874 §4, a zone id only has local significance to the sending host and must be stripped by the client:

an HTTP client, proxy, or other intermediary MUST remove any ZoneID attached to an outgoing URI, as it has only local significance at the sending host.

Servers that validate the Host header strictly against RFC 3986, for example nginx from 1.29.4 onward, now reject such requests with 400 Bad Request.

To Reproduce

  1. nginx server/reverse proxy with version >=1.29.4
  2. Make a request to an endpoint with a IPv6 link-local address (e.g. http://[fe80::1%eth0]/)
  3. Response status is 400
  4. Request headers show: Host: [fe80::1%eth0]

Expected behavior

The zone id of IPv6 link local address is stripped in the Host header -> Host: [fe80::1]

Logs/tracebacks

Nginx error:
client sent invalid host header while reading client request headers, client: fe80::1, server: localhost, request: "GET /api/test HTTP/1.1", host: "[fe80::1%eth0]"

Python Version

$ python --version
Python 3.14.4

aiohttp Version

$ python -m pip show aiohttp
Version: 3.14.3

multidict Version

$ python -m pip show multidict
Version: 6.7.1

propcache Version

$ python -m pip show propcache
Version: 0.5.2

yarl Version

$ python -m pip show yarl
Version: 1.24.5

OS

Ubuntu 24.04

Related component

Client

Additional context

No response

Code of Conduct

  • I agree to follow the aio-libs Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions