fix(security): order sanitizer after installed hooks

This commit is contained in:
kshitijk4poor 2026-07-11 12:04:50 +05:30 committed by kshitij
parent 92c2146039
commit 1f46145e03
2 changed files with 50 additions and 1 deletions

View file

@ -64,7 +64,10 @@ class _CrossOriginRequestSanitizer(urllib.request.BaseHandler):
# Request processors run in ascending order. Keep this last so an installed
# cookie/auth/instrumentation processor cannot re-add a secret after the
# redirect handler sanitizes the new Request.
handler_order = 1_000_000_000
# Infinity is greater than every finite handler order. If an installed
# processor also uses infinity, stable sorting keeps this appended handler
# after it, so sanitization still owns the final request boundary.
handler_order = float("inf") # type: ignore[assignment]
def __init__(self, original_url: str) -> None:
self._original_origin = url_origin(original_url)

View file

@ -329,6 +329,8 @@ def test_installed_request_processor_cannot_resurrect_cross_origin_secret(
_RecordingHandler.redirect_to = f"http://localhost:{sink.server_port}/sink"
class SecretProcessor(urllib.request.BaseHandler):
handler_order = float("inf") # type: ignore[assignment]
def http_request(self, request):
request.add_header("X-Installed-Secret", "must-not-cross")
return request
@ -481,6 +483,50 @@ def test_anthropic_profile_drops_x_api_key_on_redirect(monkeypatch):
assert headers["accept"] == "application/json"
def test_azure_catalog_probe_drops_api_key_and_bearer_on_redirect():
from hermes_cli import azure_detect
source = _server()
sink = _server()
_RecordingHandler.requests = []
_RecordingHandler.redirect_status = 302
_RecordingHandler.redirect_to = f"http://localhost:{sink.server_port}/sink"
try:
status, body = azure_detect._http_get_json(
f"http://127.0.0.1:{source.server_port}/redirect", "azure-secret", timeout=3
)
finally:
source.shutdown()
sink.shutdown()
assert status == 200
assert body == {"data": []}
_, headers = _RecordingHandler.requests[-1]
assert "authorization" not in headers
assert "api-key" not in headers
def test_azure_anthropic_probe_drops_api_key_and_bearer_on_redirect():
from hermes_cli import azure_detect
sink = _server()
source = ThreadingHTTPServer(("127.0.0.1", 0), _LmStudioSourceHandler)
Thread(target=source.serve_forever, daemon=True).start()
_RecordingHandler.requests = []
_LmStudioSourceHandler.redirect_to = f"http://localhost:{sink.server_port}/sink"
try:
azure_detect._probe_anthropic_messages(
f"http://127.0.0.1:{source.server_port}", "azure-secret"
)
finally:
source.shutdown()
sink.shutdown()
_, headers = _RecordingHandler.requests[-1]
assert "authorization" not in headers
assert "api-key" not in headers
def test_lmstudio_load_post_drops_bearer_on_redirect(monkeypatch):
from hermes_cli import models