From 1bd3c72e17615c280a71a100e83336e04c136f42 Mon Sep 17 00:00:00 2001 From: Rodrigo Gomes da Silva Date: Fri, 7 Aug 2026 02:40:07 -0300 Subject: [PATCH] fix: close connection on extension-sidecar provenance rejection Same class as the auth/CSRF close-on-reject: the sidecar proxy's same-origin provenance check runs before read_body(), so an HTTP/1.1 connection reused after a 403 would parse the unread body as the next request line. Flag close_connection on this path too. Found by Greptile review of #6658; covered by a new unit test. --- api/routes.py | 4 ++++ tests/test_rejected_write_connection_close.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/api/routes.py b/api/routes.py index a7d01953..41aad267 100644 --- a/api/routes.py +++ b/api/routes.py @@ -6066,6 +6066,10 @@ def _handle_extension_sidecar_proxy( # DELETE fell through the CSRF compatibility path that intentionally admits # non-browser clients, giving unsafe methods weaker provenance than GET. if not _check_same_origin_browser_request(handler, require_provenance=True): + # Provenance rejection runs before read_body(); close rather than + # reusing an HTTP/1.1 connection whose unread body would corrupt the + # next request (same class as _check_csrf close-on-reject). + handler.close_connection = True return j(handler, {"error": _csrf_rejection_error(handler)}, status=403) try: request_body = _read_body_bytes(handler) if read_request_body else None diff --git a/tests/test_rejected_write_connection_close.py b/tests/test_rejected_write_connection_close.py index ea004f2e..fa926ae6 100644 --- a/tests/test_rejected_write_connection_close.py +++ b/tests/test_rejected_write_connection_close.py @@ -54,3 +54,21 @@ def test_token_rejected_csrf_closes_connection(monkeypatch): assert routes._check_csrf(handler) is False assert handler.close_connection is True + + +def test_sidecar_provenance_rejected_closes_connection(monkeypatch): + """Sidecar proxy provenance rejection also runs before read_body().""" + import api.routes as routes + + handler = SimpleNamespace( + path="/api/extensions/ext1/sidecar/proxy", + command="POST", + close_connection=False, + ) + monkeypatch.setattr(routes, "_match_extension_sidecar_proxy_path", lambda _path: ("ext1", "/proxy")) + monkeypatch.setattr(routes, "_check_same_origin_browser_request", lambda _handler, **_: False) + monkeypatch.setattr(routes, "j", lambda _handler, _payload, status=200: None) + + routes._handle_extension_sidecar_proxy(handler, SimpleNamespace(path=handler.path, query=""), "POST") + + assert handler.close_connection is True