@@ -1449,6 +1449,21 @@ def _rewrite_206_to_200(raw: bytes) -> bytes:
14491449 filtered .append (f"Content-Length: { len (body )} " )
14501450 return ("\r \n " .join (filtered ) + "\r \n \r \n " ).encode () + body
14511451
1452+ # Headers that must never be forwarded to the upstream server because
1453+ # they expose the user's real IP address or internal network topology.
1454+ _STRIP_HEADERS : frozenset = frozenset ({
1455+ "accept-encoding" , # Apps Script auto-decompresses gzip only
1456+ "x-forwarded-for" , # would leak the client's real IP
1457+ "x-forwarded-host" ,
1458+ "x-forwarded-proto" ,
1459+ "x-forwarded-port" ,
1460+ "x-real-ip" , # nginx / CDN header that carries real IP
1461+ "forwarded" , # RFC 7239 — same problem
1462+ "via" , # reveals intermediate proxy hops
1463+ "proxy-authorization" , # never forward credentials to origin
1464+ "proxy-connection" ,
1465+ })
1466+
14521467 def _build_payload (self , method , url , headers , body ):
14531468 """Build the JSON relay payload dict."""
14541469 payload = {
@@ -1458,10 +1473,10 @@ def _build_payload(self, method, url, headers, body):
14581473 "r" : False ,
14591474 }
14601475 if headers :
1461- # Strip Accept-Encoding: Apps Script auto-decompresses gzip
1462- # but NOT brotli/zstd — forwarding "br" causes garbled responses .
1476+ # Strip headers that would leak the user's real IP or expose
1477+ # internal proxy metadata to the upstream destination server .
14631478 filt = {k : v for k , v in headers .items ()
1464- if k .lower () != "accept-encoding" }
1479+ if k .lower () not in self . _STRIP_HEADERS }
14651480 payload ["h" ] = filt if filt else headers
14661481 if body :
14671482 payload ["b" ] = base64 .b64encode (body ).decode ()
0 commit comments