Commit Graph

7 Commits

Author SHA1 Message Date
Georges-Antoine Assi
30451d5651 fix(security): move SSRF defense into the HTTP client path
The previous validator did a preflight `socket.getaddrinfo` before each
httpx request. Two problems:

  * DNS rebinding / TOCTOU: httpx re-resolves at connect time, so a
    hostname can answer with a public IP for the validator and a
    private IP for the real request. The preflight check did not
    constrain the connection.
  * Event-loop blocking: `socket.getaddrinfo` is synchronous, and the
    media-download callers are async. Slow resolvers stalled
    unrelated requests.

Replace it with two layers, both wired automatically onto every httpx
client built by `utils.context`:

  1. A request event hook running `validate_url_for_http_request`
     (syntactic checks only: scheme, reserved hostnames, literal IPs,
     internal TLDs). No DNS, no call-site responsibility.
  2. `SSRFProtectedAsyncBackend` / `SSRFProtectedSyncBackend`, custom
     httpcore network backends that resolve the hostname inside
     `connect_tcp`, reject any address in a forbidden range, then
     connect to that *same* validated address. The async variant uses
     `loop.getaddrinfo` so it doesn't block the loop. httpcore calls
     `start_tls(server_hostname=<URL host>)` after `connect_tcp`, so
     TLS SNI and cert verification still use the original hostname
     even though the TCP layer connects by IP.

Drop the explicit `validate_url_for_http_request(...)` calls from
`resources_handler.py` — the event hook covers them. Consolidate the
URL validator and its tests under `utils/ssrf.py` /
`tests/utils/test_ssrf.py` so the SSRF surface lives in one module.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:58:14 -04:00
Georges-Antoine Assi
4a8c3423df run trunk fmt 2026-04-02 10:21:43 -04:00
Eric Daras
9d659bf00b move proxy env handling into config 2026-04-02 06:23:53 +02:00
Eric Daras
8540514b46 add outbound HTTP proxy support for backend requests 2026-03-27 07:02:14 +01:00
Michael Manganiello
f96adeeaee misc: Upgrade to Python 3.13
Small changes to upgrade Python to version 3.13, and fixes based on a
`pyupgrade` run using the `--py313-plus` flag.
2025-07-03 23:37:00 -03:00
Michael Manganiello
fe1a9ce2a7 fix: Use aiohttp for RetroAchievements API calls
This change replaces the `httpx` client with `aiohttp` for the
RetroAchievements API service.

The main reason for this change is that `httpx` has an unavoidable log
line with `INFO` level, which includes the request full URL, containing
the user's API key.

`httpx` has had an
[open discussion](https://github.com/encode/httpx/discussions/2765)
regarding this security issue for almost two years.

The change to `aiohttp` is painless, and would allow us to migrate more
of the codebase to it in the future, to avoid leaking sensitive
information in logs.
2025-06-09 09:59:56 -03:00
Michael Manganiello
7c6dfa8e50 feat: Use ContextVar to share httpx AsyncClient instance between requests 2024-07-23 01:29:32 -03:00