Skip to content

fix(translate): pin the LibreTranslate client connection to the vetted address#377

Merged
rmyndharis merged 1 commit into
mainfrom
fix/translate-client-ssrf-pinning
Jun 20, 2026
Merged

fix(translate): pin the LibreTranslate client connection to the vetted address#377
rmyndharis merged 1 commit into
mainfrom
fix/translate-client-ssrf-pinning

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

What

The LibreTranslate client validated the target host and then issued a separate plain fetch, which re-resolves DNS at connection time. An attacker able to influence the configured translate hostname's DNS could answer the pre-check with a public IP and rebind to an internal address (loopback, link-local/metadata) for the actual request — exfiltrating the api_key, which travels in the POST body.

Change

Route the request through the existing withSafeFetch(url, init, use, { guard }) primitive — the same IP-pinning path that webhook and server-side media delivery already use. The connection is pinned to the pre-validated address(es) via the undici dispatcher, so it cannot be re-resolved to an internal address between check and connect. Redirects are refused (the guard only validated the original host).

Preserved behaviour

  • SSRF_ALLOWED_HOSTS allowlist and the WEBHOOK_SSRF_PROTECT=false opt-out are honoured unchanged (wired via the guard flag).
  • Abort/timeout behaviour preserved via the request signal.
  • The circuit breaker still backs off a flaky upstream; a deterministic SSRF block / refused redirect is correctly exempt from the breaker (it is a config/routing problem, not a transient failure).

Tests

libretranslate.client.spec.ts rewritten to assert the client routes through the pinned helper with the correct guard flag, that the api_key is sent in the body, and that the circuit-breaker accounting + SSRF exemption hold. Backend lint + build + full jest green.

…d address

The client validated the target host and then issued a separate plain fetch,
which re-resolves DNS at connect time. An attacker controlling the configured
translate hostname's DNS could answer the pre-check with a public IP and
rebind to an internal address (loopback, link-local/metadata) for the actual
request, exfiltrating the api_key carried in the POST body.

Route the request through withSafeFetch — the same IP-pinning path webhook
and media delivery already use — so the connection is pinned to the
pre-validated address(es) and redirects are refused. SSRF_ALLOWED_HOSTS and
the WEBHOOK_SSRF_PROTECT opt-out are honored unchanged; abort/timeout
behaviour is preserved via the request signal.
@rmyndharis rmyndharis merged commit 60a45c0 into main Jun 20, 2026
5 checks passed
@rmyndharis rmyndharis deleted the fix/translate-client-ssrf-pinning branch June 20, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant