mirror of
https://github.com/element-hq/synapse.git
synced 2026-08-14 20:10:26 +00:00
Fixes: https://github.com/element-hq/synapse/security/advisories/GHSA-vh4c-pqh4-w3wq Fixes: https://github.com/matrix-org/internal-config/issues/1703 The key thing to understand is that in `synapse/util/httpresourcetree.py`, we create `UnrecognizedRequestResource` and then dangle children (with real resources) off them. Since `UnrecognizedRequestResource` returns itself as a catch-all 'dynamic child', this means any `UnrecognizedRequestResource`s with real children can have unlimited path components inserted between it and its child. So `/_matrix/INSERTED/static/client/login/style.css` or `/_matrix/INSERTED/AS/MANY/AS/I/WANT/static/client/login/style.css` would unexpectedly resolve to the resource. Client, Federation and Admin APIs wouldn't have been affected because you wouldn't get through the regex routing that they use. ----- Reviewed-on: https://github.com/element-hq/synapse-private/pull/143
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
#
|
|
# This file is licensed under the Affero General Public License (AGPL) version 3.
|
|
#
|
|
# Copyright (C) 2026 Element Creations Ltd
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# See the GNU Affero General Public License for more details:
|
|
# <https://www.gnu.org/licenses/agpl-3.0.html>.
|
|
#
|
|
import os
|
|
from http import HTTPStatus
|
|
|
|
from twisted.web.resource import Resource
|
|
|
|
import synapse
|
|
from synapse.api.errors import Codes
|
|
from synapse.api.urls import STATIC_PREFIX
|
|
from synapse.http.server import StaticResource
|
|
|
|
from tests import unittest
|
|
|
|
|
|
class ResourceTreeTestCase(unittest.HomeserverTestCase):
|
|
servlets = []
|
|
|
|
def create_resource_dict(self) -> dict[str, Resource]:
|
|
"""
|
|
Register /_matrix/static for the test.
|
|
"""
|
|
resources = super().create_resource_dict()
|
|
resources[STATIC_PREFIX] = StaticResource(
|
|
# as in `synapse/app/homeserver.py` `_configure_named_resource`
|
|
os.path.join(os.path.dirname(synapse.__file__), "static")
|
|
)
|
|
return resources
|
|
|
|
def test_inserted_segment_is_silently_swallowed(self) -> None:
|
|
"""
|
|
Regression test for https://github.com/element-hq/synapse/security/advisories/GHSA-vh4c-pqh4-w3wq
|
|
|
|
The path `/_matrix/INSERTED/static/client/login/style.css` used to resolve to the same
|
|
as `/_matrix/static/client/login/style.css`.
|
|
"""
|
|
PATH_SUFFIX = "/static/client/login/style.css"
|
|
correct_channel = self.make_request(
|
|
"GET",
|
|
f"/_matrix{PATH_SUFFIX}",
|
|
shorthand=False,
|
|
)
|
|
# The correct path should give a 200 OK static resource
|
|
self.assertEqual(correct_channel.code, HTTPStatus.OK, correct_channel.result)
|
|
|
|
wrong_channel = self.make_request(
|
|
"GET",
|
|
f"/_matrix/INSERTED{PATH_SUFFIX}",
|
|
shorthand=False,
|
|
)
|
|
# This prefixed version of the same path should give a 404
|
|
self.assertEqual(wrong_channel.code, HTTPStatus.NOT_FOUND, wrong_channel.result)
|
|
self.assertEqual(
|
|
wrong_channel.json_body["errcode"], Codes.UNRECOGNIZED, wrong_channel.result
|
|
)
|