GitHub Security Advisory: GHSA-v5c3-6wvc-pc2q
Package: github.com/QuantumNous/new-api (GO)
Severity: HIGH (CVSS 0.0)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 0.11.9-alpha.1
Patched in: unpatched

Summary: QuantumNous/new-api has an SSRF Filter Bypass via 0.0.0.0

Details:
# SSRF Filter Bypass via `0.0.0.0` 

### Summary

The SSRF protection introduced in v0.9.0.5 (CVE-2025-59146) and hardened in v0.9.6 (CVE-2025-62155) does not block the unspecified address `0.0.0.0`. A regular (non-admin) user holding any valid API token can send a multimodal request to `/v1/chat/completions`, `/v1/responses`, or `/v1/messages` with `0.0.0.0` as the image/file URL host, bypassing the private-IP filter and causing the server to issue HTTP requests to localhost. This constitutes at minimum a **blind SSRF**; when the request is routed through an AWS/Bedrock Claude adaptor, the fetched content is inlined into the model response, upgrading it to a **full-read SSRF**.

### Details

#### Root Cause

`common/ssrf_protection.go` — `isPrivateIP()` (lines 33–47) checks the following ranges:

- `10.0.0.0/8`
- `172.16.0.0/12`
- `192.168.0.0/16`
- `127.0.0.0/8`
- `169.254.0.0/16`
- `224.0.0.0/4`
- `240.0.0.0/4`

**`0.0.0.0/8` is not checked.** On Linux, `0.0.0.0` resolves to the local machine, same as `127.0.0.1`.

#### Default Fetch Settings

`setting/system_setting/fetch_setting.go` (lines 16–24) defaults:

- `EnableSSRFProtection: true`
- `AllowPrivateIp: false`
- `AllowedPorts: ["80", "443", "8080", "8443"]`
- `ApplyIPFilterForDomain: true`

So `0.0.0.0` on any of these four ports passes all checks.

#### Data Flow (primary chain — `/v1/chat/completions`)

```
User API token
→ /v1/chat/completions  (TokenAuth, no admin required)
→ messages[].content[].image_url.url = "http://0.0.0.0:8080/..."
→ dto/openai_request.go:111-117   createFileSource() recognises http(s):// as URL source
→ dto/openai_request.go:119-198   GetTokenCountMeta() collects image_url.url / file.file_data / video_url
→ service/token_counter.go:237-264 LoadFileSource() fetches URL when shouldFetchFiles == true
→ service/file_service.go:135-143  loadFromURL() → DoDownloadRequest()
→ service/download.go:52-68       ValidateURLWithFetchSetting() → 0.0.0.0 NOT blocked → GetHttpClient().Get()
→ Server issues real TCP connection to 0.0.0.0
```

**Note on stream requirement:** `common/init.go` (lines 140–141) defaults `GET_MEDIA_TOKEN=true` but `GET_MEDIA_TOKEN_NOT_STREAM=false`, so `stream: true` is needed to trigger the fetch path.

#### Additional Affected Endpoints

The same `ValidateURLWithFetchSetting()` → `DoDownloadRequest()` sink is reachable from:

| Endpoint | User-controlled field | Auth required |
|---|---|---|
| `/v1/chat/completions` | `image_url.url`, `file.file_data`, `video_url` | Regular user token |
| `/v1/responses` | `input_file.file_url`, `input_image.image_url` | Regular user token |
| `/v1/messages` | `source.url` (type: `"url"`) | Regular user token |
| `/api/user/setting` | `webhook_url`, `bark_url`, `gotify_url` | Regular user (self) |

#### Upgrade to Full-Read SSRF (conditional)

`relay/channel/aws/adaptor.go` (lines 41–61) — `ConvertClaudeRequest()`:

- If the request is routed to an AWS/Bedrock Claude channel, the adaptor iterates over message conte