-
Notifications
You must be signed in to change notification settings - Fork 74
Description
Rescuing this from pentest scans fallout.
Steps to reproduce
- Uncomment
ip-from-header: truein keter config,
Lines 26 to 28 in a75d3e8
# Get the user's IP address from x-forwarded-for. Useful when sitting behind a # load balancer like Amazon ELB. # ip-from-header: true - Run keter, with any sort of webapp bundle under
incoming/— so that a VHost is active (e.g. localhost) - Make a request to that vhost, with bytes that don't decode to UTF-8 text in
X-Forwarded-Forheader:or the same, using>>> requests.get('http://localhost:8080/whatever', headers={'X-Forwarded-For': b'\xbf\xf0\x9f\x92\xa1'}) <Response [502]>curl:curl http://localhost:8080/whatever -H"X-Forwarded-For:$(printf '\xbf\xf0\x9f\x92\xa1')" <!DOCTYPE html> <html><head><title>Welcome to Keter</title></head><body><h1>Welcome to Keter</h1><p>There was a proxy error, check the keter logs for details.</p></body></html>
Actual result
A proxy exception, 502 crash. Request never gets to the webapp.
Keter logs:
keter|2025-03-28 10:08:51.91|:0|Error> Got a proxy exception on request Request {requestMethod = "GET", httpVersion = HTTP/1.1, rawPathInfo = "/whatever", rawQueryString = "", requestHeaders = [("X-Forwarded-Proto","http"),("Host","localhost:8080"),("User-Agent","curl/8.5.0"),("Accept","/"),("X-Forwarded-For","\191\240\159\146\161")], isSecure = False, remoteHost = 127.0.0.1:54760, pathInfo = ["whatever"], queryString = [], requestBody = , vault = , requestBodyLength = KnownLength 0, requestHeaderHost = Just "localhost:8080", requestHeaderRange = Nothing} with exception Cannot decode byte '\xbf': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream
or, perhaps more clearly readable, with this patch applied 5a2022f :
2025-03-28 09:54:10.73: Caught a proxy exception --[ Cannot decode byte '\xbf': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream ]-- on Request {requestMethod = "GET", httpVersion = HTTP/1.1, rawPathInfo = "/whatever", rawQueryString = "", requestHeaders = [("X-Forwarded-Proto","http"),("X-Forwarded-For","\191\240\159\146\161, 185.189.115.50"),("X-Forwarded-Proto","https"),("X-Forwarded-Port","443"),("Host","zdocs-testing.zoominsoftware.io"),("X-Amzn-Trace-Id","Root=1-67e671c2-59009b0f31dc1f82066dd306"),("User-Agent","python-requests/2.32.0"),("Accept-Encoding","gzip, deflate, br"),("Accept","/")], isSecure = False, remoteHost = 172.30.5.13:63224, pathInfo = ["whatever"], queryString = [], requestBody = , vault = , requestBodyLength = KnownLength 0, requestHeaderHost = Just "zdocs-testing.zoominsoftware.io", requestHeaderRange = Nothing}
Expected result
Up for discussion. My take is:
- Bogus contents in
X-Forwarded-Forshould not bother Keter as the reverse-proxy — exactly as it doesn't, whenip-from-headeris disabled (which is the default). - Either the malformed header should get stripped altogether, or passed to the webapp as-is.
- Again, consider both
ip-from-header:false&ip-from-header:true
- Again, consider both
- In any case, such requests should be reaching the web-app despite malformed
X-Forwarded-For. It may not care. - No 502 crash.