element-hq / element-hq/synapse

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

Open Beginner friendly
#20,179 1 comment 0 reactions 0 assignees View on GitHub
A-URL-Preview
Dominant language
Python
Stars
4.6k
Forks
600
Avg merge
5d 22h
Merged PRs (30d)
51

Description

### 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

Contributor guide

Open the contributing guide

Research direction

Start in synapse/media/url_previewer.py at the preview entry point and the URL handling around lines 408 and 682; compare it with the GET /_matrix/client/v1/media/preview_url request path. Reproduce with url=ontvangen: and mailto:someone@example.com. Done means unsupported schemes receive a 4xx response with no traceback or internal TypeError in the response body.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.