Skip to content

URL preview accepts any URI scheme and returns 500 with an internal TypeError #20179

Description

@syphernl

Description

GET /_matrix/client/v1/media/preview_url accepts any URI scheme and hands it straight to the HTTP client. For a scheme that cannot be fetched over HTTP, the request fails deep inside the client and Synapse answers 500 with an internal TypeError in the body, instead of rejecting the input with a 4xx.

url_previewer.py never checks the scheme. urlsplit is used only in _is_url_blocked for blocklist matching (v1.159.0, synapse/media/url_previewer.py:408), and the only scheme comparison in the file is url_parts.scheme != "data" at line 682, for images inside an already fetched page. So mailto:someone@example.com, tel:+3112345678 or a bare word: all reach the fetch path.

This is reachable without a malicious client. Element Web treats a plain word followed by a colon as a link and asks the homeserver to preview it, which is how we hit it: a message containing the Dutch word ontvangen: produced the 500 below.

Steps to reproduce

As a logged-in user:

GET /_matrix/client/v1/media/preview_url?url=ontvangen%3A

mailto:someone@example.com fails the same way.

Expected

400 or 422 with a message about an unsupported or malformed URL, and no traceback in the response body. A scheme allowlist of http and https at the entry point would cover it.

Actual

HTTP 500
Failed to download content: ["TypeError: argument of type 'NoneType' is not iterable\n"]

Server log:

synapse.http.client - 465 - INFO - Error sending request to  GET ontvangen:: TypeError argument of type 'NoneType' is not iterable
synapse.media.url_previewer - 498 - WARNING - Error downloading ontvangen:: TypeError("argument of type 'NoneType' is not iterable")

Both log lines come from generic except Exception handlers (synapse/http/client.py:459 and synapse/media/url_previewer.py:496), so the TypeError is raised further down, where the agent works with a URI whose host is None.

Impact

Low. It is a wrong status code plus log noise, not a crash. It does fill the logs: on our homeserver these previews are a steady source of tracebacks, which makes log-based alerting on exceptions harder to use.

Version information

  • Synapse: 1.159.0
  • Database: PostgreSQL
  • Client: Element Web 1.12.26
  • Installation: Docker image, Kubernetes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions