Skip to content

/avatarproxy hangs forever instead of responding when the user ID is invalid #3486

Description

@manuvega-ai

Description

GET /avatarproxy/:jellyfinUserId never sends a response when the path parameter
fails the 32-hex validation check. The request hangs until the client or an
upstream proxy times out.

In server/routes/avatarproxy.ts, the handler throws when the parameter does not
match /^[a-f0-9]{32}$/, and the catch block logs the error but never calls
res:

} catch (e) {
  logger.error('Failed to proxy avatar image', {
    errorMessage: e.message,
  });
}

Since nothing is sent and next(e) is not called, Express keeps the request open
indefinitely. The route is mounted outside /api/v1 (server/index.ts), so it is
not covered by the OpenAPI validator and requires no authentication — an
unauthenticated request can hold a server connection open with no rate limit.
Behind a reverse proxy this surfaces as a gateway timeout (Cloudflare returns 524
after 100s).

Still present on develop as of this report.

Suggested fix

Send a response on the error path, e.g.:

} catch (e) {
  logger.error('Failed to proxy avatar image', {
    errorMessage: e.message,
  });
  if (!res.headersSent) {
    res.status(400).send('Invalid avatar request');
  }
}

Returning 404 instead of 400 would be equally reasonable. Validating the parameter
before entering the try block would also work.

Version

3.4.1

Steps to Reproduce

  1. Run any Seerr instance.
  2. curl -m 15 -o /dev/null -w '%{http_code} %{time_total}\n' http://<host>:5055/avatarproxy/1
  3. Observe no response — curl reports 000 at the timeout instead of a status code.
  4. For contrast, curl http://<host>:5055/avatarproxy/00000000000000000000000000000000
    returns 200 with an image in well under a second.

Any value that is not exactly 32 lowercase hex characters reproduces it
(/avatarproxy/abc, /avatarproxy/1, etc.).

Note: this reproduces regardless of media server type. It was found on a
Plex-backed instance, where /avatarproxy is never used by the frontend at all —
those URLs are only generated for Jellyfin/Emby users — so the endpoint is
reachable and hangs even on installs that have no use for it.

Screenshots

No response

Logs

2026-09-08T01:32:32.635Z [error][API]: Failed to proxy avatar image {"errorMessage":"Provided URL is not an Emby avatar."}

$ curl -m 15 -o /dev/null -w 'HTTP %{http_code} after %{time_total}s\n' http://127.0.0.1:5055/avatarproxy/1
HTTP 000 after 15.001360s

$ curl -m 15 -o /dev/null -w 'HTTP %{http_code} after %{time_total}s\n' http://127.0.0.1:5055/avatarproxy/00000000000000000000000000000000
HTTP 200 after 0.009405s

Platform

desktop

Database

SQLite (default)

Device

Desktop PC

Operating System

Windows 11

Browser

Chrome 152

Additional Context

No response

Search Existing Issues

  • Yes, I have searched existing issues.

Code of Conduct

  • I agree to follow Seerr's Code of Conduct

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions