Commit Graph

16 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
2b0ed2296b cleanup 2026-05-27 09:29:21 -04:00
Georges-Antoine Assi
3ae7f998b9 run fmt 2026-05-27 09:20:23 -04:00
Claude
009d358175 fix(security): resolve hostnames in SSRF URL validator
validate_url_for_http_request previously skipped DNS resolution, so
attacker-controlled domains that resolve to private/loopback/link-local
addresses (e.g. 127.0.0.1.nip.io) passed validation and the subsequent
httpx GET hit internal services. Resolve the hostname via getaddrinfo
and reject any result whose IP is private, loopback, link-local,
reserved, multicast, or unspecified. Unresolvable hostnames are
rejected as well.

https://claude.ai/code/session_01T335ZvA825YhuzPctmYzUy
2026-05-27 12:33:36 +00:00
Georges-Antoine Assi
b79bcbcfce remove clud meta ID 2026-04-05 19:50:37 -04:00
Georges-Antoine Assi
7c41fb5bac revert fs_name sibling roms 2026-04-05 17:57:48 -04:00
Georges-Antoine Assi
ef35ecaea9 props rom updte endpoint 2026-04-04 14:16:00 -04:00
Georges-Antoine Assi
3fc8c68c49 last change 2026-03-07 10:23:33 -05:00
Georges-Antoine Assi
13f7586590 changes from grp review 2026-03-07 10:07:50 -05:00
Georges-Antoine Assi
b3659a1226 changes from bot review 2026-03-07 08:58:42 -05:00
Georges-Antoine Assi
46915eee5b fix types and tests 2026-03-06 19:52:09 -05:00
Georges-Antoine Assi
b030b98062 attempt to fix vuln reported in PR 2026-03-06 19:42:56 -05:00
Georges-Antoine Assi
c7d3bb7d80 fixups 2025-10-05 14:56:10 -04:00
Georges-Antoine Assi
3ee14fd23f force ascii on password and email 2025-10-05 14:52:00 -04:00
Georges-Antoine Assi
ae9b01e38d update rules 2025-10-05 14:42:57 -04:00
Georges-Antoine Assi
f6d7f9d1c1 [ROMM-2509] Validate user email and username 2025-10-05 14:11:34 -04:00