PST-088: Behind an HTTP(S) proxy, pinned HTTPS requests verify the certificate against the pinned address, not the typed name #817
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#817
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the security audit of 2026-10-10 (
SECURITY-AUDIT-2026-10-10.md), run againstmainatc30851bfrom 8 to 10 October 2026, as PST-088. Severity: Informational.The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.
src/postulo/plugins/http.py(177-201,294)Who can do it, and what they need. Not an attacker path as such; an operator who sets HTTPS_PROXY/HTTP_PROXY (honoured because
httpx.Clientis built with the defaulttrust_env=True). …How it works.
HTTPS_PROXY=http://proxy:3128._pinrewrites the URL host to the approved IP and setsextensions["sni_hostname"]=<typed name>.HTTPTransport(proxy=...); httpcore'sTunnelHTTPConnectionissuesCONNECT <ip>:443and then callsstart_tls(server_hostname=self._remote_origin.host), i.e. the IP, ignoring thesni_hostnameextension (httpcore 1.0.9_sync/http_proxy.pyline ~311; the direct path_sync/connection.pyline ~150 does honour it).SSLCertVerificationError;_fall_back_between_addressesretries each approved address with the same result. …Impact. Capture, logo fetch, link check, web push, update check and the plugin catalogue all fail for HTTPS destinations whenever an outbound proxy is configured in the environment, with an error that reads as a certificate problem. The failure is closed, not open, so no spoofing results; the risk is that the obvious 'fix' (ALLOW_PRIVATE=true) widens the policy for every account. …
Verification (verdict: confirmed; severity after verification: Informational). Line references are right (http.py 177-201 and 294; httpcore line is 312, not ~311). Two corrections: (1) the 'documented workaround' is not documented anywhere in the repo, so drop that claim from the impact; the real consequence is only that guarded HTTPS fetches (capture, logo, link check, web push, update check, catalogue, token refresh) fail with a certificate error whenever HTTP(S)_PROXY is in the environment. …
Suggested remediation. Either pass
trust_env=Falseso the guarded clients ignore proxy variables (and document a Postulo-specific proxy setting that, when used, keeps the name on the URL and relies on the proxy to resolve, with the policy enforced by re-resolving and comparing), or wrap the proxy transport so the tunnel's TLS uses thesni_hostnameextension, and add a test that pins through a proxy and asserts the server_hostname handed to start_tls is the typed …Fixed in
c78572a81on main.