
### Content repository

The content repository (or "media repository") allows users to upload
files to their homeserver for later use. For example, files which the
user wants to send to a room would be uploaded here, as would an avatar
the user wants to use.

Uploads are POSTed to a resource on the user's local homeserver which
returns an `mxc://` URI which can later be used to GET the download. Content
is downloaded from the recipient's local homeserver, which must first
transfer the content from the origin homeserver using the same API
(unless the origin and destination homeservers are the same).

When serving content, the server SHOULD provide a
`Content-Security-Policy` header. The recommended policy is
`sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';`.

{{% added-in v="1.4" %}} The server SHOULD additionally provide
`Cross-Origin-Resource-Policy: cross-origin` when serving content to allow
(web) clients to access restricted APIs such as `SharedArrayBuffer` when
interacting with the media repository.

{{% changed-in v="1.11" %}} The unauthenticated download endpoints have been
deprecated in favour of newer, authenticated, ones. This change includes updating
the paths of all media endpoints from `/_matrix/media/*` to `/_matrix/client/{version}/media/*`,
with the exception of the `/upload` and `/create` endpoints. The upload/create
endpoints are expected to undergo a similar transition in a later version of the
specification.

#### Matrix Content (`mxc://`) URIs

Content locations are represented as Matrix Content (`mxc://`) URIs. They
look like:

```nohighlight
mxc://<server-name>/<media-id>

<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
<media-id> : An opaque ID which identifies the content.
```

