Skip to content

URL path %2F-decoding mangles GCS object names containing slashes #155

@gakonst

Description

@gakonst

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions