Skip to content

Commit 7abc9dc

Browse files
authored
Merge pull request from GHSA-fvcq-4x64-hqxr
Escape invalid host when displayed in html
2 parents e8a8c09 + 2fa8c26 commit 7abc9dc

File tree

3 files changed

+21
-13
lines changed

3 files changed

+21
-13
lines changed

docs/source/changelog.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
## 4.2
44

5-
### v4.2.0 - 2024-06-DD
5+
### v4.2.0 - 2024-06-11
6+
7+
This release includes an important security patch for
8+
[CVE-2024-35225 ](https://github.com/jupyterhub/jupyter-server-proxy/security/advisories/GHSA-fvcq-4x64-hqxr).
69

710
([full changelog](https://github.com/jupyterhub/jupyter-server-proxy/compare/v4.1.2...v4.2.0))
811

jupyter_server_proxy/handlers.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,11 @@ async def proxy(self, host, port, proxied_path):
323323
"""
324324

325325
if not self._check_host_allowlist(host):
326-
self.set_status(403)
327-
self.write(
328-
"Host '{host}' is not allowed. "
329-
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.".format(
330-
host=host
331-
)
326+
raise web.HTTPError(
327+
403,
328+
f"Host '{host}' is not allowed. "
329+
"See https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html for info.",
332330
)
333-
return
334331

335332
# Remove hop-by-hop headers that don't necessarily apply to the request we are making
336333
# to the backend. See https://github.com/jupyterhub/jupyter-server-proxy/pull/328
@@ -391,9 +388,7 @@ async def proxy(self, host, port, proxied_path):
391388
# Ref: https://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient.fetch
392389
if err.code == 599:
393390
self._record_activity()
394-
self.set_status(599)
395-
self.write(str(err))
396-
return
391+
raise web.HTTPError(599, str(err))
397392
else:
398393
raise
399394

@@ -402,8 +397,7 @@ async def proxy(self, host, port, proxied_path):
402397

403398
# For all non http errors...
404399
if response.error and type(response.error) is not httpclient.HTTPError:
405-
self.set_status(500)
406-
self.write(str(response.error))
400+
raise web.HTTPError(500, str(response.error))
407401
else:
408402
# Represent the original response as a RewritableResponse object.
409403
original_response = RewritableResponse(orig_response=response)

tests/test_proxies.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,17 @@ def test_server_proxy_host_absolute(a_server_port_and_token: Tuple[int, str]) ->
255255
assert "X-Proxycontextpath" not in s
256256

257257

258+
@pytest.mark.parametrize("absolute", ["", "/absolute"])
259+
def test_server_proxy_host_invalid(
260+
a_server_port_and_token: Tuple[int, str], absolute: str
261+
) -> None:
262+
PORT, TOKEN = a_server_port_and_token
263+
r = request_get(PORT, f"/proxy{absolute}/<invalid>:54321/", TOKEN)
264+
assert r.code == 403
265+
s = r.read().decode("ascii")
266+
assert "Host &#39;&lt;invalid&gt;&#39; is not allowed." in s
267+
268+
258269
def test_server_proxy_port_non_service_rewrite_response(
259270
a_server_port_and_token: Tuple[int, str]
260271
) -> None:

0 commit comments

Comments
 (0)