The `media-id` segment MUST consist of only alphanumeric (`A-Za-z0-9`), `_` and
`-` characters. See the [security considerations](#content-repo-security-considerations)
section below for more details.

#### Client behaviour {id="content-repo-client-behaviour"}

Clients can access the content repository using the following endpoints.

{{% changed-in v="1.11" %}} A number of endpoints under the /_matrix/media hierarchy
have been deprecated and replaced with new endpoints which require authentication.
The deprecated endpoints are marked in the section below.

{{% boxes/warning %}}
By Matrix 1.12, servers SHOULD "freeze" the deprecated, unauthenticated, endpoints
to prevent newly-uploaded media from being downloaded. This SHOULD mean that any
media uploaded *before* the freeze remains accessible via the deprecated endpoints,
and any media uploaded *after* (or *during*) the freeze SHOULD only be accessible
through the new, authenticated, endpoints. For remote media, "newly-uploaded" is
determined by the date the cache was populated. This may mean the media is older
than the freeze, but because the server had to re-download it, it is now considered
"new".

Clients SHOULD update to support the authenticated endpoints before servers freeze
unauthenticated access.

Servers SHOULD consider their local ecosystem impact before enacting a freeze.
This could mean ensuring their users' typical clients support the new endpoints
when available, or updating bridges to start using media proxies.

In addition to the above, servers SHOULD exclude [IdP icons used in the `m.login.sso` flow](/client-server-api/#definition-mloginsso-flow-schema)
from the freeze. See the `m.login.sso` flow schema for details.

An *example* timeline for a server may be:

* Matrix 1.11 release: Clients begin supporting authenticated media.
* Matrix 1.12 release: Servers freeze unauthenticated media access.
  * Media uploaded prior to this point still works with the deprecated endpoints.
  * Newly uploaded (or cached) media *only* works on the authenticated endpoints.

Matrix 1.12 is expected to be released in the July-September 2024 calendar quarter.
{{% /boxes/warning %}}

{{% http-api spec="client-server" api="authed-content-repo" %}}

{{% http-api spec="client-server" api="content-repo" %}}

##### Thumbnails

The homeserver SHOULD be able to supply thumbnails for uploaded images
and videos. The exact file types which can be thumbnailed are not
currently specified - see [Issue
\#1938](https://github.com/matrix-org/matrix-spec/issues/453) for more
information.

The thumbnail methods are "crop" and "scale". "scale" tries to return an
image where either the width or the height is smaller than the requested
size. The client should then scale and letterbox the image if it needs
to fit within a given rectangle. "crop" tries to return an image where
the width and height are close to the requested size and the aspect
matches the requested size. The client should scale the image if it
needs to fit within a given rectangle.

The dimensions given to the thumbnail API are the minimum size the
client would prefer. Servers must never return thumbnails smaller than
the client's requested dimensions, unless the content being thumbnailed
is smaller than the dimensions. When the content is smaller than the
requested dimensions, servers should return the original content rather
than thumbnail it.

Servers SHOULD produce thumbnails with the following dimensions and
methods:

-   32x32, crop
-   96x96, crop
-   320x240, scale
-   640x480, scale
-   800x600, scale

In summary:
-   "scale" maintains the original aspect ratio of the image
-   "crop" provides an image in the aspect ratio of the sizes given in
    the request
-   The server will return an image larger than or equal to the
    dimensions requested where possible.

Servers MUST NOT upscale thumbnails under any circumstance. Servers MUST
NOT return a smaller thumbnail than requested, unless the original
content makes that impossible.

#### Security considerations {id="content-repo-security-considerations"}

The HTTP GET endpoint does not require any authentication. Knowing the
URL of the content is sufficient to retrieve the content, even if the
entity isn't in the room.

`mxc://` URIs are vulnerable to directory traversal attacks such as
`mxc://127.0.0.1/../../../some_service/etc/passwd`. This would cause the
target homeserver to try to access and return this file. As such,
homeservers MUST sanitise `mxc://` URIs by:

-   restricting the `server-name` segment to valid
    [server names](/appendices/#server-name)
-   allowing only alphanumeric (`A-Za-z0-9`), `_` and `-` characters in
    the `media-id` segment

The resulting set of whitelisted characters allows URL-safe
base64 encodings specified in RFC 4648. Applying this character
whitelist is preferable to blacklisting `.` and `/` as there are
techniques around blacklisted characters (percent-encoded characters,
UTF-8 encoded traversals, etc).

Homeservers have additional content-specific concerns:

-   Clients may try to upload very large files. Homeservers should not
    store files that are too large and should not serve them to clients,
    returning a HTTP 413 error with the `M_TOO_LARGE` code.
-   Clients may try to upload very large images. Homeservers should not
    attempt to generate thumbnails for images that are too large,
    returning a HTTP 413 error with the `M_TOO_LARGE` code.
-   Remote homeservers may host very large files or images. Homeservers
    should not proxy or thumbnail large files or images from remote
    homeservers, returning a HTTP 502 error with the `M_TOO_LARGE` code.
-   Clients may try to upload a large number of files. Homeservers
    should limit the number and total size of media that can be uploaded
    by clients, returning a HTTP 403 error with the `M_FORBIDDEN` code.
-   Clients may try to access a large number of remote files through a
    homeserver. Homeservers should restrict the number and size of
    remote files that it caches.
-   Clients or remote homeservers may try to upload malicious files
    targeting vulnerabilities in either the homeserver thumbnailing or
    the client decoders.

##### Serving inline content

Clients with insecure configurations may be vulnerable to Cross-Site Scripting
attacks when served media with a `Content-Disposition` of `inline`. Clients
SHOULD NOT be hosted on the same domain as the media endpoints for the homeserver
to mitigate most of this risk. Servers SHOULD restrict `Content-Type` headers to
one of the following values when serving content with `Content-Disposition: inline`:

* `text/css`
* `text/plain`
* `text/csv`
* `application/json`
* `application/ld+json`
* `image/jpeg`
* `image/gif`
* `image/png`
* `image/apng`
* `image/webp`
* `image/avif`
* `video/mp4`
* `video/webm`
* `video/ogg`
* `video/quicktime`
* `audio/mp4`
* `audio/webm`
* `audio/aac`
* `audio/mpeg`
* `audio/ogg`
* `audio/wave`
* `audio/wav`
* `audio/x-wav`
* `audio/x-pn-wav`
* `audio/flac`
* `audio/x-flac`

These types are unlikely to cause Cross-Site Scripting issues when a `Content-Type`
header is provided, as clients will only try to render the data using that content
type. For example, if a HTML file is uploaded with a `Content-Type` of `image/png`,
clients will just assume that the image is corrupted, and won't render it as a
HTML page. Therefore, there is no risk in trusting the user-defined content type,
as long as the `Content-Disposition` is calculated based on that type.

Clients SHOULD NOT rely on servers returning `inline` rather than `attachment`
on [`/download`](#get_matrixclientv1mediadownloadservernamemediaid). Server implementations might decide out of an abundance of
caution that all downloads are responded to with `attachment`, regardless of
content type - clients should not be surprised by this behaviour.
