diff --git a/core/middleware.py b/core/middleware.py index 3834bbe72..8c9eade97 100644 --- a/core/middleware.py +++ b/core/middleware.py @@ -66,8 +66,15 @@ def _header_values(headers, name: str) -> list[str]: def _internal_header_matches(value: str) -> bool: """Compare raw or proxy-combined values without obs-text type failures.""" candidates = [value] + trimmed_value = value.strip(" \t") + if trimmed_value != value: + candidates.append(trimmed_value) if "," in value: - candidates.extend(part.strip() for part in value.split(",")) + for part in value.split(","): + candidates.append(part) + trimmed_part = part.strip(" \t") + if trimmed_part != part: + candidates.append(trimmed_part) try: expected = INTERNAL_TOOL_TOKEN.encode("utf-8") except (AttributeError, UnicodeError): diff --git a/tests/test_codex_cookbook_admin_gate.py b/tests/test_codex_cookbook_admin_gate.py index 0921d1a89..d2f9589b2 100644 --- a/tests/test_codex_cookbook_admin_gate.py +++ b/tests/test_codex_cookbook_admin_gate.py @@ -12,6 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.testclient import TestClient from starlette.middleware.base import BaseHTTPMiddleware +import core.middleware as middleware from core.middleware import ( CodexCookbookBoundaryMiddleware, INTERNAL_TOOL_HEADER, @@ -123,6 +124,22 @@ DUPLICATE_PRE_BODY_HEADERS = [ [(_INTERNAL_HEADER_BYTES, b"invalid, " + _INTERNAL_TOKEN_BYTES)], id="internal-proxy-combined", ), + pytest.param( + [(_INTERNAL_HEADER_BYTES, b" " + _INTERNAL_TOKEN_BYTES)], + id="internal-leading-sp", + ), + pytest.param( + [(_INTERNAL_HEADER_BYTES, _INTERNAL_TOKEN_BYTES + b" ")], + id="internal-trailing-sp", + ), + pytest.param( + [(_INTERNAL_HEADER_BYTES, b" " + _INTERNAL_TOKEN_BYTES + b" ")], + id="internal-both-sp", + ), + pytest.param( + [(_INTERNAL_HEADER_BYTES, b"\t" + _INTERNAL_TOKEN_BYTES + b"\t")], + id="internal-both-htab", + ), pytest.param( [ (_INTERNAL_HEADER_BYTES, b"\xff"), @@ -291,6 +308,13 @@ def test_odysseus_bearer_parser_rejects_other_credentials(value): assert is_odysseus_bearer_authorization(value) is False +def test_internal_header_match_preserves_an_exact_whitespace_token(monkeypatch): + configured_token = "\t configured token \t" + monkeypatch.setattr(middleware, "INTERNAL_TOOL_TOKEN", configured_token) + + assert middleware._internal_header_matches(configured_token) is True + + def test_mounted_root_path_gate_precedes_json_validation(monkeypatch): side_effects: list[str] = [] monkeypatch.setattr(codex_routes, "COOKBOOK_STATE_FILE", _PoisonPath())