iron-proxy appears to decode escaped slashes in URL paths before forwarding upstream, which breaks APIs where %2F is part of a routing-critical path segment.
Observed with Google Cloud Storage JSON media downloads through Centaur's iron-proxy wrapper (ironsh/iron-proxy:0.42.0-rc.2). The GCS Python client requests an object with slashes in the object name using the JSON media endpoint, where slashes inside the object name are correctly percent-encoded:
GET /download/storage/v1/b/ce-transact-brand-tracker-usa/o/combined-usa1-usa2%2Fcsv%2Fbrand_detail%2Fv1%2F2026_05_25%2Fbrand_detail_2026_05_25-000000000000.gz?alt=media
The proxy audit log for the same request shows the path decoded before/while forwarding:
/download/storage/v1/b/ce-transact-brand-tracker-usa/o/combined-usa1-usa2/csv/brand_detail/v1/2026_05_25/brand_detail_2026_05_25-000000000000.gz
That makes GCS treat only the segment immediately after /o/ as the object name route component, so it returns 404 even though list calls for the exact object succeed. List calls are unaffected because the object path is carried in the query string (prefix=...) rather than as a routing-critical path segment.
Expected behavior: preserve escaped slashes on forwarded request paths. RFC 3986 section 2.2 treats / as a reserved delimiter; decoding %2F can change URI semantics. GCS object names can contain /, and the JSON API requires those slashes to remain encoded when the object name appears in the /o/<object> path segment.
Potential fixes, depending on proxy stack:
- Envoy: set
path_with_escaped_slashes_action: KEEP_UNCHANGED.
- nginx-style proxying: avoid URI rewrite in
proxy_pass and preserve $request_uri; consider merge_slashes off.
- Go reverse proxy: preserve
URL.RawPath / EscapedPath() and avoid reconstructing paths from decoded URL.Path.
This likely affects any tool that downloads GCS objects whose names contain slashes via the JSON media endpoint.
iron-proxy appears to decode escaped slashes in URL paths before forwarding upstream, which breaks APIs where
%2Fis part of a routing-critical path segment.Observed with Google Cloud Storage JSON media downloads through Centaur's iron-proxy wrapper (
ironsh/iron-proxy:0.42.0-rc.2). The GCS Python client requests an object with slashes in the object name using the JSON media endpoint, where slashes inside the object name are correctly percent-encoded:The proxy audit log for the same request shows the path decoded before/while forwarding:
That makes GCS treat only the segment immediately after
/o/as the object name route component, so it returns 404 even though list calls for the exact object succeed. List calls are unaffected because the object path is carried in the query string (prefix=...) rather than as a routing-critical path segment.Expected behavior: preserve escaped slashes on forwarded request paths. RFC 3986 section 2.2 treats
/as a reserved delimiter; decoding%2Fcan change URI semantics. GCS object names can contain/, and the JSON API requires those slashes to remain encoded when the object name appears in the/o/<object>path segment.Potential fixes, depending on proxy stack:
path_with_escaped_slashes_action: KEEP_UNCHANGED.proxy_passand preserve$request_uri; considermerge_slashes off.URL.RawPath/EscapedPath()and avoid reconstructing paths from decodedURL.Path.This likely affects any tool that downloads GCS objects whose names contain slashes via the JSON media endpoint.