Skip to content

Unsanitized HostOs telemetry header crashes requests with LocalProtocolError: Illegal header value #1087

Description

Let me begin by stating that I'm primarily an Ansible content developer and user. I make heavy use of the azure.azcollection for Azure configuration management and general purpose automation. The azure.azcollection depends upon ms-graph-sdk, msgraph-core, and friends.

I came across this odd bug after patching my local system (Ubuntu 22.04.05 LTS) in the past couple/few days and it took me hours to track it down (sadly, I had to resort to Gemini/Claude assistance to track it down in a timely manner).

Bottom line, the root cause of the bug appears to be a local kernel update, where uname -v has whitespace at the end. I have a local patch in place inside telemetry.py, but I figure'd I'd share this report.

What follows is the result of my Claude/Gemini session identifying and patching the bug.

Describe the bug

TelemetryHandler._add_host_os_header sets the HostOs header to the raw value of platform.system() + " " + platform.version() without any sanitization:

# msgraph_core/middleware/telemetry.py
def _add_host_os_header(self, request) -> None:
    system = platform.system()
    version = platform.version()
    host_os = f'{system} {version}'
    request.headers.update({'HostOs': host_os})

platform.version() is whatever the OS reports for the kernel build string, and the SDK has no control over its contents. On some hosts this string contains leading/trailing whitespace (or other characters that are illegal in an HTTP header value). When it does, every request fails before it is sent, because h11 (via httpx/httpcore) rejects the header:

httpcore.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '

(Note the trailing space — h11 rejects header values with leading/trailing whitespace.)

Expected behavior

Telemetry headers should be sanitized so a malformed platform.version() cannot crash requests — e.g. strip whitespace (and ideally collapse/replace any remaining illegal characters), or omit the header if it cannot be made valid. Telemetry must be best-effort and non-fatal.

How to reproduce

Any host whose platform.version() contains a trailing space (or other illegal header byte). Minimal reproduction of the failing condition:

import platform
from h11._headers import normalize_and_validate

# Simulating a host whose kernel build string ends with a trailing space:
version = "#124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC "
host_os = f"{platform.system()} {version}"
normalize_and_validate([(b"HostOs", host_os.encode())])
# -> h11._util.LocalProtocolError: Illegal header value b'Linux ... UTC '

In practice this surfaces through any Graph call. Real-world report: the Ansible azure.azcollection.azure_rm_adapplication module fails on the first GET /applications with the traceback above, on an Ubuntu 22.04 host (kernel 6.8.0-124-generic) whose uname -v ends with a trailing space and no year.

Suggested fix

host_os = f'{system} {version}'.strip()

A more defensive version would also collapse internal whitespace / drop non-token bytes, but .strip() resolves the reported case.

Environment

  • msgraph-core 1.1.3 (also present unchanged on main and through v1.4.0)
  • msgraph-sdk 1.6.0
  • httpx with h11 0.14.0
  • Python 3.10
  • OS: Ubuntu 22.04, kernel 6.8.0-124-generic

Full traceback (abridged)

File ".../msgraph_core/middleware/telemetry.py", line 48, in send
    response = await super().send(request, transport)
...
File ".../httpcore/_async/http11.py", line 151, in _send_request_headers
    with map_exceptions({h11.LocalProtocolError: LocalProtocolError}):
File ".../httpcore/_exceptions.py", line 14, in map_exceptions
    raise to_exc(exc) from exc
httpcore.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '

The above exception was the direct cause of the following exception:
...
httpx.LocalProtocolError: Illegal header value b'Linux #124~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 21:05:19 UTC '

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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