SEC2-034: The request id is judged by the rewritten client address, so a trusted proxy's X-Request-ID is dropped #976
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#976
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 on 2026-10-16 in a read-only security review of
postuloat56fc9d531, checked by a second, independent pass.Severity: Informational · Category: Configuration · Reference: CWE-807 (Reliance on Untrusted Inputs in a Security Decision); OWASP A09:2021 (Security Logging and Monitoring Failures)
Location:
src/postulo/core/middleware.py:244-249(RequestIDMiddleware.__call__; the check is line 248)src/postulo/core/proxy.py:146-154(TrustedProxyMiddlewarerewritesREMOTE_ADDRand keeps the peer underPOSTULO_PROXY_ADDR)src/postulo/core/proxy.py:101(request_origin()already reads the peer the right way)Issue
TrustedProxyMiddlewareruns first and, when the peer is a trusted proxy that sentX-Forwarded-For, replacesREMOTE_ADDRwith the client's address and records the proxy underPOSTULO_PROXY_ADDR.RequestIDMiddlewareruns second and asks whether the rewritten address is a trusted proxy:In the deployment the feature exists for (a proxy in
POSTULO_TRUSTED_PROXIESthat sets bothX-Forwarded-ForandX-Request-ID),REMOTE_ADDRis by then the visitor's public address,is_trustedis false, and the proxy's id is thrown away. Postulo's log, gunicorn's and the proxy's can no longer be laid side by side, which was #233's purpose.tests/test_hardening_798.pytests only a bare loopback peer and a bare stranger; no test sendsX-Forwarded-Forwith the id.Impact
Loss of log correlation in the common proxied deployment: a reviewer cannot pair a proxy's access line with Postulo's lines for the same request. No exposure.
Fix
Judge by the peer that delivered the request, which the first middleware preserved, as
proxy.request_origin()does (reuse it rather than repeating the expression):Done when:
tests/test_hardening_798.pygains two cases:REMOTE_ADDR=172.18.0.5withPOSTULO_TRUSTED_PROXIES=["172.18.0.0/16"],HTTP_X_FORWARDED_FOR=203.0.113.9and an id, which is kept; andREMOTE_ADDR=203.0.113.9(untrusted) with the same forwarded header and an id, which is replaced.Related
#798 (closed) - its suggested remediation names
POSTULO_PROXY_ADDR; the fix that landed readsREMOTE_ADDRafter it has been rewritten, so this is an incomplete fix of a closed issue. #233 (closed) - the feature. #393 (closed) - the API'sinstancefield uses the id.