Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens project-level machine translation configuration and runtime HTTP fetching to reduce SSRF risk by blocking private-network targets (unless explicitly allowed) and by restricting what remote error details can be surfaced.
Changes:
- Introduces outbound URL/hostname validation helpers and wires them into machinery form/API validation (with an allowlist via
ALLOWED_MACHINERY_DOMAINS). - Adds runtime URL validation (DNS + peer IP checks) into
http_request, including redirect handling, to prevent private-target access and DNS rebinding. - Adjusts machinery error-detail handling to avoid exposing untrusted provider response bodies; adds
trusted_error_hostsfor known providers and expands tests/docs.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| weblate/utils/outbound.py | New outbound URL/hostname/IP validation helpers (config-time + runtime). |
| weblate/utils/requests.py | Adds URL-validation mode to http_request with redirect + peer-IP checks. |
| weblate/utils/tests/test_requests.py | Adds unit tests covering URL-validation behavior (private targets, redirects, proxy cases). |
| weblate/utils/validators.py | Adds machinery-specific URL/hostname validators using outbound guards + allowlist. |
| weblate/utils/tests/test_validators.py | Tests for the new machinery validators and allowlist behavior. |
| weblate/utils/models.py | Adds ALLOWED_MACHINERY_DOMAINS setting default. |
| weblate/machinery/forms.py | Validates endpoint fields and propagates allow_private_targets into machinery validation. |
| weblate/machinery/views.py | Passes allow_private_targets to forms; disables private targets for project-level edits. |
| weblate/machinery/models.py | Threads allow_private_targets through service configuration validation. |
| weblate/api/views.py | Enforces allow_private_targets=False for project machinery settings API. |
| weblate/api/tests.py | Adds API test ensuring private project targets are rejected. |
| weblate/machinery/base.py | Adds trusted-host logic, runtime URL validation, and revised error-detail extraction. |
| weblate/machinery/openai.py | Adds runtime base URL validation and trusted hosts for OpenAI/Azure OpenAI. |
| weblate/machinery/deepl.py | Declares DeepL trusted error hosts. |
| weblate/machinery/libretranslate.py | Declares LibreTranslate trusted error hosts. |
| weblate/machinery/anthropic.py | Declares Anthropic trusted error hosts. |
| weblate/machinery/microsoft.py | Improves Microsoft host detection for regional endpoints in error handling. |
| weblate/machinery/tests.py | Adds validation/error-detail tests and runtime URL validation coverage. |
| docs/admin/config.rst | Documents ALLOWED_MACHINERY_DOMAINS. |
| docs/changes.rst | Notes SSRF hardening and error-detail behavior change in release notes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9154c9d7fa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
❌ 10 Tests Failed:
View the top 3 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 040c2e5080
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Allow only public URLs by default to reduce risk of SSRF.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def validate_request_url(url: str, *, allow_private_targets: bool = True) -> None: | ||
| with requests.Session() as session: | ||
| request_settings = session.merge_environment_settings( | ||
| url, | ||
| {}, | ||
| False, | ||
| None, | ||
| None, | ||
| ) | ||
| used_proxy = select_proxy(url, request_settings["proxies"]) is not None | ||
| validator = validate_outbound_url if used_proxy else validate_runtime_url | ||
| validator(url, allow_private_targets=allow_private_targets) |
There was a problem hiding this comment.
validate_request_url() (and the validate_proxied_url lambda in http_request()) calls validate_outbound_url() without passing allowed_domains. As a result, settings.ALLOWED_MACHINERY_DOMAINS allowlisted hostnames are still rejected at runtime when a proxy is used (e.g., single-label hosts like ollama), even though configuration-time validation allows them. Consider extending validate_request_url()/http_request() to accept and pass through allowed_domains (and have machinery pass settings.ALLOWED_MACHINERY_DOMAINS), and add a regression test for an allowlisted proxied hostname.
| The allowlist only affects configuration-time validation for project-managed | ||
| machinery endpoints. For direct connections, runtime checks still reject | ||
| destinations that resolve to private or otherwise non-public addresses. When an | ||
| HTTP(S) proxy is used, runtime validation falls back to hostname validation and | ||
| does not perform the same local DNS or peer-IP checks. |
There was a problem hiding this comment.
This docs section says the allowlist "only affects configuration-time validation", but the code also uses ALLOWED_MACHINERY_DOMAINS to decide whether remote error details can be displayed for project-level machinery (trusted host check in BatchMachineTranslation). Please update the wording to reflect that the allowlist affects both endpoint validation and which provider error messages/bodies may be surfaced.
| The allowlist only affects configuration-time validation for project-managed | |
| machinery endpoints. For direct connections, runtime checks still reject | |
| destinations that resolve to private or otherwise non-public addresses. When an | |
| HTTP(S) proxy is used, runtime validation falls back to hostname validation and | |
| does not perform the same local DNS or peer-IP checks. | |
| The allowlist is used both for configuration-time validation of project-managed | |
| machinery endpoints and as a trusted-host check to decide whether remote | |
| provider error messages or response bodies may be surfaced for project-level | |
| machinery. For direct connections, runtime checks still reject destinations that | |
| resolve to private or otherwise non-public addresses. When an HTTP(S) proxy is | |
| used, runtime validation falls back to hostname validation and does not perform | |
| the same local DNS or peer-IP checks. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10ccdfaeb7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| lowered = hostname.lower() | ||
| if lowered == "localhost" or lowered.endswith(LOCAL_HOST_SUFFIXES): | ||
| raise ValidationError(gettext("URL domain is not allowed.")) | ||
| if "." not in hostname: | ||
| raise ValidationError(gettext("URL domain is not allowed.")) |
There was a problem hiding this comment.
Normalize hostname aliases before trust checks
validate_untrusted_hostname only blocks exact localhost/.localhost suffixes and canonical IP literals, so aliases like http://localhost./ or shorthand IPv4 forms like http://127.1/ pass this check. In proxied flows (_request_with_redirects uses validate_outbound_url when a proxy is selected), no DNS/peer-IP validation runs afterward, so these hostnames can be resolved by the proxy to loopback/private targets and bypass the new SSRF guard. Canonicalizing hostnames (strip trailing dot, normalize/resolve numeric host forms) before the localhost/private checks would close this gap.
Useful? React with 👍 / 👎.
Allow only public URLs by default to reduce risk of SSRF.