GitHub Security Advisory: GHSA-wc4h-2348-jc3p
Package: github.com/lin-snow/ech0 (GO)
Severity: HIGH (CVSS 7.5)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: < 1.4.8-0[PII_REDACTED]1029-4ca56fea5ba4
Patched in: 1.4.8-0[PII_REDACTED]1029-4ca56fea5ba4

Summary: Ech0 has Unauthenticated Server-Side Request Forgery in Website Preview Feature

Details:
### Summary

Ech0 implements **link preview** (editor fetches a page title) through **`GET /api/website/title`**. That is **legitimate product behavior**, but the implementation is **unsafe**: the route is **unauthenticated**, accepts a **fully attacker-controlled URL**, performs a **server-side GET**, reads the **entire response body** into memory (`io.ReadAll`). There is **no** host allowlist, **no** SSRF filter, and **`InsecureSkipVerify: true`** on the outbound client.

**Attacker outcome :** Anyone who can reach the instance can **force the Ech0 server** to open **HTTP/HTTPS URLs of their choice** as seen from the **server’s network position** (Docker bridge, VPC, localhost from the process view). 
Go’s default `http.Client` **follows redirects** (unless disabled). Redirect chains can move the server-side request from an allowed-looking host to an internal target; the code does not disable this in `SendRequest`.

### Affected Components

**Ech0 codebase:**

- `internal/handler/common/common.go`  
  Handles the `/api/website/title` endpoint and accepts user-controlled URL input.

- `internal/service/common/common.go`  
  Processes the request and invokes the outbound HTTP fetch (`GetWebsiteTitle`).

- `internal/util/http/http.go`  
  Performs the HTTP request (`SendRequest`) with the following insecure configurations:
  - No URL validation or allowlist
  - Redirects enabled (default client behavior)
  - `InsecureSkipVerify: true`

### PoC 

**Environment:** Ech0 listening on `http://127.0.0.1:6277` (e.g. Docker image `sn0wl1n/ech0:latest`). No cookies or `Authorization` header.

**Step 1 — baseline: unauthenticated server-side fetch (public URL):**

```bash
curl.exe -sS -m 20 "http://127.0.0.1:6277/api/website/title?website_url=https://example.com"
```

**Observed result (verified):** HTTP 200, JSON with `code: 1` and `data` **`Example Domain`** — proves the **Ech0 process** performed an outbound GET without any client auth.

**Step 2 — impact: host-bound page + recorded leak (repo PoC file)**
Committed PoC page: **`poc_ssrf_proof.html`** 

1. From **`poc file directory`**, listen on **0.0.0.0** (port **9999**):

```bash
python -m http.server 9999 --bind 0.0.0.0
```

2. **Docker Desktop (Windows / macOS):** Ech0 in Docker fetches the host via `host.docker.internal`:

```bash
curl.exe -sS -m 20 "http://127.0.0.1:6277/api/website/title?website_url=http://host.docker.internal:9999/poc_ssrf_proof.html"
```

**Recorded response (verified this workspace, Ech0 4.2.2 in Docker):**

```json
{"code":1,"msg":"获取网站标题成功","data":"ECH0_SSRF_POC_LEAK_2026"}
```

**Python server log:** `GET /poc_ssrf_proof.html` → **200** (proves the **server/container** pulled the page from your host).

**Leak channel:** the backend **reads the full HTML body** before parsing (see `io.ReadAll` in `SendRequest`).


### Impact

- **Verified:** Unauthenticated callers can make the Ech0 process issue **server-side HTTP(S) requests** to **internal/reserved targets** reachable fro