Skip to content

fix: sanitize http header newline#1384

Open
DRunkPiano114 wants to merge 2 commits intoMoonshotAI:mainfrom
DRunkPiano114:fix/sanitize-http-header-newline
Open

fix: sanitize http header newline#1384
DRunkPiano114 wants to merge 2 commits intoMoonshotAI:mainfrom
DRunkPiano114:fix/sanitize-http-header-newline

Conversation

@DRunkPiano114
Copy link

@DRunkPiano114 DRunkPiano114 commented Mar 10, 2026

Related Issue

Closes #1321, closes #1364, closes #1368

Description

platform.version() on Ubuntu 22.04 HWE returns a string with a trailing newline (\n), which h11 rejects as an illegal header value, causing a Connection error on all requests.

This PR replaces _ascii_header_value() with a stricter sanitizer that only permits TAB (\x09) and printable ASCII (\x20–\x7e), rejecting both non-ASCII bytes and control characters.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open with Devin

Copilot AI review requested due to automatic review settings March 10, 2026 05:50
@DRunkPiano114 DRunkPiano114 changed the title Fix/sanitize http header newline fix: sanitize http header newline Mar 10, 2026
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens OAuth/common HTTP header generation by sanitizing header values so they can’t contain control characters (e.g., trailing newlines from platform.version() on some Ubuntu kernels) that cause h11/aiohttp to reject requests.

Changes:

  • Tighten _ascii_header_value() to allow only TAB and printable ASCII and strip outer whitespace, falling back to "unknown" when empty.
  • Add unit + integration tests validating sanitized values are accepted by h11 and aiohttp.
  • Document the fix in English/Chinese changelogs.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/kimi_cli/auth/oauth.py Replaces header-value sanitizer with a stricter printable-ASCII + TAB filter used by _common_headers()
tests/auth/test_oauth_headers.py Adds unit and h11/aiohttp integration coverage for sanitization behavior and edge cases
tests/auth/__init__.py Marks tests/auth as a package for test discovery/imports
docs/zh/release-notes/changelog.md Adds unreleased note about HTTP header sanitization fix (ZH)
docs/en/release-notes/changelog.md Adds unreleased note about HTTP header sanitization fix (EN)
CHANGELOG.md Adds unreleased note about HTTP header sanitization fix

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +96 to +100
from h11._headers import normalize_and_validate

def _validate(value: str):
headers = [(b"X-Test-Header", value.encode("ascii"))]
normalize_and_validate(headers, _parsed=False)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test imports h11._headers.normalize_and_validate, which is an internal/private API of h11 and could change when dependencies are updated. If you want to reduce brittleness, consider validating through a public h11 API path (e.g., constructing a h11.Request/h11.Response and letting h11 validate headers during event creation/sending), or gracefully skipping if the internal helper isn’t available.

Suggested change
from h11._headers import normalize_and_validate
def _validate(value: str):
headers = [(b"X-Test-Header", value.encode("ascii"))]
normalize_and_validate(headers, _parsed=False)
try:
import h11
except ImportError:
pytest.skip("h11 not available")
def _validate(value: str):
headers = [(b"X-Test-Header", value.encode("ascii"))]
# Constructing a Request triggers h11's header validation
h11.Request(method="GET", target="/", headers=headers)

Copilot uses AI. Check for mistakes.

def _validate(value: str):
# _safe_header validates the full "Name: value" string
_safe_header(f"X-Test-Header: {value}")
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aiohttp integration test relies on aiohttp.http_writer._safe_header, which is a private/internal helper and not part of aiohttp’s public API. Even with the current pin, this can make tests brittle when aiohttp is upgraded; consider exercising header validation through a public API (or a higher-level constructor that performs the same checks), or broaden the skip logic to handle API/behavior changes beyond just ImportError.

Suggested change
_safe_header(f"X-Test-Header: {value}")
try:
_safe_header(f"X-Test-Header: {value}")
except Exception:
pytest.skip("aiohttp _safe_header behavior changed; skipping integration test")

Copilot uses AI. Check for mistakes.
@renatocron
Copy link

Fixed on 1.20.0 via #1401

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